/* * Copyright (c) [2016] [ <ether.camp> ] * This file is part of the ethereumJ library. * * The ethereumJ library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * The ethereumJ library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the ethereumJ library. If not, see <http://www.gnu.org/licenses/>. */ package org.ethereum.manager; import org.ethereum.config.SystemProperties; import org.ethereum.core.*; import org.ethereum.db.DbFlushManager; import org.ethereum.util.*; import org.ethereum.validator.BlockHeaderValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.*; @Component public class BlockLoader { private static final Logger logger = LoggerFactory.getLogger("blockqueue"); @Autowired private BlockHeaderValidator headerValidator; @Autowired SystemProperties config; @Autowired private BlockchainImpl blockchain; @Autowired DbFlushManager dbFlushManager; Scanner scanner = null; DateFormat df = new SimpleDateFormat("HH:mm:ss.SSSS"); private void blockWork(Block block) { if (block.getNumber() >= blockchain.getBlockStore().getBestBlock().getNumber() || blockchain.getBlockStore().getBlockByHash(block.getHash()) == null) { if (block.getNumber() > 0 && !isValid(block.getHeader())) { throw new RuntimeException(); } long s = System.currentTimeMillis(); ImportResult result = blockchain.tryToConnect(block); if (block.getNumber() % 10 == 0) { System.out.println(df.format(new Date()) + " Imported block " + block.getShortDescr() + ": " + result + " (prework: " + exec1.getQueue().size() + ", work: " + exec2.getQueue().size() + ", blocks: " + exec1.getOrderMap().size() + ") in " + (System.currentTimeMillis() - s) + " ms"); } } else { if (block.getNumber() % 10000 == 0) System.out.println("Skipping block #" + block.getNumber()); } } ExecutorPipeline<Block, Block> exec1; ExecutorPipeline<Block, ?> exec2; public void loadBlocks() { exec1 = new ExecutorPipeline(8, 1000, true, new Functional.Function<Block, Block>() { @Override public Block apply(Block b) { if (b.getNumber() >= blockchain.getBlockStore().getBestBlock().getNumber()) { for (Transaction tx : b.getTransactionsList()) { tx.getSender(); } } return b; } }, new Functional.Consumer<Throwable>() { @Override public void accept(Throwable throwable) { logger.error("Unhandled exception: ", throwable); } }); exec2 = exec1.add(1, 1000, new Functional.Consumer<Block>() { @Override public void accept(Block block) { try { blockWork(block); } catch (Exception e) { e.printStackTrace(); } } }); String fileSrc = config.blocksLoader(); try { final String blocksFormat = config.getConfig().hasPath("blocks.format") ? config.getConfig().getString("blocks.format") : null; System.out.println("Loading blocks: " + fileSrc + ", format: " + blocksFormat); if ("rlp".equalsIgnoreCase(blocksFormat)) { // rlp encoded bytes Path path = Paths.get(fileSrc); // NOT OPTIMAL, but fine for tests byte[] data = Files.readAllBytes(path); RLPList list = RLP.decode2(data); for (RLPElement item : list) { Block block = new Block(item.getRLPData()); exec1.push(block); } } else { // hex string FileInputStream inputStream = new FileInputStream(fileSrc); scanner = new Scanner(inputStream, "UTF-8"); while (scanner.hasNextLine()) { byte[] blockRLPBytes = Hex.decode(scanner.nextLine()); Block block = new Block(blockRLPBytes); exec1.push(block); } } } catch (Exception e) { e.printStackTrace(); System.exit(1); } try { exec1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } dbFlushManager.flushSync(); System.out.println(" * Done * "); System.exit(0); } private boolean isValid(BlockHeader header) { return headerValidator.validateAndLog(header, logger); } }