/*
* 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;
}
}