Merge branch 'main' into zkbesu

# Conflicts:
#	.github/workflows/acceptance-tests.yml
#	.github/workflows/codeql.yml
#	.github/workflows/integration-tests.yml
#	.github/workflows/pre-review.yml
#	.github/workflows/reference-tests.yml
#	build.gradle
This commit is contained in:
Fabio Di Fabio
2025-03-18 11:18:55 +01:00
526 changed files with 22840 additions and 22574 deletions

View File

@@ -39,6 +39,7 @@ dependencies {
implementation 'org.apache.commons:commons-lang3'
implementation 'org.apache.logging.log4j:log4j-core'
implementation 'org.apache.logging.log4j:log4j-slf4j2-impl'
implementation 'org.bouncycastle:bcpkix-jdk18on'
implementation 'org.xerial.snappy:snappy-java'
testImplementation 'org.mockito:mockito-junit-jupiter'

View File

@@ -0,0 +1,25 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
import java.util.List;
/**
* Represents a block index in an era1 file
*
* @param startingBlockIndex The first blockIndex number indexed by this block index
* @param indexes The indexes of the blocks indexed by this block index
*/
public record Era1BlockIndex(long startingBlockIndex, List<Long> indexes) {}

View File

@@ -0,0 +1,23 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
/**
* Represents an execution block body in an era1 file
*
* @param block The execution block
* @param blockIndex The blockIndex number
*/
public record Era1ExecutionBlockBody(byte[] block, int blockIndex) {}

View File

@@ -0,0 +1,23 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
/**
* Represents an execution block header in an era1 file
*
* @param header The execution block header
* @param blockIndex The blockIndex number
*/
public record Era1ExecutionBlockHeader(byte[] header, int blockIndex) {}

View File

@@ -0,0 +1,23 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
/**
* Represents an execution block's transaction receipts in an era1 file
*
* @param receipts The execution block's transaction receipts
* @param blockIndex The blockIndex number
*/
public record Era1ExecutionBlockReceipts(byte[] receipts, int blockIndex) {}

View File

@@ -0,0 +1,127 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
import org.hyperledger.besu.util.snappy.SnappyFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.util.Pack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xerial.snappy.SnappyFramedInputStream;
/** Reads era1 files */
public class Era1Reader {
private static final Logger LOG = LoggerFactory.getLogger(Era1Reader.class);
private static final int TYPE_LENGTH = 2;
private static final int LENGTH_LENGTH = 6;
private static final int STARTING_BLOCK_INDEX_LENGTH = 8;
private static final int BLOCK_INDEX_LENGTH = 8;
private static final int BLOCK_INDEX_COUNT_LENGTH = 8;
private final SnappyFactory snappyFactory;
/**
* Creates a new Era1Reader with the supplied SnappyFactory
*
* @param snappyFactory A factory to provide objects for snappy decompression
*/
public Era1Reader(final SnappyFactory snappyFactory) {
this.snappyFactory = snappyFactory;
}
/**
* Reads the entire supplied InputStream, calling appropriate methods on the supplied
* Era1ReaderListener as different parts of the file are read
*
* @param inputStream The InputStream
* @param listener the Era1ReaderListener
* @throws IOException If there are any problems reading from the InputStream, or creating and
* using other streams, such as a SnappyFramedInputStream
*/
public void read(final InputStream inputStream, final Era1ReaderListener listener)
throws IOException {
int blockIndex = 0;
while (inputStream.available() > 0) {
Era1Type type = Era1Type.getForTypeCode(inputStream.readNBytes(TYPE_LENGTH));
int length = (int) convertLittleEndianBytesToLong(inputStream.readNBytes(LENGTH_LENGTH));
switch (type) {
case VERSION -> {
// do nothing
}
case EMPTY, ACCUMULATOR, TOTAL_DIFFICULTY -> {
// skip the bytes that were indicated to be empty
// TODO read ACCUMULATOR and TOTAL_DIFFICULTY properly?
inputStream.skipNBytes(length);
}
case COMPRESSED_EXECUTION_BLOCK_HEADER -> {
byte[] compressedExecutionBlockHeader = inputStream.readNBytes(length);
try (SnappyFramedInputStream decompressionStream =
snappyFactory.createFramedInputStream(compressedExecutionBlockHeader)) {
listener.handleExecutionBlockHeader(
new Era1ExecutionBlockHeader(decompressionStream.readAllBytes(), blockIndex));
}
}
case COMPRESSED_EXECUTION_BLOCK_BODY -> {
byte[] compressedExecutionBlock = inputStream.readNBytes(length);
try (SnappyFramedInputStream decompressionStream =
snappyFactory.createFramedInputStream(compressedExecutionBlock)) {
listener.handleExecutionBlockBody(
new Era1ExecutionBlockBody(decompressionStream.readAllBytes(), blockIndex));
}
}
case COMPRESSED_EXECUTION_BLOCK_RECEIPTS -> {
byte[] compressedReceipts = inputStream.readNBytes(length);
try (SnappyFramedInputStream decompressionStream =
snappyFactory.createFramedInputStream(compressedReceipts)) {
listener.handleExecutionBlockReceipts(
new Era1ExecutionBlockReceipts(decompressionStream.readAllBytes(), blockIndex++));
}
}
case BLOCK_INDEX -> {
ByteArrayInputStream blockIndexInputStream =
new ByteArrayInputStream(inputStream.readNBytes(length));
long startingBlockIndex =
convertLittleEndianBytesToLong(
blockIndexInputStream.readNBytes(STARTING_BLOCK_INDEX_LENGTH));
List<Long> indexes = new ArrayList<>();
while (blockIndexInputStream.available() > BLOCK_INDEX_COUNT_LENGTH) {
indexes.add(
convertLittleEndianBytesToLong(
blockIndexInputStream.readNBytes(BLOCK_INDEX_LENGTH)));
}
long indexCount =
convertLittleEndianBytesToLong(
blockIndexInputStream.readNBytes(BLOCK_INDEX_COUNT_LENGTH));
if (indexCount != indexes.size()) {
LOG.warn(
"index count does not match number of indexes present for InputStream: {}",
inputStream);
}
listener.handleBlockIndex(new Era1BlockIndex(startingBlockIndex, indexes));
}
}
}
}
private long convertLittleEndianBytesToLong(final byte[] bytes) {
return Pack.littleEndianToLong(bytes, 0, bytes.length);
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
/** A Listener interface for listening to an Era1Reader */
public interface Era1ReaderListener {
/**
* Handles the supplied Era1ExecutionBlockHeader
*
* @param executionBlockHeader the Era1ExecutionBlockHeader
*/
void handleExecutionBlockHeader(Era1ExecutionBlockHeader executionBlockHeader);
/**
* Handles the supplied Era1ExecutionBlockBody
*
* @param executionBlockBody the Era1ExecutionBlockBody
*/
void handleExecutionBlockBody(Era1ExecutionBlockBody executionBlockBody);
/**
* Handles the supplied Era1ExecutionBlockReceipts
*
* @param executionBlockReceipts the Era1ExecutionBlockReceipts
*/
void handleExecutionBlockReceipts(Era1ExecutionBlockReceipts executionBlockReceipts);
/**
* Handles the supplied Era1BlockIndex
*
* @param blockIndex the Era1BlockIndex
*/
void handleBlockIndex(Era1BlockIndex blockIndex);
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
import java.util.HexFormat;
/** An enumeration of known sections of era1 files */
public enum Era1Type {
/** An empty section */
EMPTY(new byte[] {0x00, 0x00}),
/** A snappy compressed execution block header */
COMPRESSED_EXECUTION_BLOCK_HEADER(new byte[] {0x03, 0x00}),
/** A snappy compressed execution block body */
COMPRESSED_EXECUTION_BLOCK_BODY(new byte[] {0x04, 0x00}),
/** A snappy compressed list of execution block transaction receipts */
COMPRESSED_EXECUTION_BLOCK_RECEIPTS(new byte[] {0x05, 0x00}),
/** The total difficulty */
TOTAL_DIFFICULTY(new byte[] {0x06, 0x00}),
/** The accumulator */
ACCUMULATOR(new byte[] {0x07, 0x00}),
/** A version section */
VERSION(new byte[] {0x65, 0x32}),
/** An execution block index */
BLOCK_INDEX(new byte[] {0x66, 0x32}),
;
private final byte[] typeCode;
Era1Type(final byte[] typeCode) {
this.typeCode = typeCode;
}
/**
* Gets the type code
*
* @return the type code
*/
public byte[] getTypeCode() {
return typeCode;
}
/**
* Gets the Era1Type corresponding to the supplied typeCode
*
* @param typeCode the typeCode to find the corresponding Era1Type for
* @return the Era1Type corresponding to the supplied typeCode
* @throws IllegalArgumentException if there is no Era1Type corresponding to the supplied typeCode
*/
public static Era1Type getForTypeCode(final byte[] typeCode) {
if (typeCode == null || typeCode.length != 2) {
throw new IllegalArgumentException("typeCode must be 2 bytes");
}
Era1Type result = null;
for (Era1Type era1Type : values()) {
if (era1Type.typeCode[0] == typeCode[0] && era1Type.typeCode[1] == typeCode[1]) {
result = era1Type;
}
}
if (result == null) {
throw new IllegalArgumentException(
"typeCode " + HexFormat.of().formatHex(typeCode) + " is not recognised");
}
return result;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.snappy;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.xerial.snappy.SnappyFramedInputStream;
/** A Factory for producing objects related to handling snappy compressed data */
public class SnappyFactory {
/** Creates a SnappyFactory */
public SnappyFactory() {}
/**
* Creates a SnappyFramedInputStream reading from the supplied compressedData
*
* @param compressedData The data for the SnappyFramedInputStream to read
* @return a SnappyFramedInputStream reading from the supplied compressedData
* @throws IOException if the SnappyFramedInputStream is unable to be created
*/
public SnappyFramedInputStream createFramedInputStream(final byte[] compressedData)
throws IOException {
return new SnappyFramedInputStream(new ByteArrayInputStream(compressedData));
}
}

View File

@@ -0,0 +1,229 @@
/*
* Copyright contributors to Besu.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.util.era1;
import org.hyperledger.besu.util.snappy.SnappyFactory;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.xerial.snappy.SnappyFramedInputStream;
@ExtendWith(MockitoExtension.class)
public class Era1ReaderTest {
private @Mock SnappyFactory snappyFactory;
private Era1Reader reader;
@BeforeEach
public void beforeTest() {
reader = new Era1Reader(snappyFactory);
}
@Test
public void testReadForVersionType() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
Mockito.when(inputStream.available()).thenReturn(8, 0);
Mockito.when(inputStream.readNBytes(2)).thenReturn(Era1Type.VERSION.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
reader.read(inputStream, listener);
Mockito.verifyNoInteractions(snappyFactory);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verifyNoInteractions(listener);
}
@Test
public void testReadForEmptyType() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
Mockito.when(inputStream.available()).thenReturn(16, 0);
Mockito.when(inputStream.readNBytes(2)).thenReturn(Era1Type.EMPTY.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x08, 0x00, 0x00, 0x00, 0x00, 0x00});
reader.read(inputStream, listener);
Mockito.verifyNoInteractions(snappyFactory);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verify(inputStream).skipNBytes(8);
Mockito.verifyNoInteractions(listener);
}
@Test
public void testReadForCompressedExecutionBlockHeader() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
SnappyFramedInputStream snappyFramedInputStream = Mockito.mock(SnappyFramedInputStream.class);
Mockito.when(inputStream.available()).thenReturn(15, 0);
Mockito.when(inputStream.readNBytes(2))
.thenReturn(Era1Type.COMPRESSED_EXECUTION_BLOCK_HEADER.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x07, 0x00, 0x00, 0x00, 0x00, 0x00});
byte[] compressedExecutionBlockHeader = new byte[] {1, 2, 3, 4, 5, 6, 7};
Mockito.when(inputStream.readNBytes(7)).thenReturn(compressedExecutionBlockHeader);
Mockito.when(snappyFactory.createFramedInputStream(compressedExecutionBlockHeader))
.thenReturn(snappyFramedInputStream);
byte[] executionBlockHeader = new byte[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
Mockito.when(snappyFramedInputStream.readAllBytes()).thenReturn(executionBlockHeader);
reader.read(inputStream, listener);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verify(inputStream).readNBytes(7);
Mockito.verify(snappyFactory).createFramedInputStream(compressedExecutionBlockHeader);
Mockito.verify(snappyFramedInputStream).readAllBytes();
ArgumentCaptor<Era1ExecutionBlockHeader> executionBlockHeaderArgumentCaptor =
ArgumentCaptor.forClass(Era1ExecutionBlockHeader.class);
Mockito.verify(listener)
.handleExecutionBlockHeader(executionBlockHeaderArgumentCaptor.capture());
Mockito.verifyNoMoreInteractions(listener);
Era1ExecutionBlockHeader era1ExecutionBlockHeader =
executionBlockHeaderArgumentCaptor.getValue();
Assertions.assertEquals(executionBlockHeader, era1ExecutionBlockHeader.header());
Assertions.assertEquals(0, era1ExecutionBlockHeader.blockIndex());
}
@Test
public void testReadForCompressedExecutionBlockBody() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
SnappyFramedInputStream snappyFramedInputStream = Mockito.mock(SnappyFramedInputStream.class);
Mockito.when(inputStream.available()).thenReturn(15, 0);
Mockito.when(inputStream.readNBytes(2))
.thenReturn(Era1Type.COMPRESSED_EXECUTION_BLOCK_BODY.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x07, 0x00, 0x00, 0x00, 0x00, 0x00});
byte[] compressedExecutionBlockBody = new byte[] {1, 2, 3, 4, 5, 6, 7};
Mockito.when(inputStream.readNBytes(7)).thenReturn(compressedExecutionBlockBody);
Mockito.when(snappyFactory.createFramedInputStream(compressedExecutionBlockBody))
.thenReturn(snappyFramedInputStream);
byte[] executionBlockBody = new byte[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
Mockito.when(snappyFramedInputStream.readAllBytes()).thenReturn(executionBlockBody);
reader.read(inputStream, listener);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verify(inputStream).readNBytes(7);
Mockito.verify(snappyFactory).createFramedInputStream(compressedExecutionBlockBody);
Mockito.verify(snappyFramedInputStream).readAllBytes();
ArgumentCaptor<Era1ExecutionBlockBody> executionBlockBodyArgumentCaptor =
ArgumentCaptor.forClass(Era1ExecutionBlockBody.class);
Mockito.verify(listener).handleExecutionBlockBody(executionBlockBodyArgumentCaptor.capture());
Mockito.verifyNoMoreInteractions(listener);
Era1ExecutionBlockBody era1ExecutionBlockBody = executionBlockBodyArgumentCaptor.getValue();
Assertions.assertEquals(executionBlockBody, era1ExecutionBlockBody.block());
Assertions.assertEquals(0, era1ExecutionBlockBody.blockIndex());
}
@Test
public void testReadForCompressedExecutionBlockReceipts() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
SnappyFramedInputStream snappyFramedInputStream = Mockito.mock(SnappyFramedInputStream.class);
Mockito.when(inputStream.available()).thenReturn(15, 0);
Mockito.when(inputStream.readNBytes(2))
.thenReturn(Era1Type.COMPRESSED_EXECUTION_BLOCK_RECEIPTS.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x07, 0x00, 0x00, 0x00, 0x00, 0x00});
byte[] compressedExecutionBlockReceipts = new byte[] {1, 2, 3, 4, 5, 6, 7};
Mockito.when(inputStream.readNBytes(7)).thenReturn(compressedExecutionBlockReceipts);
Mockito.when(snappyFactory.createFramedInputStream(compressedExecutionBlockReceipts))
.thenReturn(snappyFramedInputStream);
byte[] executionBlockReceipts = new byte[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
Mockito.when(snappyFramedInputStream.readAllBytes()).thenReturn(executionBlockReceipts);
reader.read(inputStream, listener);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verify(inputStream).readNBytes(7);
Mockito.verify(snappyFactory).createFramedInputStream(compressedExecutionBlockReceipts);
Mockito.verify(snappyFramedInputStream).readAllBytes();
ArgumentCaptor<Era1ExecutionBlockReceipts> executionBlockReceiptsArgumentCaptor =
ArgumentCaptor.forClass(Era1ExecutionBlockReceipts.class);
Mockito.verify(listener)
.handleExecutionBlockReceipts(executionBlockReceiptsArgumentCaptor.capture());
Mockito.verifyNoMoreInteractions(listener);
Era1ExecutionBlockReceipts era1ExecutionBlockReceipts =
executionBlockReceiptsArgumentCaptor.getValue();
Assertions.assertEquals(executionBlockReceipts, era1ExecutionBlockReceipts.receipts());
Assertions.assertEquals(0, era1ExecutionBlockReceipts.blockIndex());
}
@Test
public void testReadForBlockIndexType() throws IOException {
InputStream inputStream = Mockito.mock(InputStream.class);
Era1ReaderListener listener = Mockito.mock(Era1ReaderListener.class);
Mockito.when(inputStream.available()).thenReturn(40, 0);
Mockito.when(inputStream.readNBytes(2)).thenReturn(Era1Type.BLOCK_INDEX.getTypeCode());
Mockito.when(inputStream.readNBytes(6))
.thenReturn(new byte[] {0x20, 0x00, 0x00, 0x00, 0x00, 0x00});
Mockito.when(inputStream.readNBytes(32))
.thenReturn(
new byte[] {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
});
reader.read(inputStream, listener);
Mockito.verifyNoInteractions(snappyFactory);
Mockito.verify(inputStream, Mockito.times(2)).available();
Mockito.verify(inputStream).readNBytes(2);
Mockito.verify(inputStream).readNBytes(6);
Mockito.verify(inputStream).readNBytes(32);
ArgumentCaptor<Era1BlockIndex> blockIndexArgumentCaptor =
ArgumentCaptor.forClass(Era1BlockIndex.class);
Mockito.verify(listener).handleBlockIndex(blockIndexArgumentCaptor.capture());
Mockito.verifyNoMoreInteractions(listener);
Era1BlockIndex blockIndex = blockIndexArgumentCaptor.getValue();
Assertions.assertEquals(1, blockIndex.startingBlockIndex());
Assertions.assertEquals(List.of(2L, 3L), blockIndex.indexes());
}
}