feat(verification): TSS Integration on verification path#2305
feat(verification): TSS Integration on verification path#2305AlfredoG87 wants to merge 9 commits intomainfrom
Conversation
…tion - Verify block proofs via TSS.verifyTSS() with full chain-of-trust - Parse LedgerIdPublicationTransactionBody from block 0 to bootstrap address book, WRAPS VK, and ledger ID - Add verification.ledgerId config property to pre-seed ledger ID for networks joined mid-stream - Drop TSS-only (historyEnabled=false) mode; TssWraps only per expert guidance - Add TssWraps block 0 fixture; settled-path test disabled pending fixture generation - Export com.hedera.hapi.node.tss packages from protobuf-pbj module Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
0b486b2 to
c8ca9d8
Compare
…ck 0 instead of pre-configured Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
- Add verification.ledgerId config to pre-seed ledger ID for nodes joining an established network mid-stream (block 0 will not be replayed) - Add verification.ledgerIdFilePath config to persist ledger ID across restarts - Block 0 is authoritative: always writes the ledger ID file on completion - File takes priority over config string at startup; block 0 always overwrites both - Add 5 bootstrap path tests covering all paths and combinations Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
jsync-swirlds
left a comment
There was a problem hiding this comment.
This is a good design, but there are some areas we could still improve.
block-node/verification/src/main/java/org/hiero/block/node/verification/VerificationConfig.java
Outdated
Show resolved
Hide resolved
.../verification/src/main/java/org/hiero/block/node/verification/VerificationServicePlugin.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
Outdated
Show resolved
Hide resolved
.../src/main/java/org/hiero/block/node/verification/session/impl/ExtendedMerkleTreeSession.java
Outdated
Show resolved
Hide resolved
.../verification/src/main/java/org/hiero/block/node/verification/VerificationServicePlugin.java
Outdated
Show resolved
Hide resolved
.../verification/src/main/java/org/hiero/block/node/verification/VerificationServicePlugin.java
Outdated
Show resolved
Hide resolved
Nana-EC
left a comment
There was a problem hiding this comment.
Started, will circle back
| // bootstraps TSS native state (address book + WRAPS VK) and sets ACTIVE_LEDGER_ID. | ||
| // Returns true if the publication was found and applied, false otherwise. | ||
| private static boolean loadLedgerId(Bytes signedTxBytes) throws ParseException { | ||
| if (signedTxBytes == null || signedTxBytes.length() == 0) { |
There was a problem hiding this comment.
Q: Should we capture the block number and ensure that we're only ever setting assuming the block number is incrementing.
I'm curious about a backfill scenario that included the LedgerIdPublicationTransactionBody and overwrites the more recent values?
There was a problem hiding this comment.
Good question. TSS initialization only triggers for block 0 (if (blockItemsMessage.blockNumber() == 0)), so backfill of other blocks won't attempt to overwrite. Additionally, the tssParametersPersisted guard on initializeTssParameters() prevents any overwrite once the parameters have been successfully
verified and persisted. A backfilled block 0 would only initialize TSS parameters if they haven't been persisted yet, which is the correct behavior for a node that doesn't have block 0 locally.
However unlikely since such cases most likely manually copy/pasted the /opt/hiero/block-node/verification/tss-parameters.bin file for that network, similar as we are planing to do with the TSS Cutover EPIC.
- Move TSS state (activeLedgerId, activeTssPublication) from ExtendedMerkleTreeSession to VerificationServicePlugin as public static fields - Add public static initializeTssParameters() on plugin with tssParametersPersisted guard; session calls it during block 0 when LedgerIdPublicationTransactionBody is discovered - TSS parameters can be overwritten by any block 0 until persisted after successful verification; once persisted, initializeTssParameters() is a no-op - Split loadLedgerId() into findLedgerIdPublication() (pure parsing on session) and initializeTssParameters() (native init on plugin) - Remove VK_LENGTH constant; let TSS.verifyTSS() handle validation internally - Remove verification.ledgerId config string (useless without address book/WRAPS VK) - Rename verification.ledgerIdFilePath to verification.tssParametersFilePath - Persist/restore full LedgerIdPublicationTransactionBody protobuf (ledger ID + address book + WRAPS VK) instead of raw ledger ID bytes - Fix backfill block 0 persisting TSS parameters without checking verification success - Add hedera-cryptography-wraps dependency - Add TssWraps test fixtures (block 0 and block 50) and verification tests - Add plugin-level integration test verifying full TSS flow: block 0 bootstraps TSS parameters, subsequent block verifies with TSS Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
Signed-off-by: Alfredo Gutierrez Grajeda <alfredo@hashgraph.com>
Codecov Report❌ Patch coverage is @@ Coverage Diff @@
## main #2305 +/- ##
============================================
+ Coverage 80.74% 80.81% +0.06%
- Complexity 1461 1472 +11
============================================
Files 139 139
Lines 6766 6837 +71
Branches 728 738 +10
============================================
+ Hits 5463 5525 +62
- Misses 984 990 +6
- Partials 319 322 +3
... and 1 file with indirect coverage changes 🚀 New features to boost your workflow:
|
Context
Starting with HAPI 0.72.0, Consensus Nodes sign block proofs using TSS (Threshold Signature Scheme) instead of the legacy hash of hash signature. Verifying these proofs requires three components: a ledger ID, an address book (node public keys, weights, and IDs), and a WRAPS verification key. All three are published together in block 0 via a
LedgerIdPublicationTransactionBodyembedded in a signed transaction.This PR wires that bootstrap into the live verification path so that block nodes can verify TSS-signed blocks end-to-end.
How It Works
Block 0 bootstrap: When the session processes block 0, it scans
SIGNED_TRANSACTIONitems for aLedgerIdPublicationTransactionBody. When found, it callsVerificationServicePlugin.initializeTssParameters(), which sets the native TSS state (address book, WRAPS VK) and stores the publication on the plugin. If block 0 verification then succeeds, the full publication is persisted to disk as a serialized protobuf.Restart recovery: On startup, if the TSS parameters file exists, the plugin loads and restores the full publication — ledger ID, address book, and WRAPS VK — before any blocks are processed.
Retry semantics: If block 0 fails verification (e.g., tampered items), TSS parameters are not locked in. Any subsequent block 0 can overwrite them and try again. Once parameters are persisted after a successful verification, they are locked —
initializeTssParameters()becomes a no-op, preventing a corrupt block 0 from poisoning verified state.Session design: Each session is short-lived (one per block) and receives the current
ledgerIdvia constructor. The plugin — which owns process-level state — is the right home for TSS parameters.Key Changes
VerificationServicePluginowns TSS state aspublic staticfields (activeLedgerId,activeTssPublication,tssParametersPersisted)ExtendedMerkleTreeSessionreceivesledgerIdvia constructor and callsVerificationServicePlugin.initializeTssParameters()when it discovers the publication in block 0LedgerIdPublicationTransactionBodyprotobuf instead of just raw ledger ID bytes (fixes incomplete state restoration on restart)verification.ledgerIdFilePath→verification.tssParametersFilePathto reflect that it stores more than just the ledger IDverification.ledgerIdconfig property — a ledger ID alone is useless without the address book and WRAPS VKbackfillNotification.success()hedera-cryptography-wrapsdependency for WRAPS VK initializationFollow-up
TSS state currently lives as static fields on the plugin as a pragmatic starting point (the native TSS library is itself a singleton). Moving it into
BlockNodeContextso other plugins can access it is tracked in #2321.Fixes #1660
Fixes #1659
Fixes #2008