@@ -49,12 +49,14 @@ class IndirectProofSequenceValidator {
4949
5050 private final Map <Long , Bytes > expectedBlockRootHashes = new HashMap <>();
5151 private final Map <Long , Bytes > expectedPreviousBlockRootHashes = new HashMap <>();
52+ private final Map <Long , MerkleSiblingHash []> expectedSiblingsByBlock = new HashMap <>();
5253
5354 /**
5455 * The signed block proof corresponding to the latest signed block number. This is needed to
5556 * verify the indirect proofs and must be the last proof in the sequence.
5657 */
5758 private BlockProof signedProof ;
59+
5860 /**
5961 * The consensus timestamp of the signed block corresponding to the latest signed block number.
6062 */
@@ -93,9 +95,10 @@ boolean containsIndirectProofs() {
9395 void registerProof (
9496 final long blockNumber ,
9597 final @ NonNull BlockProof proof ,
96- final @ NonNull Bytes blockRootHash ,
98+ final @ NonNull Bytes expectedBlockHash ,
9799 final @ NonNull Bytes previousBlockHash ,
98- final @ NonNull Timestamp blockTimestamp ) {
100+ final @ NonNull Timestamp blockTimestamp ,
101+ final @ NonNull MerkleSiblingHash [] expectedSiblings ) {
99102 if (endOfSequenceReached ) {
100103 throw new IllegalStateException (
101104 "Cannot track indirect proof for block #%s: end of sequence previously reached"
@@ -135,10 +138,7 @@ void registerProof(
135138 // Block's Merkle Path 2: block contents path
136139 // Technically we could roll the timestamp into the sibling hashes here, but for clarity we keep them
137140 // separate
138- final var siblingHashes = proof .blockStateProof ().paths ().get (BLOCK_CONTENTS_PATH_INDEX ).siblings ().stream ()
139- .map (s -> new MerkleSiblingHash (s .isLeft (), s .hash ()))
140- .toList ();
141- final var mp2 = new PartialMerklePath (null , previousBlockHash , siblingHashes );
141+ final var mp2 = new PartialMerklePath (null , previousBlockHash , Arrays .asList (expectedSiblings ));
142142
143143 // Block's Merkle Path 3: parent (i.e. combined hash of left child and right child)
144144 // This is the combined result and should have no data
@@ -150,8 +150,9 @@ void registerProof(
150150 actualIndirectProofs .put (blockNumber , proof .blockStateProof ());
151151 }
152152
153- expectedBlockRootHashes .put (blockNumber , blockRootHash );
153+ expectedBlockRootHashes .put (blockNumber , expectedBlockHash );
154154 expectedPreviousBlockRootHashes .put (blockNumber , previousBlockHash );
155+ expectedSiblingsByBlock .put (blockNumber , expectedSiblings );
155156
156157 log .info ("Registered proof for block {}" , blockNumber );
157158 }
@@ -313,8 +314,8 @@ private Map<Long, MerklePath[]> constructExpectedMerklePaths() {
313314 // Merkle Path 2: enumerate all sibling hashes for remaining UNSIGNED blocks
314315 MerklePath .Builder earliestBlockMp2 = MerklePath .newBuilder ();
315316
316- // Create a set of siblings for all unsigned blocks remaining, plus another set for the signed block (excluding
317- // its timestamp)
317+ // Create a set of siblings for all _unsigned_ blocks remaining, plus another set for the signed block
318+ // (excluding its timestamp)
318319 final var numBlocksRemaining = signedBlockNum - firstUnsignedBlockNum ;
319320 final var totalExpectedSiblings = expectedSiblingsFrom (numBlocksRemaining );
320321 final SiblingNode [] allSiblingHashes = new SiblingNode [totalExpectedSiblings ];
@@ -361,11 +362,12 @@ private Map<Long, MerklePath[]> constructExpectedMerklePaths() {
361362 final var currUnsignedBlockSiblings = new SiblingNode [currUnsignedBlockSiblingsSize ];
362363 final var currUnsignedBlockStartingIndex =
363364 (int ) ((currUnsignedBlock - firstUnsignedBlockNum ) * UNSIGNED_BLOCK_SIBLING_COUNT );
365+ currentBlockNum = 0 ;
364366 for (int i = currUnsignedBlockStartingIndex ; i < allSiblingHashes .length ; i ++) {
365367 // Copy the subset of sibling hashes from the full set of hashes (note: COPIES the current hash)
366- currUnsignedBlockSiblings [i ] = allSiblingHashes [ currUnsignedBlockStartingIndex + i ]
367- .copyBuilder ()
368- . build () ;
368+ currUnsignedBlockSiblings [( int ) currentBlockNum ] =
369+ allSiblingHashes [ i ] .copyBuilder (). build ();
370+ currentBlockNum ++ ;
369371 }
370372
371373 newMp2 .siblings (currUnsignedBlockSiblings ).nextPathIndex (FINAL_MERKLE_PATH_INDEX );
@@ -415,8 +417,14 @@ private void verifyHashSequence() {
415417 // Verify the sequence of hashes by recomputing each block hash from the previous block
416418 // hash and the indirect proof
417419 final var finalExpectedHash = expectedBlockRootHashes .get (signedBlockNum );
420+ assertTrue (
421+ finalExpectedHash .length () > 0 ,
422+ "Final expected block hash is empty for signed block " + signedBlockNum );
418423 for (long blockNum = firstUnsignedBlockNum ; blockNum < signedBlockNum ; blockNum ++) {
419424 final var expectedPreviousBlockHash = expectedPreviousBlockRootHashes .get (blockNum );
425+ assertTrue (
426+ expectedPreviousBlockHash .length () > 0 ,
427+ "Expected previous block hash is empty for block " + blockNum );
420428
421429 final var actualBlockStateProof = actualIndirectProofs .get (blockNum );
422430 assertNotNull (actualBlockStateProof , "Missing indirect state proof for block " + blockNum );
@@ -489,7 +497,7 @@ private static int expectedSiblingsFrom(final long numUnsignedBlocksRemaining) {
489497 // For the signed block we _do_ include its siblings in the state proof's block contents path, but we _don't_
490498 // include the timestamp as a sibling hash. The verification algorithm expects the signed block's timestamp to
491499 // be provided separately.
492- return unsignedSiblingCount + + SIGNED_BLOCK_SIBLING_COUNT ;
500+ return unsignedSiblingCount + SIGNED_BLOCK_SIBLING_COUNT ;
493501 }
494502
495503 // A quick note: any field in this record can be null depending on which of the three types of merkle path it
0 commit comments