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

add merkle root meta column to blockstore #33979

Merged
merged 5 commits into from
Nov 12, 2023

Conversation

AshwinSekar
Copy link
Contributor

@AshwinSekar AshwinSekar commented Nov 7, 2023

Problem

In order to detect duplicate blocks with conflicting merkle roots we need to be able to access the merkle root for each FEC set. We would like to store the merkle root and relevant meta information for easy access in blockstore.

Summary of Changes

Add new merkle root meta column

Contributes to #33644

@AshwinSekar AshwinSekar force-pushed the merkle-root-blockstore branch 3 times, most recently from 5b62f50 to 01f3c9f Compare November 7, 2023 21:54
@AshwinSekar AshwinSekar changed the title add merkle root column in blockstore add merkle root meta column to blockstore Nov 7, 2023
@AshwinSekar AshwinSekar marked this pull request as ready for review November 7, 2023 23:16
Copy link

codecov bot commented Nov 7, 2023

Codecov Report

Merging #33979 (f17b5d2) into master (04e4efd) will increase coverage by 0.0%.
The diff coverage is 57.1%.

@@           Coverage Diff           @@
##           master   #33979   +/-   ##
=======================================
  Coverage    81.9%    81.9%           
=======================================
  Files         811      811           
  Lines      219424   219452   +28     
=======================================
+ Hits       179761   179797   +36     
+ Misses      39663    39655    -8     

@behzadnouri
Copy link
Contributor

  • Should we separate out the new blockstore column addition into its own pr?
  • I think this commit correctly identifies merkle root mismatch when fec_set_index are the same. But another scenario for duplicate blocks is that you receive a coding shred which indicates data shreds with indices [10..20] belong to the same FEC set with fec_set_index = 10, but then you have a data shred with index 17 (i.e. within that range) but different fec_set_index. We are not catching this case anywhere right?
  • Another case is that we have 2 coding shreds which indicate overlapping FEC sets.

@AshwinSekar
Copy link
Contributor Author

  • Should we separate out the new blockstore column addition into its own pr?

This PR only adds the new column, and writes to it. The next change will actually utilize the column

  • I think this commit correctly identifies merkle root mismatch when fec_set_index are the same. But another scenario for duplicate blocks is that you receive a coding shred which indicates data shreds with indices [10..20] belong to the same FEC set with fec_set_index = 10, but then you have a data shred with index 17 (i.e. within that range) but different fec_set_index. We are not catching this case anywhere right?
  • Another case is that we have 2 coding shreds which indicate overlapping FEC sets.

Correct, this behavior is not currently caught, but it is next on my list! #33037

ledger/src/blockstore.rs Outdated Show resolved Hide resolved
@behzadnouri
Copy link
Contributor

This PR only adds the new column, and writes to it. The next change will actually utilize the column

don't we need to backport the new column to v1.17, v1.16 for forward compatibility?
In that case we probably need to keep the writing part out as well.

@steviez
Copy link
Contributor

steviez commented Nov 9, 2023

don't we need to backport the new column to v1.17, v1.16 for forward compatibility?
In that case we probably need to keep the writing part out as well.

Yes, the idea would be to backport some minimal PR to the older versions. Since we're adding a new column, the old branches only need to know about the existence of the columns (Rocksdb has a requirement that all present columns must be opened in order to open the DB).

I think we could considerably slim down what we backport from this PR. Namely, we don't need any code that interacts with the column, like the stuff in do_insert_shreds().

We would definitely want the BP for v1.17, probably v1.16 as well but we'll likely have to do some convincing given where v1.16 is at in its' release cycle

ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_meta.rs Outdated Show resolved Hide resolved
Comment on lines 555 to 557
pub fn merkle_root(&self) -> Option<Hash> {
layout::get_merkle_root(self.payload())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

noted, will do this in the following PR

@AshwinSekar
Copy link
Contributor Author

Yes, the idea would be to backport some minimal PR to the older versions. Since we're adding a new column, the old branches only need to know about the existence of the columns (Rocksdb has a requirement that all present columns must be opened in order to open the DB).

good to know, I was unaware of the rocksdb requirement. I've slimmed down this PR to just the addition of the new column.

ledger/src/blockstore.rs Outdated Show resolved Hide resolved
ledger/src/blockstore/blockstore_purge.rs Show resolved Hide resolved
ledger/src/blockstore/blockstore_purge.rs Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_db.rs Outdated Show resolved Hide resolved
ledger/src/blockstore_meta.rs Outdated Show resolved Hide resolved
@AshwinSekar AshwinSekar added the v1.17 PRs that should be backported to v1.17 label Nov 9, 2023
}

fn key((slot, fec_set_index): Self::Index) -> Vec<u8> {
let mut key = vec![0; 16];
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not 16 bytes anymore.
It is 8 + 4 = 12 bytes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch

Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a test for this part? The mismatch isn't caught by any test sounds scary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unable to create a test that would fail.
assert_eq!(MerkleRootMeta::index(&MerkleRootMeta::key((slot, fec_set_index)), (slot, fec_set_index)) will pass with both 12 and 16.

only way would be to check the length of MerkleRootMeta::key which requires hardcoding the 16 or 12 in the unit test. this approach would not have caught the oversight.

Copy link
Contributor

Choose a reason for hiding this comment

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

a round-trip test might still be useful to assert that what is written is read back the same.
asserting manually in the test that the key size is 12 is also fine (agreed that it wouldn't have caught this though, but nonetheless)

Copy link
Contributor

Choose a reason for hiding this comment

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

Never hit submit but was chatting with Ashwin and agreed with others that a unit test would have been unlikely to catch this.

There is a key_size() field on the Column trait that I thought about suggesting; however, this method is flawed in that it calls std::mem::size_of on Self::Index. The result is that the calculated key size from this call will include any alignment bytes that would be present in Self::Index. But, we manually pack the keys end-to-end, so the actual keys do not contain alignment bytes. Have a PR to rip that out / maybe re-implement on each column individually.

Will think on this one a little more to see if there is some way to make this a little more full-proof.

@behzadnouri
Copy link
Contributor

I think we'll definitely want this BP'd for v1.17; I think it is worth bringing up in #releng as well to discuss v1.16 BP. A Blockstore that is opened with this commit will create the new, empty column. Without a v1.16 BP, v1.16 would be unable to open a Blockstore that has been opened with tip-of-master

We always want to be + 1 version compatible, so the storage created/written to by v1.17 should work with v1.16 as well; and so if we are backporting to v1.17 then we need to backport to v1.16 as well.

Nonetheless, my preference would be to backport to v1.16 anyways. It would be a pita if we need to do some debugging on mainnet and then we hit this incompatibility issue.

AshwinSekar added a commit that referenced this pull request Nov 13, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs
@AshwinSekar AshwinSekar added the v1.16 PRs that should be backported to v1.16 label Nov 13, 2023
mergify bot pushed a commit that referenced this pull request Nov 13, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs
AshwinSekar added a commit that referenced this pull request Nov 15, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs
@AshwinSekar AshwinSekar deleted the merkle-root-blockstore branch November 15, 2023 20:16
@AshwinSekar AshwinSekar self-assigned this Nov 29, 2023
Copy link
Contributor

mergify bot commented Nov 29, 2023

Backports to the stable branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule.

Copy link
Contributor

mergify bot commented Nov 29, 2023

Backports to the beta branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule. Exceptions include CI/metrics changes, CLI improvements and documentation updates on a case by case basis.

@AshwinSekar AshwinSekar added v1.17 PRs that should be backported to v1.17 and removed v1.16 PRs that should be backported to v1.16 v1.17 PRs that should be backported to v1.17 labels Nov 29, 2023
Copy link
Contributor

mergify bot commented Nov 30, 2023

Backports to the beta branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule. Exceptions include CI/metrics changes, CLI improvements and documentation updates on a case by case basis.

AshwinSekar added a commit that referenced this pull request Dec 1, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs
AshwinSekar added a commit that referenced this pull request Dec 1, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)
AshwinSekar added a commit that referenced this pull request Dec 1, 2023
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)
mergify bot added a commit that referenced this pull request Dec 1, 2023
…#34028)

* add merkle root meta column to blockstore (#33979)

* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

* blockstore: make merkle root Optional in MerkleRootMeta column (#34091)

---------

Co-authored-by: Ashwin Sekar <ashwin@solana.com>
@steviez steviez added the v1.16 PRs that should be backported to v1.16 label Jan 5, 2024
Copy link
Contributor

mergify bot commented Jan 5, 2024

Backports to the stable branch are to be avoided unless absolutely necessary for fixing bugs, security issues, and perf regressions. Changes intended for backport should be structured such that a minimum effective diff can be committed separately from any refactoring, plumbing, cleanup, etc that are not strictly necessary to achieve the goal. Any of the latter should go only into master and ride the normal stabilization schedule.

@steviez steviez removed the v1.16 PRs that should be backported to v1.16 label Jan 5, 2024
steviez pushed a commit that referenced this pull request Jan 5, 2024
* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs
steviez added a commit that referenced this pull request Jan 5, 2024
…#34665)

* add merkle root meta column to blockstore (#33979)

* add merkle root meta column to blockstore

* pr feedback: remove write/reads to column

* pr feedback: u64 -> u32 + revert

* pr feedback: fec_set_index u32, use Self::Index

* pr feedback: key size 16 -> 12

(cherry picked from commit e457c02)

# Conflicts:
#	ledger/src/blockstore.rs

* fix conflicts

* blockstore: make merkle root Optional in MerkleRootMeta column (#34091)

---------

Co-authored-by: Ashwin Sekar <ashwin@solana.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v1.17 PRs that should be backported to v1.17
Projects
Development

Successfully merging this pull request may close these issues.

4 participants