From ff3e08375e228dcf1b2791bcfe87ed37e284669f Mon Sep 17 00:00:00 2001 From: Anton Nahsatyrev Date: Thu, 31 Dec 2015 18:19:59 +0300 Subject: [PATCH] Add uncles including (yet to be fixed). Synchronisation improvements. --- .../java/org/ethereum/mine/BlockMiner.java | 146 ++++++++++++------ 1 file changed, 97 insertions(+), 49 deletions(-) diff --git a/ethereumj-core/src/main/java/org/ethereum/mine/BlockMiner.java b/ethereumj-core/src/main/java/org/ethereum/mine/BlockMiner.java index 7a5016765b..f867edd1cb 100644 --- a/ethereumj-core/src/main/java/org/ethereum/mine/BlockMiner.java +++ b/ethereumj-core/src/main/java/org/ethereum/mine/BlockMiner.java @@ -5,6 +5,8 @@ import org.apache.commons.collections4.CollectionUtils; import org.ethereum.config.SystemProperties; import org.ethereum.core.*; +import org.ethereum.db.BlockStore; +import org.ethereum.db.IndexedBlockStore; import org.ethereum.facade.Ethereum; import org.ethereum.facade.EthereumImpl; import org.ethereum.listener.CompositeEthereumListener; @@ -20,6 +22,9 @@ import java.util.*; import java.util.concurrent.*; +import static org.ethereum.config.Constants.UNCLE_GENERATION_LIMIT; +import static org.ethereum.config.Constants.UNCLE_LIST_LIMIT; + /** * Created by Anton Nashatyrev on 10.12.2015. */ @@ -33,6 +38,9 @@ public class BlockMiner { @Autowired private Blockchain blockchain; + @Autowired + private IndexedBlockStore blockStore; + @Autowired private Ethereum ethereum; @@ -66,8 +74,8 @@ private void init() { fullMining = config.isMineFullDataset(); listener.addListener(new EthereumListenerAdapter() { @Override - public void onPendingTransactionsReceived(List transactions) { - BlockMiner.this.onPendingTransactionsReceived(transactions); + public void onPendingStateChanged(PendingState pendingState) { + BlockMiner.this.onPendingStateChanged(); } }); } @@ -84,7 +92,7 @@ public void startMining() { isMining = true; fireMinerStarted(); logger.info("Miner started"); - restartMining(Collections.emptyList()); + restartMining(); } public void stopMining() { @@ -95,7 +103,8 @@ public void stopMining() { } protected List getAllPendingTransactions() { - List ret = new ArrayList<>(); +// List ret = new ArrayList<>(); + PendingStateImpl.TransactionSortedSet ret = new PendingStateImpl.TransactionSortedSet(); ret.addAll(pendingState.getPendingTransactions()); ret.addAll(pendingState.getWireTransactions()); Iterator it = ret.iterator(); @@ -106,25 +115,29 @@ protected List getAllPendingTransactions() { it.remove(); } } - return ret; + return new ArrayList<>(ret); } -// @Override -// public void onBlock(Block block, List receipts) { -// List curPendingTxs = getAllPendingTransactions(); -// if (!CollectionUtils.isEqualCollection(miningPendingTxs, curPendingTxs)) { -// restartMining(curPendingTxs); -// } -// } - - public void onPendingTransactionsReceived(List transactions) { + private void onPendingStateChanged() { if (!isMining) return; - logger.debug("Miner received new pending txs"); - List curPendingTxs = getAllPendingTransactions(); - if (miningBlock == null || transactions.isEmpty() || - !CollectionUtils.isEqualCollection(miningBlock.getTransactionsList(), curPendingTxs)) { - restartMining(curPendingTxs); + logger.debug("onPendingStateChanged()"); + if (miningBlock == null) { + restartMining(); + } else if (miningBlock.getNumber() <= ((PendingStateImpl) pendingState).getBestBlock().getNumber()) { + logger.debug("Restart mining: new best block: " + blockchain.getBestBlock().getShortDescr()); + restartMining(); + } else if (!CollectionUtils.isEqualCollection(miningBlock.getTransactionsList(), getAllPendingTransactions())) { + logger.debug("Restart mining: pending transactions changed"); + restartMining(); + } else { + if (logger.isDebugEnabled()) { + String s = "onPendingStateChanged() event, but pending Txs the same as in currently mining block: "; + for (Transaction tx : getAllPendingTransactions()) { + s += "\n " + tx; + } + logger.debug(s); + } } } @@ -132,37 +145,74 @@ protected boolean isAcceptableTx(Transaction tx) { return minGasPrice.compareTo(new BigInteger(1, tx.getGasPrice())) <= 0; } - protected void cancelCurrentBlock() { + protected synchronized void cancelCurrentBlock() { if (ethashTask != null && !ethashTask.isCancelled()) { ethashTask.cancel(true); fireBlockCancelled(miningBlock); - logger.debug("Tainted block mining cancelled: {}", miningBlock.getShortHash()); + logger.debug("Tainted block mining cancelled: {}", miningBlock.getShortDescr()); + ethashTask = null; + miningBlock = null; } } - protected void restartMining(List txs) { - cancelCurrentBlock(); - miningBlock = blockchain.createNewBlock(blockchain.getBestBlock(), txs); - ethashTask = fullMining ? - Ethash.getForBlock(miningBlock.getNumber()).mine(miningBlock, cpuThreads) : - Ethash.getForBlock(miningBlock.getNumber()).mineLight(miningBlock, cpuThreads) - ; - fireBlockStarted(miningBlock); - logger.debug("New block mining started: {}", miningBlock.getShortHash()); - ethashTask.addListener(new Runnable() { - @Override - public void run() { - try { - ethashTask.get(); - // wow, block mined! - blockMined(miningBlock); - } catch (InterruptedException | CancellationException e) { - // OK, we've been cancelled, just exit - } catch (Exception e) { - logger.warn("Exception during mining: ", e); + protected List getUncles(Block best) { + List ret = new ArrayList<>(); + long miningNum = best.getNumber() + 1; + long uncleNum = miningNum - 1; + + outer: + while(uncleNum > miningNum - UNCLE_GENERATION_LIMIT) { + List genBlocks = blockStore.getBlocksByNumber(uncleNum); + if (genBlocks.size() > 1) { + Block mainBlock = blockStore.getChainBlockByNumber(uncleNum); + for (Block uncleCandidate : genBlocks) { + if (!uncleCandidate.isEqual(mainBlock)) { + ret.add(uncleCandidate.getHeader()); + if (ret.size() > UNCLE_LIST_LIMIT) { + break outer; + } + } } } - }, MoreExecutors.sameThreadExecutor()); + uncleNum--; + } + return ret; + } + + protected void restartMining() { + Block bestBlockchain = blockchain.getBestBlock(); + Block bestPendingState = ((PendingStateImpl) pendingState).getBestBlock(); + + logger.debug("Best blocks: PendingState: " + bestPendingState.getShortDescr() + + ", Blockchain: " + bestBlockchain.getShortDescr()); + + Block newMiningBlock = blockchain.createNewBlock(bestPendingState, getAllPendingTransactions(), + getUncles(bestPendingState)); + + synchronized(this) { + cancelCurrentBlock(); + miningBlock = newMiningBlock; + ethashTask = fullMining ? + Ethash.getForBlock(miningBlock.getNumber()).mine(miningBlock, cpuThreads) : + Ethash.getForBlock(miningBlock.getNumber()).mineLight(miningBlock, cpuThreads); + ethashTask.addListener(new Runnable() { + // private final Future task = ethashTask; + @Override + public void run() { + try { + ethashTask.get(); + // wow, block mined! + blockMined(miningBlock); + } catch (InterruptedException | CancellationException e) { + // OK, we've been cancelled, just exit + } catch (Exception e) { + logger.warn("Exception during mining: ", e); + } + } + }, MoreExecutors.sameThreadExecutor()); + } + fireBlockStarted(miningBlock); + logger.debug("New block mining started: {}", miningBlock.getShortHash()); } protected void blockMined(Block newBlock) throws InterruptedException { @@ -186,8 +236,6 @@ protected void blockMined(Block newBlock) throws InterruptedException { logger.debug("Importing newly mined block " + newBlock.getShortHash() + " ..."); ImportResult importResult = ((EthereumImpl) ethereum).addNewMinedBlock(newBlock); logger.debug("Mined block import result is " + importResult + " : " + newBlock.getShortHash()); - -// restartMining(Collections.emptyList()); } /***** Listener boilerplate ******/ @@ -200,27 +248,27 @@ public void removeListener(MinerListener l) { listeners.remove(l); } - public void fireMinerStarted() { + protected void fireMinerStarted() { for (MinerListener l : listeners) { l.miningStarted(); } } - public void fireMinerStopped() { + protected void fireMinerStopped() { for (MinerListener l : listeners) { l.miningStopped(); } } - public void fireBlockStarted(Block b) { + protected void fireBlockStarted(Block b) { for (MinerListener l : listeners) { l.blockMiningStarted(b); } } - public void fireBlockCancelled(Block b) { + protected void fireBlockCancelled(Block b) { for (MinerListener l : listeners) { l.blockMiningCanceled(b); } } - public void fireBlockMined(Block b) { + protected void fireBlockMined(Block b) { for (MinerListener l : listeners) { l.blockMined(b); }