mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 07:27:55 -05:00
7935: Add E2StoreReader (#8329)
* Refactor to use clock to validate expiry Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * 7935: Finish unit testing E2StoreReader Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Build out E2StoreReader and associated files Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Spotless Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Add javadoc to new util module classes Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Remove unnecessary e2 and era file stuff Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Rename files to be era1 specific Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Rename e2 package to era1 Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Spotless Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Rename Era1StoreReaderListener to Era1ReaderListener Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Use bouncycastle for little endian to long conversion Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Rename slot related variables to blockIndex Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Spotless Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> * Use Pack.littleEndianToLong with length to avoid using Arrays.concatenate Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net> --------- Signed-off-by: Matilda Clerke <matilda.clerke@consensys.net>
This commit is contained in:
@@ -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'
|
||||
|
||||
@@ -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) {}
|
||||
@@ -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) {}
|
||||
@@ -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) {}
|
||||
@@ -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) {}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user