/* * 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.sync; import org.ethereum.core.BlockHeader; import org.ethereum.core.BlockHeaderWrapper; import org.ethereum.core.BlockWrapper; import org.ethereum.datasource.DataSourceArray; import org.ethereum.db.DbFlushManager; import org.ethereum.db.IndexedBlockStore; import org.ethereum.net.server.Channel; import org.ethereum.net.server.ChannelManager; 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.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import java.util.List; /** * Created by Anton Nashatyrev on 27.10.2016. */ @Component @Lazy public class HeadersDownloader extends BlockDownloader { private final static Logger logger = LoggerFactory.getLogger("sync"); @Autowired SyncPool syncPool; @Autowired ChannelManager channelManager; @Autowired IndexedBlockStore blockStore; @Autowired @Qualifier("headerSource") DataSourceArray<BlockHeader> headerStore; @Autowired DbFlushManager dbFlushManager; byte[] genesisHash; int headersLoaded = 0; @Autowired public HeadersDownloader(BlockHeaderValidator headerValidator) { super(headerValidator); setHeaderQueueLimit(200000); setBlockBodiesDownload(false); logger.info("HeaderDownloader created."); } public void init(byte[] startFromBlockHash) { logger.info("HeaderDownloader init: startHash = " + Hex.toHexString(startFromBlockHash)); SyncQueueReverseImpl syncQueue = new SyncQueueReverseImpl(startFromBlockHash, true); super.init(syncQueue, syncPool); syncPool.init(channelManager); } @Override protected synchronized void pushBlocks(List<BlockWrapper> blockWrappers) {} @Override protected void pushHeaders(List<BlockHeaderWrapper> headers) { if (headers.get(headers.size() - 1).getNumber() == 0) { genesisHash = headers.get(headers.size() - 1).getHash(); } if (headers.get(headers.size() - 1).getNumber() == 1) { genesisHash = headers.get(headers.size() - 1).getHeader().getParentHash(); } logger.info(headers.size() + " headers loaded: " + headers.get(0).getNumber() + " - " + headers.get(headers.size() - 1).getNumber()); for (BlockHeaderWrapper header : headers) { headerStore.set((int) header.getNumber(), header.getHeader()); headersLoaded++; } dbFlushManager.commit(); } /** * Headers download could block chain synchronization occupying all peers * Prevents this by leaving one peer without work * Fallbacks to any peer when low number of active peers available */ @Override Channel getAnyPeer() { return syncPool.getActivePeersCount() > 2 ? syncPool.getNotLastIdle() : syncPool.getAnyIdle(); } @Override protected int getBlockQueueFreeSize() { return Integer.MAX_VALUE; } public int getHeadersLoaded() { return headersLoaded; } @Override protected void finishDownload() { stop(); } public byte[] getGenesisHash() { return genesisHash; } }