Skip to content

Commit 90db487

Browse files
7935: add era1 format to blocks importer (#8352)
* Refactor to use clock to validate expiry Signed-off-by: Matilda Clerke <[email protected]> * 7935: Finish unit testing E2StoreReader Signed-off-by: Matilda Clerke <[email protected]> * Build out E2StoreReader and associated files Signed-off-by: Matilda Clerke <[email protected]> * Spotless Signed-off-by: Matilda Clerke <[email protected]> * Add javadoc to new util module classes Signed-off-by: Matilda Clerke <[email protected]> * Implement Era1 block import sub command Signed-off-by: Matilda Clerke <[email protected]> * Remove unnecessary e2 and era file stuff Signed-off-by: Matilda Clerke <[email protected]> * Rename files to be era1 specific Signed-off-by: Matilda Clerke <[email protected]> * Rename e2 package to era1 Signed-off-by: Matilda Clerke <[email protected]> * Spotless Signed-off-by: Matilda Clerke <[email protected]> * Rename Era1StoreReaderListener to Era1ReaderListener Signed-off-by: Matilda Clerke <[email protected]> * Clean up after merge Signed-off-by: Matilda Clerke <[email protected]> * Set up Era1BlockImporter to enable FAST sync and variations upon besu running Signed-off-by: Matilda Clerke <[email protected]> * Use bouncycastle for little endian to long conversion Signed-off-by: Matilda Clerke <[email protected]> * Rename slot related variables to blockIndex Signed-off-by: Matilda Clerke <[email protected]> * Spotless Signed-off-by: Matilda Clerke <[email protected]> * Fix broken unit test Signed-off-by: Matilda Clerke <[email protected]> * Fix AT compilation Signed-off-by: Matilda Clerke <[email protected]> * Fix javadoc Signed-off-by: Matilda Clerke <[email protected]> * Rework Era1BlockImporter to use appropriate data directory. Add unit test Signed-off-by: Matilda Clerke <[email protected]> * Fix javadoc Signed-off-by: Matilda Clerke <[email protected]> * changelog Signed-off-by: Matilda Clerke <[email protected]> * Add era1 files to .gitattributes as binary file type Signed-off-by: Matilda Clerke <[email protected]> * Remove pivot block header file creation from Era1BlockImporter Signed-off-by: Matilda Clerke <[email protected]> --------- Signed-off-by: Matilda Clerke <[email protected]> Signed-off-by: Matilda-Clerke <[email protected]>
1 parent e0bad46 commit 90db487

File tree

13 files changed

+320
-11
lines changed

13 files changed

+320
-11
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,5 @@
1717
*.p12 binary
1818
*.db binary
1919
*.woff2 binary
20+
*.era1 binary
2021
goss-linux-amd64 binary

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
- Update `eth_getLogs` to return a `Block not found` error when the requested block is not found. [#8290](https://github.com/hyperledger/besu/pull/8290)
4141
- Change `Invalid block, unable to parse RLP` RPC error message to `Invalid block param (block not found)` [#8328](https://github.com/hyperledger/besu/pull/8328)
4242
- Support pending transaction score when saving and restoring txpool [#8363](https://github.com/hyperledger/besu/pull/8363)
43+
- Add era1 format to blocks import subcommand [#7935](https://github.com/hyperledger/besu/issues/7935)
4344

4445
### Bug fixes
4546
- Add missing RPC method `debug_accountRange` to `RpcMethod.java` so this method can be used with `--rpc-http-api-method-no-auth` [#8153](https://github.com/hyperledger/besu/issues/8153)

acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ThreadBesuNodeRunner.java

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.hyperledger.besu.Runner;
2020
import org.hyperledger.besu.RunnerBuilder;
2121
import org.hyperledger.besu.chainexport.RlpBlockExporter;
22+
import org.hyperledger.besu.chainimport.Era1BlockImporter;
2223
import org.hyperledger.besu.chainimport.JsonBlockImporter;
2324
import org.hyperledger.besu.chainimport.RlpBlockImporter;
2425
import org.hyperledger.besu.cli.BesuCommand;
@@ -632,6 +633,7 @@ BesuCommand provideBesuCommand(final BesuPluginContextImpl pluginContext) {
632633
new BesuCommand(
633634
RlpBlockImporter::new,
634635
JsonBlockImporter::new,
636+
Era1BlockImporter::new,
635637
RlpBlockExporter::new,
636638
new RunnerBuilder(),
637639
new BesuController.Builder(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright contributors to Besu.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*
13+
* SPDX-License-Identifier: Apache-2.0
14+
*/
15+
package org.hyperledger.besu.chainimport;
16+
17+
import org.hyperledger.besu.controller.BesuController;
18+
import org.hyperledger.besu.ethereum.ProtocolContext;
19+
import org.hyperledger.besu.ethereum.core.Block;
20+
import org.hyperledger.besu.ethereum.core.BlockBody;
21+
import org.hyperledger.besu.ethereum.core.BlockHeader;
22+
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
23+
import org.hyperledger.besu.ethereum.core.BlockImporter;
24+
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
25+
import org.hyperledger.besu.ethereum.mainnet.BlockImportResult;
26+
import org.hyperledger.besu.ethereum.mainnet.BodyValidationMode;
27+
import org.hyperledger.besu.ethereum.mainnet.HeaderValidationMode;
28+
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
29+
import org.hyperledger.besu.ethereum.mainnet.ScheduleBasedBlockHeaderFunctions;
30+
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
31+
import org.hyperledger.besu.ethereum.rlp.RLPInput;
32+
import org.hyperledger.besu.util.era1.Era1BlockIndex;
33+
import org.hyperledger.besu.util.era1.Era1ExecutionBlockBody;
34+
import org.hyperledger.besu.util.era1.Era1ExecutionBlockHeader;
35+
import org.hyperledger.besu.util.era1.Era1ExecutionBlockReceipts;
36+
import org.hyperledger.besu.util.era1.Era1Reader;
37+
import org.hyperledger.besu.util.era1.Era1ReaderListener;
38+
import org.hyperledger.besu.util.snappy.SnappyFactory;
39+
40+
import java.io.Closeable;
41+
import java.io.FileInputStream;
42+
import java.io.IOException;
43+
import java.nio.file.Path;
44+
import java.util.ArrayList;
45+
import java.util.List;
46+
import java.util.concurrent.CompletableFuture;
47+
import java.util.concurrent.ExecutionException;
48+
import java.util.concurrent.Future;
49+
import java.util.concurrent.TimeUnit;
50+
import java.util.concurrent.TimeoutException;
51+
52+
import org.apache.tuweni.bytes.Bytes;
53+
import org.slf4j.Logger;
54+
import org.slf4j.LoggerFactory;
55+
56+
/**
57+
* Tool for importing era1-encoded block data, headers, and transaction receipts from era1 files.
58+
*/
59+
public class Era1BlockImporter implements Closeable {
60+
private static final Logger LOG = LoggerFactory.getLogger(Era1BlockImporter.class);
61+
62+
private static final int ERA1_BLOCK_COUNT_MAX = 8192;
63+
private static final int IMPORT_COUNT_FOR_LOG_UPDATE = 1000;
64+
65+
/** Default Constructor. */
66+
public Era1BlockImporter() {}
67+
68+
/**
69+
* Imports the blocks, headers, and transaction receipts from the file found at the supplied path
70+
*
71+
* @param controller The BesuController
72+
* @param path The path
73+
* @throws IOException IOException
74+
* @throws ExecutionException ExecutionException
75+
* @throws InterruptedException InterruptedException
76+
* @throws TimeoutException TimeoutException
77+
*/
78+
public void importBlocks(final BesuController controller, final Path path)
79+
throws IOException, ExecutionException, InterruptedException, TimeoutException {
80+
final ProtocolSchedule protocolSchedule = controller.getProtocolSchedule();
81+
final BlockHeaderFunctions blockHeaderFunctions =
82+
ScheduleBasedBlockHeaderFunctions.create(protocolSchedule);
83+
final ProtocolContext context = controller.getProtocolContext();
84+
85+
Era1Reader reader = new Era1Reader(new SnappyFactory());
86+
87+
final List<Future<BlockHeader>> headersFutures = new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
88+
final List<Future<BlockBody>> bodiesFutures = new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
89+
final List<Future<List<TransactionReceipt>>> receiptsFutures =
90+
new ArrayList<>(ERA1_BLOCK_COUNT_MAX);
91+
reader.read(
92+
new FileInputStream(path.toFile()),
93+
new Era1ReaderListener() {
94+
95+
@Override
96+
public void handleExecutionBlockHeader(
97+
final Era1ExecutionBlockHeader executionBlockHeader) {
98+
headersFutures.add(
99+
CompletableFuture.supplyAsync(
100+
() ->
101+
BlockHeader.readFrom(
102+
new BytesValueRLPInput(
103+
Bytes.wrap(executionBlockHeader.header()), false),
104+
blockHeaderFunctions)));
105+
}
106+
107+
@Override
108+
public void handleExecutionBlockBody(final Era1ExecutionBlockBody executionBlockBody) {
109+
bodiesFutures.add(
110+
CompletableFuture.supplyAsync(
111+
() ->
112+
BlockBody.readWrappedBodyFrom(
113+
new BytesValueRLPInput(Bytes.wrap(executionBlockBody.block()), false),
114+
blockHeaderFunctions,
115+
true)));
116+
}
117+
118+
@Override
119+
public void handleExecutionBlockReceipts(
120+
final Era1ExecutionBlockReceipts executionBlockReceipts) {
121+
receiptsFutures.add(
122+
CompletableFuture.supplyAsync(
123+
() -> {
124+
RLPInput input =
125+
new BytesValueRLPInput(
126+
Bytes.wrap(executionBlockReceipts.receipts()), false);
127+
final List<TransactionReceipt> receiptsForBlock = new ArrayList<>();
128+
input.readList((in) -> receiptsForBlock.add(TransactionReceipt.readFrom(in)));
129+
return receiptsForBlock;
130+
}));
131+
}
132+
133+
@Override
134+
public void handleBlockIndex(final Era1BlockIndex blockIndex) {
135+
// not really necessary, do nothing
136+
}
137+
});
138+
139+
LOG.info("Read {} blocks, now importing", headersFutures.size());
140+
141+
Block block = null;
142+
for (int i = 0; i < headersFutures.size(); i++) {
143+
BlockHeader blockHeader = headersFutures.get(i).get(10, TimeUnit.SECONDS);
144+
BlockImporter blockImporter =
145+
protocolSchedule.getByBlockHeader(blockHeader).getBlockImporter();
146+
block = new Block(blockHeader, bodiesFutures.get(i).get(10, TimeUnit.SECONDS));
147+
148+
BlockImportResult importResult =
149+
blockImporter.importBlockForSyncing(
150+
context,
151+
block,
152+
receiptsFutures.get(i).get(10, TimeUnit.SECONDS),
153+
HeaderValidationMode.NONE,
154+
HeaderValidationMode.NONE,
155+
BodyValidationMode.NONE,
156+
false);
157+
if (importResult.getStatus() != BlockImportResult.BlockImportStatus.IMPORTED) {
158+
LOG.warn(
159+
"Failed to import block {} due to {}",
160+
blockHeader.getNumber(),
161+
importResult.getStatus());
162+
} else if (i % IMPORT_COUNT_FOR_LOG_UPDATE == 0) {
163+
LOG.info("{}/{} blocks imported", i, headersFutures.size());
164+
}
165+
}
166+
LOG.info("Done importing {} blocks", headersFutures.size());
167+
}
168+
169+
@Override
170+
public void close() throws IOException {}
171+
}

besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java

+10-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.hyperledger.besu.Runner;
3232
import org.hyperledger.besu.RunnerBuilder;
3333
import org.hyperledger.besu.chainexport.RlpBlockExporter;
34+
import org.hyperledger.besu.chainimport.Era1BlockImporter;
3435
import org.hyperledger.besu.chainimport.JsonBlockImporter;
3536
import org.hyperledger.besu.chainimport.RlpBlockImporter;
3637
import org.hyperledger.besu.cli.config.EthNetworkConfig;
@@ -284,6 +285,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
284285

285286
private final Supplier<RlpBlockImporter> rlpBlockImporter;
286287
private final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory;
288+
private final Supplier<Era1BlockImporter> era1BlockImporter;
287289
private final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory;
288290

289291
// Unstable CLI options
@@ -719,6 +721,7 @@ static class PrivacyOptionGroup {
719721
*
720722
* @param rlpBlockImporter RlpBlockImporter supplier
721723
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
724+
* @param era1BlockImporter Era1BlockImporter supplier
722725
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
723726
* @param runnerBuilder instance of RunnerBuilder
724727
* @param controllerBuilder instance of BesuController.Builder
@@ -729,6 +732,7 @@ static class PrivacyOptionGroup {
729732
public BesuCommand(
730733
final Supplier<RlpBlockImporter> rlpBlockImporter,
731734
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
735+
final Supplier<Era1BlockImporter> era1BlockImporter,
732736
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
733737
final RunnerBuilder runnerBuilder,
734738
final BesuController.Builder controllerBuilder,
@@ -738,6 +742,7 @@ public BesuCommand(
738742
this(
739743
rlpBlockImporter,
740744
jsonBlockImporterFactory,
745+
era1BlockImporter,
741746
rlpBlockExporterFactory,
742747
runnerBuilder,
743748
controllerBuilder,
@@ -760,6 +765,7 @@ public BesuCommand(
760765
*
761766
* @param rlpBlockImporter RlpBlockImporter supplier
762767
* @param jsonBlockImporterFactory instance of {@code Function<BesuController, JsonBlockImporter>}
768+
* @param era1BlockImporter Era1BlockImporter supplier
763769
* @param rlpBlockExporterFactory instance of {@code Function<Blockchain, RlpBlockExporter>}
764770
* @param runnerBuilder instance of RunnerBuilder
765771
* @param controllerBuilder instance of BesuController.Builder
@@ -780,6 +786,7 @@ public BesuCommand(
780786
protected BesuCommand(
781787
final Supplier<RlpBlockImporter> rlpBlockImporter,
782788
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
789+
final Supplier<Era1BlockImporter> era1BlockImporter,
783790
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
784791
final RunnerBuilder runnerBuilder,
785792
final BesuController.Builder controllerBuilder,
@@ -798,8 +805,9 @@ protected BesuCommand(
798805

799806
this.logger = commandLogger;
800807
this.rlpBlockImporter = rlpBlockImporter;
801-
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
802808
this.jsonBlockImporterFactory = jsonBlockImporterFactory;
809+
this.era1BlockImporter = era1BlockImporter;
810+
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
803811
this.runnerBuilder = runnerBuilder;
804812
this.controllerBuilder = controllerBuilder;
805813
this.besuPluginContext = besuPluginContext;
@@ -1100,6 +1108,7 @@ private void addSubCommands(final InputStream in) {
11001108
new BlocksSubCommand(
11011109
rlpBlockImporter,
11021110
jsonBlockImporterFactory,
1111+
era1BlockImporter,
11031112
rlpBlockExporterFactory,
11041113
commandLine.getOut()));
11051114
commandLine.addSubcommand(

besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlockImportFormat.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,7 @@ public enum BlockImportFormat {
1919
/** RLP block import format. */
2020
RLP,
2121
/** Json block import format. */
22-
JSON
22+
JSON,
23+
/** Era1 block import format. */
24+
ERA1,
2325
}

besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java

+19-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.hyperledger.besu.cli.subcommands.blocks.BlocksSubCommand.COMMAND_NAME;
1919

2020
import org.hyperledger.besu.chainexport.RlpBlockExporter;
21+
import org.hyperledger.besu.chainimport.Era1BlockImporter;
2122
import org.hyperledger.besu.chainimport.JsonBlockImporter;
2223
import org.hyperledger.besu.chainimport.RlpBlockImporter;
2324
import org.hyperledger.besu.cli.BesuCommand;
@@ -51,6 +52,7 @@
5152
import java.util.ArrayList;
5253
import java.util.List;
5354
import java.util.Optional;
55+
import java.util.concurrent.TimeoutException;
5456
import java.util.function.Function;
5557
import java.util.function.Supplier;
5658

@@ -92,6 +94,7 @@ public class BlocksSubCommand implements Runnable {
9294

9395
private final Supplier<RlpBlockImporter> rlpBlockImporter;
9496
private final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory;
97+
private final Supplier<Era1BlockImporter> era1BlockImporter;
9598
private final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory;
9699

97100
private final PrintWriter out;
@@ -101,17 +104,20 @@ public class BlocksSubCommand implements Runnable {
101104
*
102105
* @param rlpBlockImporter the RLP block importer
103106
* @param jsonBlockImporterFactory the Json block importer factory
107+
* @param era1BlockImporter the era1 block importer supplier
104108
* @param rlpBlockExporterFactory the RLP block exporter factory
105109
* @param out Instance of PrintWriter where command usage will be written.
106110
*/
107111
public BlocksSubCommand(
108112
final Supplier<RlpBlockImporter> rlpBlockImporter,
109113
final Function<BesuController, JsonBlockImporter> jsonBlockImporterFactory,
114+
final Supplier<Era1BlockImporter> era1BlockImporter,
110115
final Function<Blockchain, RlpBlockExporter> rlpBlockExporterFactory,
111116
final PrintWriter out) {
112117
this.rlpBlockImporter = rlpBlockImporter;
113-
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
114118
this.jsonBlockImporterFactory = jsonBlockImporterFactory;
119+
this.era1BlockImporter = era1BlockImporter;
120+
this.rlpBlockExporterFactory = rlpBlockExporterFactory;
115121
this.out = out;
116122
}
117123

@@ -198,6 +204,7 @@ public void run() {
198204
checkCommand(parentCommand);
199205
checkNotNull(parentCommand.rlpBlockImporter);
200206
checkNotNull(parentCommand.jsonBlockImporterFactory);
207+
checkNotNull(parentCommand.era1BlockImporter);
201208
if (blockImportFiles.isEmpty()) {
202209
throw new ParameterException(spec.commandLine(), "No files specified to import.");
203210
}
@@ -214,12 +221,9 @@ public void run() {
214221
try {
215222
LOG.info("Importing from {}", path);
216223
switch (format) {
217-
case RLP:
218-
importRlpBlocks(controller, path);
219-
break;
220-
case JSON:
221-
importJsonBlocks(controller, path);
222-
break;
224+
case RLP -> importRlpBlocks(controller, path);
225+
case JSON -> importJsonBlocks(controller, path);
226+
case ERA1 -> importEra1Blocks(controller, path);
223227
}
224228
} catch (final FileNotFoundException e) {
225229
if (blockImportFiles.size() == 1) {
@@ -297,6 +301,14 @@ private void importRlpBlocks(final BesuController controller, final Path path)
297301
.get()
298302
.importBlockchain(path, controller, skipPow, startBlock, endBlock);
299303
}
304+
305+
private void importEra1Blocks(final BesuController controller, final Path path)
306+
throws IOException,
307+
java.util.concurrent.ExecutionException,
308+
InterruptedException,
309+
TimeoutException {
310+
parentCommand.era1BlockImporter.get().importBlocks(controller, path);
311+
}
300312
}
301313

302314
/**

besu/src/main/java/org/hyperledger/besu/components/BesuCommandModule.java

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.hyperledger.besu.Besu;
1818
import org.hyperledger.besu.RunnerBuilder;
1919
import org.hyperledger.besu.chainexport.RlpBlockExporter;
20+
import org.hyperledger.besu.chainimport.Era1BlockImporter;
2021
import org.hyperledger.besu.chainimport.JsonBlockImporter;
2122
import org.hyperledger.besu.chainimport.RlpBlockImporter;
2223
import org.hyperledger.besu.cli.BesuCommand;
@@ -50,6 +51,7 @@ BesuCommand provideBesuCommand(final @Named("besuCommandLogger") Logger commandL
5051
new BesuCommand(
5152
RlpBlockImporter::new,
5253
JsonBlockImporter::new,
54+
Era1BlockImporter::new,
5355
RlpBlockExporter::new,
5456
new RunnerBuilder(),
5557
new BesuController.Builder(),

0 commit comments

Comments
 (0)