-
Notifications
You must be signed in to change notification settings - Fork 14
chore: Improvements to Block Footer and Proof Support #1891
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,9 @@ | |
| import static org.hiero.block.common.hasher.HashingUtilities.noThrowSha384HashOf; | ||
|
|
||
| import com.hedera.hapi.block.stream.BlockProof; | ||
| import com.hedera.hapi.block.stream.SignedRecordFileProof; | ||
| import com.hedera.hapi.block.stream.StateProof; | ||
| import com.hedera.hapi.block.stream.TssSignedBlockProof; | ||
| import com.hedera.hapi.block.stream.output.BlockFooter; | ||
| import com.hedera.hapi.block.stream.output.BlockHeader; | ||
| import com.hedera.pbj.runtime.ParseException; | ||
|
|
@@ -55,8 +58,11 @@ | |
| private BlockHeader blockHeader = null; | ||
|
|
||
| private BlockFooter blockFooter = null; | ||
| private TssSignedBlockProof tssSignedBlockProof; | ||
| private StateProof blockStateProof; | ||
|
Check warning on line 62 in block-node/verification/src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
|
||
| private SignedRecordFileProof signedRecordFileProof; | ||
|
Check warning on line 63 in block-node/verification/src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
|
||
|
|
||
| private List<BlockProof> blockProofs = new ArrayList<>(); | ||
| private int blockProofsReceived = 0; | ||
|
|
||
| public ExtendedMerkleTreeSession(final long blockNumber, final BlockSource blockSource) { | ||
| this.blockNumber = blockNumber; | ||
|
|
@@ -94,16 +100,31 @@ | |
| // append block proofs | ||
| case BLOCK_PROOF -> { | ||
| BlockProof blockProof = BlockProof.PROTOBUF.parse(item.blockProof()); | ||
| blockProofs.add(blockProof); | ||
| switch (blockProof.proof().kind()) { | ||
| case BLOCK_STATE_PROOF -> this.blockStateProof = blockProof.blockStateProof(); | ||
| case SIGNED_BLOCK_PROOF -> this.tssSignedBlockProof = blockProof.signedBlockProof(); | ||
| case SIGNED_RECORD_FILE_PROOF -> | ||
| this.signedRecordFileProof = blockProof.signedRecordFileProof(); | ||
| default -> { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| blockProofsReceived++; | ||
|
Comment on lines
+103
to
+113
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This appears to be assuming only one of any given type of proof. That is not what we expect; there may well be multiples of the same type. The original (add all of them to a set and process all as a set) seems more correct.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed that was the assumption, good note, will re-approach this |
||
| } | ||
| case REDACTED_ITEM -> LOGGER.log(WARNING, "Redacted item observed in block {0}", blockNumber); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is tricky.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes tricky indeed, hmm, VerificationSession would have to be aware of the source of the Block.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably better to have an issue filed to revisit. |
||
| case FILTERED_ITEM_HASH -> LOGGER.log(WARNING, "Filtered item hash observed in block {0}", blockNumber); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is fun.
In all cases filtered items still need to be added to the proper subtree as a pre-computed hash (which I do not believe the current hasher supports, future work to handle that). This suggests that we probably need two different verification plugins. One that is "strict" and runs in tier 1, and another that is "lenient" and may run in tier 2 if an operator chooses. (yes, we could do this with configuration, but I believe we'd be better off and much safer to just have two different plugins). |
||
| case RECORD_FILE -> LOGGER.log(WARNING, "Record file observed in block {0}", blockNumber); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We actually need to parse and process these; for now we probably want an info log; not warning. |
||
| case UNSET -> LOGGER.log(WARNING, "Unset block item observed in block {1}", kind, blockNumber); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This shouldn't happen.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe a new blockitem type we are unaware of would show up as UNSET. |
||
| default -> LOGGER.log(WARNING, "Unknown block item type {0} in block {1}", kind, blockNumber); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We shouldn't have default; the enumerated value is comprehensive and we should ensure every known enum is handled (which the compiler will only do if there is no default). |
||
| } | ||
| } | ||
|
|
||
| // since we are only expecting 1 block proof per block, we can finalize verification here | ||
| // however in the future, we might want to revisit this if we expect multiple proofs | ||
| // and use the EndOfBlock signal to finalize verification. | ||
| if (blockFooter != null && blockProofs.size() > 0) { | ||
| return finalizeVerification(blockProofs.get(0)); | ||
| if (blockFooter != null && blockProofsReceived > 0) { | ||
| return finalizeVerification(); | ||
| } | ||
|
|
||
| // was not able to finalize verification yet | ||
|
|
@@ -114,10 +135,9 @@ | |
| * Finalizes the block verification by computing the final block hash, | ||
| * verifying its signature, and updating metrics accordingly. | ||
| * | ||
| * @param blockProof the block proof | ||
| * @return VerificationNotification indicating the result of the verification | ||
| */ | ||
| protected VerificationNotification finalizeVerification(BlockProof blockProof) { | ||
| protected VerificationNotification finalizeVerification() { | ||
|
|
||
| // pre-checks | ||
| if (previousBlockHash != Bytes.EMPTY | ||
|
|
@@ -139,12 +159,17 @@ | |
| traceDataHasher, | ||
| previousBlockHash); | ||
|
|
||
| final boolean verified = | ||
| verifySignature(blockRootHash, blockProof.signedBlockProof().blockSignature()); | ||
|
|
||
| // set the previous block hash for the next block | ||
| previousBlockHash = blockRootHash; | ||
|
|
||
| // confirm block proofs (tssSignedBlockProof, blockStateProof or signedRecordFileProof), one must be valid. | ||
| // As of CN v0.68 only TSS proof is supported. | ||
| int validProofCount = 0; | ||
| if (tssSignedBlockProof != null && verifyTssSignature(blockRootHash, tssSignedBlockProof.blockSignature())) { | ||
| validProofCount++; | ||
| } | ||
|
|
||
| boolean verified = validProofCount > 0; | ||
| return new VerificationNotification( | ||
| verified, blockNumber, blockRootHash, verified ? new BlockUnparsed(blockItems) : null, blockSource); | ||
| } | ||
|
|
@@ -156,7 +181,7 @@ | |
| * @param signature the signature to verify | ||
| * @return true if the signature is valid, false otherwise | ||
| */ | ||
| protected Boolean verifySignature(@NonNull Bytes hash, @NonNull Bytes signature) { | ||
| protected Boolean verifyTssSignature(@NonNull Bytes hash, @NonNull Bytes signature) { | ||
| // TODO we are close to having real TSS signature verification, we maybe should have a config if we are work on | ||
| // TODO preview or production block stream and hence which verification to use | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably won't work. We can have multiple of the same type of block proof.
StateProof type block proofs, in particular, are very likely to have multiple on a given block.
TSS signed proofs are currently expected to be singular, but that may not always be true. Signed record file proof type will probably always be singular, but we perhaps shouldn't assume that (for symmetry, if nothing else).