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

feat: Block Verification Feature #414

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open

Conversation

AlfredoG87
Copy link
Contributor

@AlfredoG87 AlfredoG87 commented Dec 17, 2024

Description:

New Classes:

  • verification package
    • BlockVerificationStatus (Enum)
    • StreamVerificationHandlerImpl (Implementation)
    • VerificationConfig (record)
    • VerificationInjectionModule (interface)
    • VerificationResult (Record)
  • verification.hasher package
    • CommonUtils (utility class for hashing)
    • Hashes (Record)
    • StreamingTreeHasher (Interface)
    • NaiveStreamingTreeHasher (implementation)
    • ConcurrentStreamingTreeHasher (implementation)
  • verification.service package:
    • BlockVerificationService (Interface)
    • BlockVerificationServiceImpl (implementation)
    • NoOpBlockVerificationService (implementation)
  • verification.session pacakge:
    • BlockVerificationSession (Interface)
    • AbstractBlockVerificationSession
    • BlockVerificationSessionSync
    • BlockVerificationSessionAsync
    • BlockVerificationSessionFactory
    • BlockVerificationSessionType
  • verification.signature package:
    • SignatureVerifier (Interface)
    • SignatureVerifierDummy (Implementation)

Other notable changes:

  • Added StreamVerificationHandlerImpl as a new subscriber to the unverified ring buffer.
  • Changes to the dashboard
  • Changes to the Metrics definitions to add the new metrics
  • Added new Config type to the application
  • Fixed some Unit Tests
  • Added enough coverage for the new classes added.
  • Added Config Documentation to the Docs
  • Added New Dashboard to K8 Helm Chart deployment

Related issue(s):

Fixes #375
Fixes #374
Fixes #376
Fixes #173
Fixes #423
Fixes #424

Notes for reviewer:

For the scenarios below, I use a 501 blocks sample with up-to-date (Dec-18-2024) very high TPS (10K).

The default implementation will be ASYNC that not only is faster, but is also non-blocking

Stats with SYNC implementation:
image

Stats with ASYNC implementation:
image

Checklist

  • Documented (Code comments, README, etc.)
  • Tested (unit, integration, etc.)

@AlfredoG87 AlfredoG87 force-pushed the verification-handler branch 2 times, most recently from 50fbeb9 to fa09df7 Compare December 18, 2024 04:39
@AlfredoG87 AlfredoG87 self-assigned this Dec 18, 2024
@AlfredoG87 AlfredoG87 added Block Node Issues/PR related to the Block Node. New Feature A new feature, service, or documentation. Major changes that are not backwards compatible. labels Dec 18, 2024
@AlfredoG87 AlfredoG87 added this to the 0.3.0 milestone Dec 18, 2024
Next steps: Add metrics to measure time to hash.

Signed-off-by: Alfredo Gutierrez <[email protected]>
… added. and temporary stuff.

Signed-off-by: Alfredo Gutierrez <[email protected]>
…ink I will create several implementations to the interfaces with some simple and synchronous and another one concurrent and asynchronous.

Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
…ckerframework.checker.qual;) on module-info by accident

Signed-off-by: Alfredo Gutierrez <[email protected]>
…me refactor around BlockVerificationService

Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Small improvements in other tests as well.
Improvements to the flow of finalizeVerification thanks to issues surfaced during unit testing

Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
…tual/final configuration values

Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
@AlfredoG87 AlfredoG87 marked this pull request as ready for review December 18, 2024 23:11
@AlfredoG87 AlfredoG87 requested a review from a team as a code owner December 18, 2024 23:11
… on the chart deployment

Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Signed-off-by: Alfredo Gutierrez <[email protected]>
Copy link

codecov bot commented Dec 19, 2024

Codecov Report

Attention: Patch coverage is 92.50646% with 29 lines in your changes missing coverage. Please review.

Project coverage is 96.07%. Comparing base (9bae709) to head (f173ed8).

Files with missing lines Patch % Lines
...fication/hasher/ConcurrentStreamingTreeHasher.java 87.50% 6 Missing and 6 partials ⚠️
.../block/server/verification/hasher/CommonUtils.java 83.01% 9 Missing ⚠️
.../verification/hasher/NaiveStreamingTreeHasher.java 88.23% 2 Missing and 2 partials ⚠️
.../block/server/verification/VerificationConfig.java 75.00% 1 Missing and 1 partial ⚠️
...erver/verification/hasher/StreamingTreeHasher.java 60.00% 2 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #414      +/-   ##
============================================
- Coverage     97.02%   96.07%   -0.96%     
- Complexity      409      501      +92     
============================================
  Files            82      100      +18     
  Lines          1446     1833     +387     
  Branches         89      132      +43     
============================================
+ Hits           1403     1761     +358     
- Misses           32       52      +20     
- Partials         11       20       +9     
Files with missing lines Coverage Δ
.../block/server/config/BlockNodeConfigExtension.java 100.00% <ø> (ø)
...era/block/server/config/ConfigInjectionModule.java 88.88% <100.00%> (+1.38%) ⬆️
...er/config/ServerMappedConfigSourceInitializer.java 100.00% <ø> (ø)
...era/block/server/metrics/BlockNodeMetricTypes.java 100.00% <100.00%> (ø)
...com/hedera/block/server/notifier/NotifierImpl.java 100.00% <ø> (ø)
...a/block/server/pbj/PbjBlockAccessServiceProxy.java 100.00% <ø> (ø)
...a/block/server/pbj/PbjBlockStreamServiceProxy.java 91.22% <100.00%> (+0.15%) ⬆️
.../persistence/storage/PersistenceStorageConfig.java 100.00% <ø> (ø)
...k/server/verification/BlockVerificationStatus.java 100.00% <100.00%> (ø)
...er/verification/StreamVerificationHandlerImpl.java 100.00% <100.00%> (ø)
... and 16 more

Copy link
Contributor

@georgi-l95 georgi-l95 left a comment

Choose a reason for hiding this comment

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

Did a fast first review, good progress, left some questions.

/**
* The Block failed verification, either due to an invalid signature or an invalid hash.
*/
SIGNATURE_INVALID
Copy link
Contributor

Choose a reason for hiding this comment

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

This implies that it's strictly signature issue, maybe add invalid hash enum or change name to something more ambiguous, as we are not sure at this point what is the root cause ?

try {

if (!serviceStatus.isRunning()) {
LOGGER.log(ERROR, "Service is not running. Block item will not be processed further.");
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe wrap with else statement, otherwise won't it continue running down ?

* A {@link StreamingTreeHasher} that computes the root hash of a perfect binary Merkle tree of {@link Bytes} leaves
* using a concurrent algorithm that hashes leaves in parallel and combines the resulting hashes in parallel.
* <p>
* <b>Important:</b> This class is not thread-safe, and client code must not make concurrent calls to
Copy link
Contributor

Choose a reason for hiding this comment

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

How can we be sure that this will be the case ? Do we wanna consider using some synchronization primitives ?

Copy link
Contributor

@ata-nas ata-nas left a comment

Choose a reason for hiding this comment

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

@AlfredoG87 really good job!

This is my first pass through, I was focused mostly at looking at things on the surface level. Will need additional passes to get into the logic in depth, but the change is very big.

That being said, I comment you some nits/cleanup I found on the first pass.

I have not looked at the metrics and charts json changes as well as tests.

Here general comments:

  • I would not use var ever anywhere, even in test/loops etc. I think it makes things very unreadable and we should not be using that IMO. Not a blocker, but an opinion and a suggestion.

  • I am sure I have missed places, but let's be adding the non-null annotation for the static code analysis.

  • Also I am sure I have missed some places, but lets always have a require non null checks on things that must not be null and we only do assignment (not calling a method on the target object). Lets fail early on these places. (Mostly in constructors or in methods where we need a non null object but we use it after executing a lot of logic before hand)

My focus on the next runs will be to get into and test the logic. Then tests (I presume there will be changes made, so I am hesitant to go to tests yet)

Comment on lines +12 to +15
| Environment Variable | Description | Default Value |
|:---------------------------------------|:-------------------------------------------------------------------------|--------------------:|
| PERSISTENCE_STORAGE_LIVE_ROOT_PATH | The root path for the live storage. | |
| PERSISTENCE_STORAGE_ARCHIVE_ROOT_PATH | The root path for the archive storage. | |
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's stick with the old formatting of the md tables for now. I will make a discussion so that the team will be able to vote on what the formatting should be for the tables so we can all be on the same page.

Comment on lines 81 to 87
this.serviceStatus = serviceStatus;
this.notifier = notifier;
this.blockNodeContext = blockNodeContext;

streamMediator.subscribe(streamPersistenceHandler);
streamMediator.subscribe(streamVerificationHandler);
this.streamMediator = streamMediator;
Copy link
Contributor

Choose a reason for hiding this comment

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

we should add null checks here on all lines 81-87 as they are assignment and will be used later, lets fail early here.

Comment on lines +176 to +194
/**
* Constructs a new instance of {@link CompressionType}.
*
* @param minCompressionLevel the minimum compression level
* @param maxCompressionLevel the maximum compression level
*/
CompressionType(final int minCompressionLevel, final int maxCompressionLevel) {
this.minCompressionLevel = minCompressionLevel;
this.maxCompressionLevel = maxCompressionLevel;
}

/**
* This method verifies that the compression level is within the
* acceptable range for the given compression type.
*
* @param levelToCheck the compression level to check
* @throws IllegalArgumentException if the compression level is not within
* the acceptable range
*/
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the docs! I've missed that :)

Comment on lines +22 to +23
*
* @param <V> the type of the value to be written
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the docs again :)

/**
* An enum representing the status of block verification.
*/
public enum BlockVerificationStatus {
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we also add an UNVERIFIED option which would mean that this block is not yet verified? Or does the core logic and design do not support that?

Comment on lines +97 to +103
this.blockNumber = blockHeader.number();
this.metricsService = metricsService;
this.signatureVerifier = signatureVerifier;
this.inputTreeHasher = inputTreeHasher;
this.outputTreeHasher = outputTreeHasher;

this.blockWorkStartTime = System.nanoTime();
Copy link
Contributor

@ata-nas ata-nas Dec 19, 2024

Choose a reason for hiding this comment

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

add require non null on 98-101 as they are assignment only, lets fail early here

Comment on lines +52 to +55
this.config = verificationConfig;
this.metricsService = metricsService;
this.signatureVerifier = signatureVerifier;
this.executorService = executorService;
Copy link
Contributor

Choose a reason for hiding this comment

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

lets add require non null check on 52-55 as they are assignment only, lets fail early here

Comment on lines +71 to +73
case ASYNC -> new BlockVerificationSessionAsync(
blockHeader, metricsService, signatureVerifier, executorService, hashCombineBatchSize);
case SYNC -> new BlockVerificationSessionSync(blockHeader, metricsService, signatureVerifier);
Copy link
Contributor

Choose a reason for hiding this comment

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

same comment as above for considering to migrate to static factory methods due to easier maintainability in the future

* @param signature the signature to verify
* @return true if the signature is valid, false otherwise
*/
Boolean verifySignature(Bytes hash, Bytes signature);
Copy link
Contributor

Choose a reason for hiding this comment

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

could add the non-null annotation to the parameter for the static code analysis

Comment on lines +36 to +37
blockStream.millisecondsPerBlock=500
blockStream.blockItemsBatchSize=1_000
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe drop these defaults, I think you changed these during development of the new feature, but by default they should be commented out?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Block Node Issues/PR related to the Block Node. New Feature A new feature, service, or documentation. Major changes that are not backwards compatible.
Projects
None yet
5 participants