diff --git a/core/src/main/java/org/bitcoinj/core/Context.java b/core/src/main/java/org/bitcoinj/core/Context.java index b39c8df13..786e28a36 100644 --- a/core/src/main/java/org/bitcoinj/core/Context.java +++ b/core/src/main/java/org/bitcoinj/core/Context.java @@ -284,7 +284,8 @@ public void initDash(boolean liteMode, boolean allowInstantX, @Nullable EnumSet< public void setMasternodeListManager(SimplifiedMasternodeListManager masternodeListManager) { this.masternodeListManager = masternodeListManager; - masternodeListManager.setBlockChain(blockChain, headerChain, peerGroup, quorumManager, quorumSnapshotManager, chainLockHandler); + DualBlockChain dualBlockChain = new DualBlockChain(headerChain, blockChain); + masternodeListManager.setBlockChain(dualBlockChain, peerGroup, quorumManager, quorumSnapshotManager, chainLockHandler); } public void closeDash() { @@ -399,6 +400,7 @@ public void setPeerGroupAndBlockChain(PeerGroup peerGroup, AbstractBlockChain bl this.peerGroup = peerGroup; this.blockChain = blockChain; this.headerChain = headerChain; + DualBlockChain dualBlockChain = new DualBlockChain(headerChain, blockChain); hashStore = new HashStore(blockChain.getBlockStore()); blockChain.addNewBestBlockListener(newBestBlockListener); handleActivations(blockChain.getChainHead()); @@ -406,8 +408,7 @@ public void setPeerGroupAndBlockChain(PeerGroup peerGroup, AbstractBlockChain bl sporkManager.setBlockChain(blockChain, peerGroup); masternodeSync.setBlockChain(blockChain, netFullfilledRequestManager); masternodeListManager.setBlockChain( - blockChain, - peerGroup != null ? peerGroup.headerChain : null, + dualBlockChain, peerGroup, quorumManager, quorumSnapshotManager, diff --git a/core/src/main/java/org/bitcoinj/core/DualBlockChain.java b/core/src/main/java/org/bitcoinj/core/DualBlockChain.java new file mode 100644 index 000000000..708109f40 --- /dev/null +++ b/core/src/main/java/org/bitcoinj/core/DualBlockChain.java @@ -0,0 +1,105 @@ +/* + * Copyright 2023 Dash Core Group + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.bitcoinj.core; + +import org.bitcoinj.store.BlockStoreException; + +import javax.annotation.Nullable; + +import static java.lang.Math.max; + +/** + * Manages a header chain and the regular blockchain + */ +public class DualBlockChain { + private final @Nullable AbstractBlockChain headersChain; + private final AbstractBlockChain blockChain; + + public DualBlockChain(@Nullable AbstractBlockChain headersChain, AbstractBlockChain blockChain) { + this.headersChain = headersChain; + this.blockChain = blockChain; + } + + public AbstractBlockChain getBlockChain() { + return blockChain; + } + + public AbstractBlockChain getHeadersChain() { + return headersChain; + } + + + public int getBlockHeight(Sha256Hash blockHash) { + try { + if (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight()) { + return headersChain.getBlockStore().get(blockHash).getHeight(); + } else return blockChain.getBlockStore().get(blockHash).getHeight(); + } catch (BlockStoreException x) { + return -1; + } + } + + public int getBestChainHeight() { + int height = blockChain.getBestChainHeight(); + if (headersChain != null) + height = max(headersChain.getBestChainHeight(), blockChain.getBestChainHeight()); + return height; + } + + public StoredBlock getBlock(Sha256Hash blockHash) { + try { + StoredBlock block = blockChain.getBlockStore().get(blockHash); + if (block == null && headersChain != null) { + block = headersChain.getBlockStore().get(blockHash); + } + return block; + } catch (BlockStoreException e) { + throw new RuntimeException(e); + } + } + + public StoredBlock getBlockAncestor(StoredBlock block, int height) { + try { + StoredBlock ancestor = block.getAncestor(blockChain.getBlockStore(), height); + if (ancestor == null && headersChain != null) { + ancestor = block.getAncestor(headersChain.getBlockStore(), height); + } + return ancestor; + } catch (BlockStoreException e) { + throw new RuntimeException(e); + } + } + + public StoredBlock getBlock(int height) { + try { + StoredBlock block = blockChain.getBlockStore().get(height); + if (block == null && headersChain != null) { + block = headersChain.getBlockStore().get(height); + } + return block; + } catch (BlockStoreException e) { + throw new RuntimeException(e); + } + } + + public StoredBlock getChainHead() { + StoredBlock bestBlock = blockChain.getChainHead(); + if (headersChain != null && headersChain.getBestChainHeight() > bestBlock.getHeight()) + bestBlock = headersChain.getChainHead(); + return bestBlock; + } +} diff --git a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumRequest.java b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumRequest.java index 93d25b6c7..6947d583d 100644 --- a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumRequest.java +++ b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumRequest.java @@ -16,14 +16,14 @@ package org.bitcoinj.evolution; -import org.bitcoinj.core.AbstractBlockChain; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.Message; import org.bitcoinj.core.NetworkParameters; /** * The abstract base class for messages that are for requesting masternode list and quorum list updates * - * This class requires that subclasses implement {@link #toString(AbstractBlockChain)} + * This class requires that subclasses implement {@link #toString(DualBlockChain)} */ public abstract class AbstractQuorumRequest extends Message { @@ -45,5 +45,5 @@ public AbstractQuorumRequest(NetworkParameters params, byte [] payload, int offs * @param blockChain the blockChain that will convert block hashes to heights * @return the string representation of this object with block heights next to all block hashes */ - public abstract String toString(AbstractBlockChain blockChain); + public abstract String toString(DualBlockChain blockChain); } diff --git a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java index 598532bff..88bbd4cf5 100644 --- a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java +++ b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java @@ -22,6 +22,7 @@ import org.bitcoinj.core.AbstractBlockChain; import org.bitcoinj.core.BlockQueue; import org.bitcoinj.core.Context; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.MasternodeSync; import org.bitcoinj.core.Message; import org.bitcoinj.core.NetworkParameters; @@ -88,11 +89,10 @@ public abstract class AbstractQuorumState lastRequest; @@ -165,13 +165,8 @@ public void setBootstrap(String bootstrapFilePath, InputStream bootstrapStream, } // TODO: Do we need to keep track of the header chain also? - public void setBlockChain(PeerGroup peerGroup, AbstractBlockChain headerChain, AbstractBlockChain blockChain) { + public void setBlockChain(PeerGroup peerGroup, DualBlockChain blockChain) { this.blockChain = blockChain; - this.headerChain = headerChain; - blockStore = blockChain.getBlockStore(); - if (headerChain != null) { - headerStore = headerChain.getBlockStore(); - } if (peerGroup != null) { this.peerGroup = peerGroup; peerGroup.addMnListDownloadCompleteListener(() -> initChainTipSyncComplete = true, Threading.SAME_THREAD); @@ -211,7 +206,7 @@ public boolean reachedMaxFailedAttempts() { abstract boolean needsUpdate(StoredBlock nextBlock); public abstract void processDiff(@Nullable Peer peer, DiffMessage difference, - AbstractBlockChain headersChain, AbstractBlockChain blockChain, + DualBlockChain blockChain, boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException; @@ -288,7 +283,7 @@ protected void requestAfterMNListReset() throws BlockStoreException { } else { height = currentHeight; } - StoredBlock resetBlock = blockChain.getBlockStore().get(height); + StoredBlock resetBlock = blockChain.getBlock(height); if (resetBlock == null) resetBlock = blockChain.getChainHead(); requestMNListDiff(resetBlock != null ? resetBlock : blockChain.getChainHead()); @@ -352,6 +347,7 @@ void requestNextMNListDiff() { //fill up the pending list with recent blocks if (syncOptions != MasternodeListSyncOptions.SYNC_MINIMUM) { + // TODO: update based on headers first sync Sha256Hash tipHash = blockChain.getChainHead().getHeader().getHash(); ArrayList blocksToAdd = new ArrayList<>(); if (!getMasternodeListCache().containsKey(tipHash) && !pendingBlocks.contains(blockChain.getChainHead())) { @@ -361,7 +357,7 @@ void requestNextMNListDiff() { blocksToAdd.add(0, cursor); } else break; try { - cursor = cursor.getPrev(blockChain.getBlockStore()); + cursor = cursor.getPrev(blockChain.getBlockChain().getBlockStore()); } catch (BlockStoreException x) { break; } @@ -479,16 +475,13 @@ void maybeGetMNListDiffFresh() { } StoredBlock endBlock = blockChain.getChainHead(); - try { - if (syncOptions == MasternodeListSyncOptions.SYNC_MINIMUM) - endBlock = blockChain.getBlockStore().get(endBlock.getHeight() - SigningManager.SIGN_HEIGHT_OFFSET); - if (getMasternodeListCache().containsKey(endBlock.getHeader().getHash())) - endBlock = blockChain.getBlockStore().get((int) getMasternodeListAtTip().getHeight() + 1); - if (endBlock == null) - endBlock = blockChain.getChainHead(); - } catch (BlockStoreException x) { - throw new RuntimeException(x); - } + + if (syncOptions == MasternodeListSyncOptions.SYNC_MINIMUM) + endBlock = blockChain.getBlock(endBlock.getHeight() - SigningManager.SIGN_HEIGHT_OFFSET); + if (getMasternodeListCache().containsKey(endBlock.getHeader().getHash())) + endBlock = blockChain.getBlock((int) getMasternodeListAtTip().getHeight() + 1); + if (endBlock == null) + endBlock = blockChain.getChainHead(); requestUpdate(downloadPeer, endBlock); waitingForMNListDiff = true; @@ -508,12 +501,13 @@ public boolean isSynced() { protected void fillPendingBlocksList(Sha256Hash first, Sha256Hash last) { lock.lock(); try { - StoredBlock cursor = blockChain.getBlockStore().get(last); + // TODO: update to use DualBlockchain? + StoredBlock cursor = blockChain.getBlockChain().getBlockStore().get(last); while (cursor != null && !cursor.getHeader().getHash().equals(first)) { if (!pendingBlocks.contains(cursor)) { pendingBlocks.add(cursor); } - cursor = cursor.getPrev(blockChain.getBlockStore()); + cursor = cursor.getPrev(blockChain.getBlockChain().getBlockStore()); } } catch (BlockStoreException x) { throw new RuntimeException(x); @@ -535,7 +529,6 @@ public boolean isDeterministicMNsSporkActive() { } public void addEventListeners(AbstractBlockChain blockChain, PeerGroup peerGroup) { - this.blockChain = blockChain; blockChain.addNewBestBlockListener(Threading.SAME_THREAD, newBestBlockListener); blockChain.addReorganizeListener(reorganizeListener); if (peerGroup != null) { @@ -569,14 +562,12 @@ public void notifyNewBestBlock(StoredBlock block) throws VerificationException { if (Utils.currentTimeSeconds() - block.getHeader().getTimeSeconds() < timePeriod) { if (syncOptions == MasternodeListSyncOptions.SYNC_MINIMUM) { try { - StoredBlock requestBlock = getBlockHeightOffset() > 0 ? blockChain.getBlockStore().get(block.getHeight() - getBlockHeightOffset()) : block; + StoredBlock requestBlock = getBlockHeightOffset() > 0 ? blockChain.getBlock(block.getHeight() - getBlockHeightOffset()) : block; if (getMasternodeListAtTip().getHeight() > requestBlock.getHeight()) - requestBlock = blockChain.getBlockStore().get((int) getMasternodeListAtTip().getHeight() + 1); + requestBlock = blockChain.getBlock((int) getMasternodeListAtTip().getHeight() + 1); if (requestBlock != null) { block = requestBlock; } - } catch (BlockStoreException x) { - throw new RuntimeException(x); } catch (NullPointerException x) { log.info("null pointer exception", x); } @@ -699,15 +690,11 @@ public void onFirstSaveComplete() { long timePeriod = syncOptions == MasternodeListSyncOptions.SYNC_SNAPSHOT_PERIOD ? SNAPSHOT_TIME_PERIOD : MAX_CACHE_SIZE * 3 * 60L; if (Utils.currentTimeSeconds() - block.getHeader().getTimeSeconds() < timePeriod) { if (syncOptions == MasternodeListSyncOptions.SYNC_MINIMUM) { - try { - StoredBlock requestBlock = blockChain.getBlockStore().get(block.getHeight() - getBlockHeightOffset()); - if (getMasternodeListAtTip().getHeight() > requestBlock.getHeight()) - requestBlock = blockChain.getBlockStore().get((int) getMasternodeListAtTip().getHeight() + 1); - if (requestBlock != null) { - block = requestBlock; - } - } catch (BlockStoreException x) { - //do nothing + StoredBlock requestBlock = blockChain.getBlock(block.getHeight() - getBlockHeightOffset()); + if (getMasternodeListAtTip().getHeight() > requestBlock.getHeight()) + requestBlock = blockChain.getBlock((int) getMasternodeListAtTip().getHeight() + 1); + if (requestBlock != null) { + block = requestBlock; } } requestMNListDiff(block); @@ -837,30 +824,6 @@ else if (bootstrapFilePath != null) { } } - protected StoredBlock getBlockFromHash(Sha256Hash blockHash) { - try { - StoredBlock block = blockChain.getBlockStore().get(blockHash); - if (block == null) { - block = headerChain.getBlockStore().get(blockHash); - } - return block; - } catch (BlockStoreException e) { - throw new RuntimeException(e); - } - } - - protected StoredBlock getBlockAncestor(StoredBlock block, int height) { - try { - StoredBlock ancestor = block.getAncestor(blockStore, height); - if (ancestor == null) { - ancestor = block.getAncestor(headerStore, height); - } - return ancestor; - } catch (BlockStoreException e) { - throw new RuntimeException(e); - } - } - BLSSignature getCoinbaseChainlock(StoredBlock block) { ChainLockSignature clsig = chainLocksHandler.getCoinbaseChainLock(block.getHeader().getHash()); if (clsig != null) @@ -870,7 +833,7 @@ BLSSignature getCoinbaseChainlock(StoredBlock block) { // DIP29 Random Beacon for LLMQ selection is activated with v20 Sha256Hash getHashModifier(LLMQParameters llmqParams, StoredBlock quorumBaseBlock) { - StoredBlock workBlock = getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 8); + StoredBlock workBlock = blockChain.getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 8); if (params.isV20Active(workBlock.getHeight())) { // v20 is active: calculate modifier using the new way. diff --git a/core/src/main/java/org/bitcoinj/evolution/GetSimplifiedMasternodeListDiff.java b/core/src/main/java/org/bitcoinj/evolution/GetSimplifiedMasternodeListDiff.java index c4c44d507..4951e4828 100644 --- a/core/src/main/java/org/bitcoinj/evolution/GetSimplifiedMasternodeListDiff.java +++ b/core/src/main/java/org/bitcoinj/evolution/GetSimplifiedMasternodeListDiff.java @@ -1,10 +1,9 @@ package org.bitcoinj.evolution; -import org.bitcoinj.core.AbstractBlockChain; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.ProtocolException; import org.bitcoinj.core.Sha256Hash; -import org.bitcoinj.store.BlockStoreException; import java.io.IOException; import java.io.OutputStream; @@ -64,14 +63,12 @@ public String toString() { } @Override - public String toString(AbstractBlockChain blockChain) { + public String toString(DualBlockChain blockChain) { int baseHeight = -1; int blockHeight = -1; try { - baseHeight = blockChain.getBlockStore().get(baseBlockHash).getHeight(); - blockHeight = blockChain.getBlockStore().get(blockHash).getHeight(); - } catch (BlockStoreException x) { - throw new RuntimeException(x); + baseHeight = blockChain.getBlock(baseBlockHash).getHeight(); + blockHeight = blockChain.getBlock(blockHash).getHeight(); } catch (NullPointerException x) { // swallow } diff --git a/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java b/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java index f5a93c891..98a23db1a 100644 --- a/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java +++ b/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java @@ -158,7 +158,7 @@ public QuorumRotationState(Context context, byte[] payload, int offset, int prot finishInitialization(); } - public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockChain blockChain, + public void applyDiff(Peer peer, DualBlockChain blockChain, QuorumRotationInfo quorumRotationInfo, boolean isLoadingBootStrap) throws BlockStoreException, MasternodeListDiffException { StoredBlock blockAtTip; @@ -172,24 +172,24 @@ public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockC peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Received, quorumRotationInfo.getMnListDiffTip()); boolean isSyncingHeadersFirst = context.peerGroup != null && context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST; - AbstractBlockChain chain = isSyncingHeadersFirst ? headersChain : blockChain; + //AbstractBlockChain chain = isSyncingHeadersFirst ? headersChain : blockChain; // in the event that we don't know that DIP24 is active, then isSyncingHeadersFirst is false //if (chain.getBestChainHeight() <= 1 || (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight())) { - chain = (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight()) ? headersChain : blockChain; + //chain = (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight()) ? headersChain : blockChain; //} log.info("processing {} qrinfo between (atH): {} & {}; {}", isLoadingBootStrap ? "bootstrap" : "requested", - mnListAtH.getHeight(), newHeight, quorumRotationInfo.toString(chain)); + mnListAtH.getHeight(), newHeight, quorumRotationInfo.toString(blockChain)); - blockAtTip = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffTip().blockHash); - blockAtH = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtH().blockHash); - blockMinusC = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtHMinusC().blockHash); - blockMinus2C = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtHMinus2C().blockHash); - blockMinus3C = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtHMinus3C().blockHash); + blockAtTip = blockChain.getBlock(quorumRotationInfo.getMnListDiffTip().blockHash); + blockAtH = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtH().blockHash); + blockMinusC = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtHMinusC().blockHash); + blockMinus2C = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtHMinus2C().blockHash); + blockMinus3C = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtHMinus3C().blockHash); if (quorumRotationInfo.hasExtraShare()) { - blockMinus4C = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtHMinus4C().blockHash); + blockMinus4C = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtHMinus4C().blockHash); } // TODO: this may not be needed @@ -227,12 +227,12 @@ public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockC baseMNList = mnListsCache.get(quorumRotationInfo.getMnListDiffAtHMinusC().prevBlockHash); if (baseMNList == null) throw new MasternodeListDiffException("does not connect to previous lists", true, false, false, false); - StoredBlock prevBlockHMinusC = chain.getBlockStore().get(quorumRotationInfo.getMnListDiffAtHMinusC().prevBlockHash); + StoredBlock prevBlockHMinusC = blockChain.getBlock(quorumRotationInfo.getMnListDiffAtHMinusC().prevBlockHash); if (baseMNList == null) { log.info("mnList missing for " + quorumRotationInfo.getMnListDiffAtHMinusC().prevBlockHash + " " + (prevBlockHMinusC != null ? prevBlockHMinusC.getHeight() : -1)); for (Sha256Hash hash : mnListsCache.keySet()) { - StoredBlock block = chain.getBlockStore().get(hash); + StoredBlock block = blockChain.getBlock(hash); log.info("--> {}: {}: {}", hash, block == null ? -1 : block.getHeight(), mnListsCache.get(hash).getBlockHash()); } } @@ -316,20 +316,20 @@ public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockC if (quorumRotationInfo.hasExtraShare()) { baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus4C().prevBlockHash); - newQuorumListAtHMinus4C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus4C(), isLoadingBootStrap, chain, true, false); + newQuorumListAtHMinus4C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus4C(), isLoadingBootStrap, blockChain, true, false); } baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus3C().prevBlockHash); - SimplifiedQuorumList newQuorumListAtHMinus3C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus3C(), isLoadingBootStrap, chain, true, false); + SimplifiedQuorumList newQuorumListAtHMinus3C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus3C(), isLoadingBootStrap, blockChain, true, false); baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus2C().prevBlockHash); - SimplifiedQuorumList newQuorumListAtHMinus2C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus2C(), isLoadingBootStrap, chain, true, false); + SimplifiedQuorumList newQuorumListAtHMinus2C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus2C(), isLoadingBootStrap, blockChain, true, false); baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinusC().prevBlockHash); - SimplifiedQuorumList newQuorumListAtHMinusC = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinusC(), isLoadingBootStrap, chain, true, false); + SimplifiedQuorumList newQuorumListAtHMinusC = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinusC(), isLoadingBootStrap, blockChain, true, false); baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtH().prevBlockHash); - SimplifiedQuorumList newQuorumListAtH = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtH(), isLoadingBootStrap, chain, true, false); + SimplifiedQuorumList newQuorumListAtH = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtH(), isLoadingBootStrap, blockChain, true, false); if (context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM)) { // verify the merkle root of the quorums at H @@ -376,8 +376,8 @@ public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockC } } if (!hasList) { - newList.setBlock(blockAtH != null ? blockAtH : chain.getChainHead()); - newList.verifyQuorums(isLoadingBootStrap, chain, true); + newList.setBlock(blockAtH != null ? blockAtH : blockChain.getChainHead()); + newList.verifyQuorums(isLoadingBootStrap, blockChain, true); activeQuorumLists.put((int) newList.getHeight(), newList); } log.info("activeQuorumLists: {}", activeQuorumLists.size()); @@ -407,41 +407,35 @@ public void requestUpdate(Peer peer, StoredBlock nextBlock) { } public GetQuorumRotationInfo getQuorumRotationInfoRequest(StoredBlock nextBlock) { - try { - // int requestHeight = nextBlock.getHeight() - nextBlock.getHeight() % getUpdateInterval(); - LLMQParameters llmqParameters = params.getLlmqs().get(llmqType); - int requestHeight = nextBlock.getHeight() % getUpdateInterval() < llmqParameters.getDkgMiningWindowEnd() ? //(11 + LLMQParameters.fromType(llmqType).getSigningActiveQuorumCount() + SigningManager.SIGN_HEIGHT_OFFSET) ? - nextBlock.getHeight() - nextBlock.getHeight() % getUpdateInterval() : nextBlock.getHeight(); - // TODO: only do this on an empty list - obsolete - //if (mnListAtH.getBlockHash().equals(params.getGenesisBlock().getHash()) /*!initChainTipSyncComplete*/) { - // requestHeight = requestHeight - 3 * (nextBlock.getHeight() % getUpdateInterval()); - //} - // if nextBlock is a rotation block, then use it since it won't be in the blockStore - StoredBlock requestBlock = requestHeight == nextBlock.getHeight() ? - nextBlock : - blockStore.get(requestHeight); - - if (requestBlock == null) { - requestBlock = headerChain.getBlockStore().get(requestHeight); - } - log.info("requesting next qrinfo {} -> {}", nextBlock.getHeight(), requestHeight); - - HashSet set = Sets.newHashSet( - requestBlock.getHeader().getPrevBlockHash(), - mnListAtH.getBlockHash(), - mnListAtHMinusC.getBlockHash(), - mnListAtHMinus2C.getBlockHash(), - mnListAtHMinus3C.getBlockHash() - ); - if (mnListAtHMinus4C != null) { - set.add(mnListAtHMinus4C.getBlockHash()); - } - ArrayList baseBlockHashes = Lists.newArrayList(set); - return new GetQuorumRotationInfo(context.getParams(), baseBlockHashes, requestBlock.getHeader().getHash(), true); - } catch (BlockStoreException x) { - throw new RuntimeException(x); + // int requestHeight = nextBlock.getHeight() - nextBlock.getHeight() % getUpdateInterval(); + LLMQParameters llmqParameters = params.getLlmqs().get(llmqType); + int requestHeight = nextBlock.getHeight() % getUpdateInterval() < llmqParameters.getDkgMiningWindowEnd() ? //(11 + LLMQParameters.fromType(llmqType).getSigningActiveQuorumCount() + SigningManager.SIGN_HEIGHT_OFFSET) ? + nextBlock.getHeight() - nextBlock.getHeight() % getUpdateInterval() : nextBlock.getHeight(); + // TODO: only do this on an empty list - obsolete + //if (mnListAtH.getBlockHash().equals(params.getGenesisBlock().getHash()) /*!initChainTipSyncComplete*/) { + // requestHeight = requestHeight - 3 * (nextBlock.getHeight() % getUpdateInterval()); + //} + // if nextBlock is a rotation block, then use it since it won't be in the blockStore + StoredBlock requestBlock = requestHeight == nextBlock.getHeight() ? + nextBlock : + blockChain.getBlock(requestHeight); + + log.info("requesting next qrinfo {} -> {}", nextBlock.getHeight(), requestHeight); + + HashSet set = Sets.newHashSet( + requestBlock.getHeader().getPrevBlockHash(), + mnListAtH.getBlockHash(), + mnListAtHMinusC.getBlockHash(), + mnListAtHMinus2C.getBlockHash(), + mnListAtHMinus3C.getBlockHash() + ); + if (mnListAtHMinus4C != null) { + set.add(mnListAtHMinus4C.getBlockHash()); } + ArrayList baseBlockHashes = Lists.newArrayList(set); + + return new GetQuorumRotationInfo(context.getParams(), baseBlockHashes, requestBlock.getHeader().getHash(), true); } @Override @@ -505,11 +499,8 @@ public ArrayList getAllQuorumMembers(LLMQParameters.LLMQType llmqTyp return quorumMembers; } - StoredBlock quorumBaseBlock = blockChain.getBlockStore().get(blockHash); - // TODO: There needs to be a better way to do this instead of checking each time - if (quorumBaseBlock == null && headerChain != null) { - quorumBaseBlock = headerChain.getBlockStore().get(blockHash); - } + StoredBlock quorumBaseBlock = blockChain.getBlock(blockHash); + if (mapIndexedQuorumMembers.isEmpty()) { initIndexedQuorumsCache(mapIndexedQuorumMembers); } @@ -525,10 +516,7 @@ public ArrayList getAllQuorumMembers(LLMQParameters.LLMQType llmqTyp int quorumIndex = quorumBaseBlock.getHeight() % LLMQParameters.fromType(llmqType).getDkgInterval(); int cycleQuorumBaseHeight = quorumBaseBlock.getHeight() - quorumIndex; - StoredBlock cycleQuorumBaseBlock = blockChain.getBlockStore().get(cycleQuorumBaseHeight); - if (cycleQuorumBaseBlock == null && headerChain != null) { - cycleQuorumBaseBlock = headerChain.getBlockStore().get(cycleQuorumBaseHeight); - } + StoredBlock cycleQuorumBaseBlock = blockChain.getBlock(cycleQuorumBaseHeight); /* * Since mapQuorumMembers stores Quorum members per block hash, and we don't know yet the block hashes of blocks for all quorumIndexes (since these blocks are not created yet) @@ -578,10 +566,9 @@ private ArrayList> computeQuorumMembersByQuarterRotation(L final int cycleLength = llmqParameters.getDkgInterval(); - final BlockStore store = headerStore != null && headerStore.getChainHead().getHeight() > blockStore.getChainHead().getHeight() ? headerStore : blockStore; - final StoredBlock blockHMinusC = quorumBaseBlock.getAncestor(store, quorumBaseBlock.getHeight() - cycleLength); - final StoredBlock pBlockHMinus2C = quorumBaseBlock.getAncestor(store, quorumBaseBlock.getHeight() - 2 * cycleLength); - final StoredBlock pBlockHMinus3C = quorumBaseBlock.getAncestor(store, quorumBaseBlock.getHeight() - 3 * cycleLength); + final StoredBlock blockHMinusC = blockChain.getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - cycleLength); + final StoredBlock pBlockHMinus2C = blockChain.getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 2 * cycleLength); + final StoredBlock pBlockHMinus3C = blockChain.getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 3 * cycleLength); log.info("computeQuorumMembersByQuarterRotation llmqType[{}] nHeight[{}]", llmqType, quorumBaseBlock.getHeight()); @@ -693,125 +680,121 @@ private static ArrayList> createNewQuar } private ArrayList> buildNewQuorumQuarterMembers(LLMQParameters llmqParameters, StoredBlock cycleQuorumBaseBlock, PreviousQuorumQuarters previousQuarters) { - try { - ArrayList> quarterQuorumMembers = createNewQuarterQuorumMembers(llmqParameters); - int quorumSize = llmqParameters.getSize(); - int quarterSize = quorumSize / 4; - // - 8 - final BlockStore store = headerStore != null && headerStore.getChainHead().getHeight() > blockStore.getChainHead().getHeight() ? headerStore : blockStore; - final StoredBlock workBlock = cycleQuorumBaseBlock.getAncestor(store, cycleQuorumBaseBlock.getHeight() - 8); - final Sha256Hash modifier = getHashModifier(llmqParameters, cycleQuorumBaseBlock); - SimplifiedMasternodeList allMns = getListForBlock(workBlock.getHeader().getHash()); - if (allMns.getAllMNsCount() < quarterSize) - return quarterQuorumMembers; + ArrayList> quarterQuorumMembers = createNewQuarterQuorumMembers(llmqParameters); + int quorumSize = llmqParameters.getSize(); + int quarterSize = quorumSize / 4; - SimplifiedMasternodeList MnsUsedAtH = new SimplifiedMasternodeList(params); - SimplifiedMasternodeList MnsNotUsedAtH = new SimplifiedMasternodeList(params); - ArrayList MnsUsedAtHIndex = Lists.newArrayListWithCapacity(llmqParameters.getSigningActiveQuorumCount()); + // - 8 + final StoredBlock workBlock = blockChain.getBlockAncestor(cycleQuorumBaseBlock, cycleQuorumBaseBlock.getHeight() - 8); + final Sha256Hash modifier = getHashModifier(llmqParameters, cycleQuorumBaseBlock); + SimplifiedMasternodeList allMns = getListForBlock(workBlock.getHeader().getHash()); + if (allMns.getAllMNsCount() < quarterSize) + return quarterQuorumMembers; - boolean skipRemovedMNs = params.isV19Active(cycleQuorumBaseBlock) || params.getId().equals(NetworkParameters.ID_TESTNET); + SimplifiedMasternodeList MnsUsedAtH = new SimplifiedMasternodeList(params); + SimplifiedMasternodeList MnsNotUsedAtH = new SimplifiedMasternodeList(params); + ArrayList MnsUsedAtHIndex = Lists.newArrayListWithCapacity(llmqParameters.getSigningActiveQuorumCount()); - for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { - MnsUsedAtHIndex.add(new SimplifiedMasternodeList(params)); - } + boolean skipRemovedMNs = params.isV19Active(cycleQuorumBaseBlock) || params.getId().equals(NetworkParameters.ID_TESTNET); - for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { - for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinusC.get(i)) { - boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); - if (!skip && allMns.isValid(mn.proRegTxHash)) { - MnsUsedAtH.addMN(mn); - MnsUsedAtHIndex.get(i).addMN(mn); - } - } - for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinus2C.get(i)) { - boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); - if (!skip && allMns.isValid(mn.proRegTxHash)) { - MnsUsedAtH.addMN(mn); - MnsUsedAtHIndex.get(i).addMN(mn); - } + for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { + MnsUsedAtHIndex.add(new SimplifiedMasternodeList(params)); + } + + for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { + for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinusC.get(i)) { + boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); + if (!skip && allMns.isValid(mn.proRegTxHash)) { + MnsUsedAtH.addMN(mn); + MnsUsedAtHIndex.get(i).addMN(mn); } - for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinus3C.get(i)) { - boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); - if (!skip && allMns.isValid(mn.proRegTxHash)) { - MnsUsedAtH.addMN(mn); - MnsUsedAtHIndex.get(i).addMN(mn); - } + } + for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinus2C.get(i)) { + boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); + if (!skip && allMns.isValid(mn.proRegTxHash)) { + MnsUsedAtH.addMN(mn); + MnsUsedAtHIndex.get(i).addMN(mn); } } - - allMns.forEachMN(true, mn -> { - if (mn.isValid() && !MnsUsedAtH.containsMN(mn.getProTxHash())) { - MnsNotUsedAtH.addMN(mn); + for (SimplifiedMasternodeListEntry mn : previousQuarters.quarterHMinus3C.get(i)) { + boolean skip = skipRemovedMNs && !allMns.containsMN(mn.proRegTxHash); + if (!skip && allMns.isValid(mn.proRegTxHash)) { + MnsUsedAtH.addMN(mn); + MnsUsedAtHIndex.get(i).addMN(mn); } - }); + } + } - if (context.isDebugMode()) { - log.info("modifier: {}", modifier); - printList(MnsUsedAtH, "MnsUsedAtH"); - printList(MnsNotUsedAtH, "MnsNotUsedAtH"); + allMns.forEachMN(true, mn -> { + if (mn.isValid() && !MnsUsedAtH.containsMN(mn.getProTxHash())) { + MnsNotUsedAtH.addMN(mn); } - ArrayList sortedMnsUsedAtH = MnsUsedAtH.calculateQuorum(MnsUsedAtH.getAllMNsCount(), modifier); - if (context.isDebugMode()) printList(sortedMnsUsedAtH, "sortedMnsUsedAtH"); - ArrayList sortedMnsNotUsedAtH = MnsNotUsedAtH.calculateQuorum(MnsNotUsedAtH.getAllMNsCount(), modifier); - if (context.isDebugMode()) printList(sortedMnsNotUsedAtH, "sortedMnsNotUsedAtH"); - ArrayList sortedCombinedMnsList = new ArrayList<>(sortedMnsNotUsedAtH); - sortedCombinedMnsList.addAll(sortedMnsUsedAtH); - if (context.isDebugMode()) { - printList(sortedCombinedMnsList, "sortedCombinedMnsList"); - StringBuilder ss = new StringBuilder(); - ss.append(" ["); - for (Masternode m : sortedCombinedMnsList) { - ss.append(m.getProTxHash().toString(), 0, 4).append("|"); - } - ss.append("]"); - log.info("BuildNewQuorumQuarterMembers h[{}] {}\n", cycleQuorumBaseBlock.getHeight(), ss); + }); + + if (context.isDebugMode()) { + log.info("modifier: {}", modifier); + printList(MnsUsedAtH, "MnsUsedAtH"); + printList(MnsNotUsedAtH, "MnsNotUsedAtH"); + } + ArrayList sortedMnsUsedAtH = MnsUsedAtH.calculateQuorum(MnsUsedAtH.getAllMNsCount(), modifier); + if (context.isDebugMode()) printList(sortedMnsUsedAtH, "sortedMnsUsedAtH"); + ArrayList sortedMnsNotUsedAtH = MnsNotUsedAtH.calculateQuorum(MnsNotUsedAtH.getAllMNsCount(), modifier); + if (context.isDebugMode()) printList(sortedMnsNotUsedAtH, "sortedMnsNotUsedAtH"); + ArrayList sortedCombinedMnsList = new ArrayList<>(sortedMnsNotUsedAtH); + sortedCombinedMnsList.addAll(sortedMnsUsedAtH); + if (context.isDebugMode()) { + printList(sortedCombinedMnsList, "sortedCombinedMnsList"); + StringBuilder ss = new StringBuilder(); + ss.append(" ["); + for (Masternode m : sortedCombinedMnsList) { + ss.append(m.getProTxHash().toString(), 0, 4).append("|"); } + ss.append("]"); + log.info("BuildNewQuorumQuarterMembers h[{}] {}\n", cycleQuorumBaseBlock.getHeight(), ss); + } - ArrayList skipList = Lists.newArrayList(); - int firstSkippedIndex = 0; - int idx = 0; - for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { - int usedMNsCount = MnsUsedAtHIndex.get(i).getAllMNsCount(); - boolean updated = false; - int initialLoopIndex = idx; - while (quarterQuorumMembers.get(i).size() < quarterSize) { - boolean skip = true; - Masternode mn = sortedCombinedMnsList.get(idx); - if (!MnsUsedAtHIndex.get(i).containsMN(mn.getProTxHash())) { - MnsUsedAtHIndex.get(i).addMN((SimplifiedMasternodeListEntry) sortedCombinedMnsList.get(idx)); - quarterQuorumMembers.get(i).add((SimplifiedMasternodeListEntry) mn); - updated = true; - skip = false; - } - if (skip) { - if (firstSkippedIndex == 0) { - firstSkippedIndex = idx; - skipList.add(idx); - } else { - skipList.add(idx - firstSkippedIndex); - } - } - idx++; - if (idx == sortedCombinedMnsList.size()) { - idx = 0; + ArrayList skipList = Lists.newArrayList(); + int firstSkippedIndex = 0; + int idx = 0; + for (int i = 0; i < llmqParameters.getSigningActiveQuorumCount(); ++i) { + int usedMNsCount = MnsUsedAtHIndex.get(i).getAllMNsCount(); + boolean updated = false; + int initialLoopIndex = idx; + while (quarterQuorumMembers.get(i).size() < quarterSize) { + boolean skip = true; + Masternode mn = sortedCombinedMnsList.get(idx); + if (!MnsUsedAtHIndex.get(i).containsMN(mn.getProTxHash())) { + MnsUsedAtHIndex.get(i).addMN((SimplifiedMasternodeListEntry) sortedCombinedMnsList.get(idx)); + quarterQuorumMembers.get(i).add((SimplifiedMasternodeListEntry) mn); + updated = true; + skip = false; + } + if (skip) { + if (firstSkippedIndex == 0) { + firstSkippedIndex = idx; + skipList.add(idx); + } else { + skipList.add(idx - firstSkippedIndex); } - if (idx == initialLoopIndex) { - // we made full "while" loop - if (!updated) { - // there are not enough MNs, there is nothing we can do here - return createNewQuarterQuorumMembers(llmqParameters); - } - // reset and try again - updated = false; + } + idx++; + if (idx == sortedCombinedMnsList.size()) { + idx = 0; + } + if (idx == initialLoopIndex) { + // we made full "while" loop + if (!updated) { + // there are not enough MNs, there is nothing we can do here + return createNewQuarterQuorumMembers(llmqParameters); } + // reset and try again + updated = false; } } - - return quarterQuorumMembers; - } catch (BlockStoreException x) { - throw new RuntimeException(x); } + + return quarterQuorumMembers; } @Deprecated @@ -884,32 +867,27 @@ PreviousQuorumQuarters getPreviousQuorumQuarterMembers(LLMQParameters llmqParame int height) { PreviousQuorumQuarters quarters = new PreviousQuorumQuarters(); - try { - final BlockStore store = headerStore != null && headerStore.getChainHead().getHeight() > blockStore.getChainHead().getHeight() ? headerStore : blockStore; - StoredBlock snapshotBlockHMinusC = blockHMinusC.getAncestor(store, blockHMinusC.getHeight() - 8); - StoredBlock snapshotBlockHMinus2C = blockHMinusC.getAncestor(store, blockHMinus2C.getHeight() - 8); - StoredBlock snapshotBlockHMinus3C = blockHMinusC.getAncestor(store, blockHMinus3C.getHeight() - 8); + StoredBlock snapshotBlockHMinusC = blockChain.getBlockAncestor(blockHMinusC, blockHMinusC.getHeight() - 8); + StoredBlock snapshotBlockHMinus2C = blockChain.getBlockAncestor(blockHMinusC, blockHMinus2C.getHeight() - 8); + StoredBlock snapshotBlockHMinus3C = blockChain.getBlockAncestor(blockHMinusC, blockHMinus3C.getHeight() - 8); - QuorumSnapshot quSnapshotHMinusC = quorumSnapshotCache.get(snapshotBlockHMinusC.getHeader().getHash()); - if (quSnapshotHMinusC != null) { + QuorumSnapshot quSnapshotHMinusC = quorumSnapshotCache.get(snapshotBlockHMinusC.getHeader().getHash()); + if (quSnapshotHMinusC != null) { - quarters.quarterHMinusC = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinusC, quSnapshotHMinusC, height); + quarters.quarterHMinusC = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinusC, quSnapshotHMinusC, height); - QuorumSnapshot quSnapshotHMinus2C = quorumSnapshotCache.get(snapshotBlockHMinus2C.getHeader().getHash()); - if (quSnapshotHMinus2C != null) { - quarters.quarterHMinus2C = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinus2C, quSnapshotHMinus2C, height); + QuorumSnapshot quSnapshotHMinus2C = quorumSnapshotCache.get(snapshotBlockHMinus2C.getHeader().getHash()); + if (quSnapshotHMinus2C != null) { + quarters.quarterHMinus2C = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinus2C, quSnapshotHMinus2C, height); - QuorumSnapshot quSnapshotHMinus3C = quorumSnapshotCache.get(snapshotBlockHMinus3C.getHeader().getHash()); - if (quSnapshotHMinus3C != null) { - quarters.quarterHMinus3C = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinus3C, quSnapshotHMinus3C, height); - } + QuorumSnapshot quSnapshotHMinus3C = quorumSnapshotCache.get(snapshotBlockHMinus3C.getHeader().getHash()); + if (quSnapshotHMinus3C != null) { + quarters.quarterHMinus3C = getQuorumQuarterMembersBySnapshot(llmqParameters, blockHMinus3C, quSnapshotHMinus3C, height); } } - - return quarters; - } catch (BlockStoreException x) { - throw new RuntimeException(x); } + + return quarters; } ArrayList> getQuorumQuarterMembersBySnapshot(LLMQParameters llmqParameters, StoredBlock cycleQuorumBaseBlock, QuorumSnapshot snapshot, int height) { @@ -1002,12 +980,11 @@ Pair getMNUsageBySnapshot(LL StoredBlock cycleQuorumBaseBlock, QuorumSnapshot snapshot, int height) { - try { SimplifiedMasternodeList usedMNs = new SimplifiedMasternodeList(params); SimplifiedMasternodeList nonUsedMNs = new SimplifiedMasternodeList(params); - final BlockStore store = headerStore != null && headerStore.getChainHead().getHeight() > blockStore.getChainHead().getHeight() ? headerStore : blockStore; - final StoredBlock workBlock = cycleQuorumBaseBlock.getAncestor(store, cycleQuorumBaseBlock.getHeight() - 8); + //final BlockStore store = headerStore != null && headerStore.getChainHead().getHeight() > blockStore.getChainHead().getHeight() ? headerStore : blockStore; + final StoredBlock workBlock = blockChain.getBlockAncestor(cycleQuorumBaseBlock, cycleQuorumBaseBlock.getHeight() - 8); final Sha256Hash modifier = getHashModifier(llmqParameters, cycleQuorumBaseBlock); SimplifiedMasternodeList allMns = getListForBlock(workBlock.getHeader().getHash()); @@ -1027,9 +1004,6 @@ Pair getMNUsageBySnapshot(LL i.getAndIncrement(); } return new Pair<>(usedMNs, nonUsedMNs); - } catch (BlockStoreException x) { - throw new RuntimeException(x); - } } void initIndexedQuorumsCache(HashMap, ArrayList>> cache) { @@ -1263,22 +1237,20 @@ public String toString() { } @Override - public void processDiff(@Nullable Peer peer, QuorumRotationInfo quorumRotationInfo, AbstractBlockChain headersChain, - AbstractBlockChain blockChain, boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException { + public void processDiff(@Nullable Peer peer, QuorumRotationInfo quorumRotationInfo, DualBlockChain blockChain, + boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException { long newHeight = ((CoinbaseTx) quorumRotationInfo.getMnListDiffTip().coinBaseTx.getExtraPayloadObject()).getHeight(); if (peer != null) peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Received, quorumRotationInfo.getMnListDiffTip()); Stopwatch watch = Stopwatch.createStarted(); boolean isSyncingHeadersFirst = syncStage == PeerGroup.SyncStage.MNLIST; - AbstractBlockChain chain = isSyncingHeadersFirst ? headersChain : blockChain; - headerChain = headersChain; quorumRotationInfo.dump(getMnListTip().getHeight(), newHeight); lock.lock(); try { - setBlockChain(peerGroup, headersChain, blockChain); - applyDiff(peer, headersChain, blockChain, quorumRotationInfo, isLoadingBootStrap); + setBlockChain(peerGroup, blockChain); + applyDiff(peer, blockChain, quorumRotationInfo, isLoadingBootStrap); unCache(); failedAttempts = 0; diff --git a/core/src/main/java/org/bitcoinj/evolution/QuorumState.java b/core/src/main/java/org/bitcoinj/evolution/QuorumState.java index 47f748e00..6cfe832ea 100644 --- a/core/src/main/java/org/bitcoinj/evolution/QuorumState.java +++ b/core/src/main/java/org/bitcoinj/evolution/QuorumState.java @@ -18,8 +18,8 @@ import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; -import org.bitcoinj.core.AbstractBlockChain; import org.bitcoinj.core.Context; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.MasternodeSync; import org.bitcoinj.core.Peer; import org.bitcoinj.core.PeerGroup; @@ -27,7 +27,6 @@ import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.StoredBlock; import org.bitcoinj.core.VerificationException; -import org.bitcoinj.crypto.BLSSignature; import org.bitcoinj.evolution.listeners.MasternodeListDownloadedListener; import org.bitcoinj.quorums.LLMQParameters; import org.bitcoinj.quorums.SigningManager; @@ -40,7 +39,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; @@ -117,23 +115,15 @@ public void requestUpdate(Peer peer, StoredBlock nextBlock) { sendRequestWithRetry(peer); } - public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockChain blockChain, + public void applyDiff(Peer peer, DualBlockChain blockChain, SimplifiedMasternodeListDiff mnlistdiff, boolean isLoadingBootStrap) throws BlockStoreException, MasternodeListDiffException { StoredBlock block; boolean isSyncingHeadersFirst = context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST; - AbstractBlockChain chain = isSyncingHeadersFirst ? headersChain : blockChain; long newHeight = ((CoinbaseTx) mnlistdiff.coinBaseTx.getExtraPayloadObject()).getHeight(); - block = chain.getBlockStore().get(mnlistdiff.blockHash); - if (block == null) { - // this should be improved. isSyncingHeadersFirst could be false, but blockChain may not be synced - // so we need to check the headersChain - block = headersChain.getBlockStore().get(mnlistdiff.blockHash); - if (block != null) { - chain = headersChain; - } - } + block = blockChain.getBlock(mnlistdiff.blockHash); + if(!isLoadingBootStrap && block.getHeight() != newHeight) throw new ProtocolException("mnlistdiff blockhash (height="+block.getHeight()+" doesn't match coinbase blockheight: " + newHeight); @@ -147,7 +137,7 @@ public void applyDiff(Peer peer, AbstractBlockChain headersChain, AbstractBlockC SimplifiedQuorumList newQuorumList = quorumList; if (mnlistdiff.coinBaseTx.getExtraPayloadObject().getVersion() >= SimplifiedMasternodeListManager.LLMQ_FORMAT_VERSION) { - newQuorumList = quorumList.applyDiff(mnlistdiff, isLoadingBootStrap, chain, false, true); + newQuorumList = quorumList.applyDiff(mnlistdiff, isLoadingBootStrap, blockChain, false, true); if (context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM)) newQuorumList.verify(mnlistdiff.coinBaseTx, mnlistdiff, quorumList, newMNList); } else { @@ -187,7 +177,7 @@ public GetSimplifiedMasternodeListDiff getMasternodeListDiffRequest(StoredBlock } public ArrayList getAllQuorumMembers(LLMQParameters.LLMQType llmqType, Sha256Hash quorumBaseBlockHash) { - StoredBlock quorumBaseBlock = getBlockFromHash(quorumBaseBlockHash); + StoredBlock quorumBaseBlock = blockChain.getBlock(quorumBaseBlockHash); return computeQuorumMembers(llmqType, quorumBaseBlock); } @@ -200,7 +190,7 @@ protected ArrayList computeQuorumMembers(LLMQParameters.LLMQType llm } StoredBlock workBlock = params.isV20Active(quorumBaseBlock) ? - getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 8) : + blockChain.getBlockAncestor(quorumBaseBlock, quorumBaseBlock.getHeight() - 8) : quorumBaseBlock; Sha256Hash modifier = getHashModifier(llmqParameters, quorumBaseBlock); @@ -260,8 +250,8 @@ public SimplifiedQuorumList getQuorumListAtTip() { } @Override - public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlistdiff, AbstractBlockChain headersChain, - AbstractBlockChain blockChain, boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException { + public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlistdiff, DualBlockChain blockChain, + boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException { StoredBlock block = null; long newHeight = ((CoinbaseTx) mnlistdiff.coinBaseTx.getExtraPayloadObject()).getHeight(); if (peer != null) peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Received, mnlistdiff); @@ -269,7 +259,6 @@ public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlist Stopwatch watchMNList = Stopwatch.createUnstarted(); Stopwatch watchQuorums = Stopwatch.createUnstarted(); boolean isSyncingHeadersFirst = context.peerGroup != null && context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST; - this.headerChain = headersChain; log.info("processing {} mnlistdiff between : {} & {}; {}", isLoadingBootStrap ? "bootstrap" : "requested", getMnList().getHeight(), newHeight, mnlistdiff); @@ -278,7 +267,7 @@ public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlist lock.lock(); try { - applyDiff(peer, headersChain, blockChain, mnlistdiff, isLoadingBootStrap); + applyDiff(peer, blockChain, mnlistdiff, isLoadingBootStrap); log.info(this.toString()); unCache(); diff --git a/core/src/main/java/org/bitcoinj/evolution/QuorumUpdateRequest.java b/core/src/main/java/org/bitcoinj/evolution/QuorumUpdateRequest.java index 41f4f23e3..20b056c32 100644 --- a/core/src/main/java/org/bitcoinj/evolution/QuorumUpdateRequest.java +++ b/core/src/main/java/org/bitcoinj/evolution/QuorumUpdateRequest.java @@ -17,6 +17,7 @@ package org.bitcoinj.evolution; import org.bitcoinj.core.AbstractBlockChain; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.PeerAddress; import org.bitcoinj.core.Utils; @@ -69,7 +70,7 @@ public String toString() { '}'; } - public String toString(AbstractBlockChain blockChain) { + public String toString(DualBlockChain blockChain) { return "QuorumUpdateRequest{" + "request=" + request.toString(blockChain) + ", time=" + time + diff --git a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListDiff.java b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListDiff.java index 696b6d037..fa0e1f37b 100644 --- a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListDiff.java +++ b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListDiff.java @@ -6,7 +6,6 @@ import org.bitcoinj.core.*; import org.bitcoinj.crypto.BLSSignature; import org.bitcoinj.quorums.FinalCommitment; -import org.bitcoinj.store.BlockStore; import org.bitcoinj.utils.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -204,12 +203,12 @@ public String toString() { (coinBaseTx.getExtraPayloadObject().getVersion() >= 2 ? (" while adding " + newQuorums.size() + " and removing " + deletedQuorums.size() + " quorums") : ""); } - public String toString(BlockStore blockStore) { + public String toString(DualBlockChain blockChain) { int height = -1; int prevHeight = -1; try { - height = blockStore.get(blockHash).getHeight(); - prevHeight = blockStore.get(prevBlockHash).getHeight(); + height = blockChain.getBlock(blockHash).getHeight(); + prevHeight = blockChain.getBlock(prevBlockHash).getHeight(); } catch (Exception x) { // swallow } diff --git a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java index 148156d30..b47eced14 100644 --- a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java +++ b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java @@ -19,9 +19,9 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.util.concurrent.SettableFuture; -import org.bitcoinj.core.AbstractBlockChain; import org.bitcoinj.core.AbstractManager; import org.bitcoinj.core.Context; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.MasternodeSync; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Peer; @@ -41,7 +41,6 @@ import org.bitcoinj.quorums.QuorumSnapshotManager; import org.bitcoinj.quorums.SigningManager; import org.bitcoinj.quorums.SimplifiedQuorumList; -import org.bitcoinj.store.BlockStoreException; import org.bitcoinj.utils.ContextPropagatingThreadFactory; import org.bitcoinj.utils.Threading; import org.slf4j.Logger; @@ -96,21 +95,11 @@ public void processQuorum(FinalCommitment finalCommitment) { } public int getBlockHeight(Sha256Hash quorumHash) { - try { - if (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight()) { - return headersChain.getBlockStore().get(quorumHash).getHeight(); - } else return blockChain.getBlockStore().get(quorumHash).getHeight(); - } catch (BlockStoreException x) { - return -1; - } + return blockChain.getBlockHeight(quorumHash); } public StoredBlock getBlockTip() { - if (headersChain != null && headersChain.getBestChainHeight() > blockChain.getBestChainHeight()) { - return headersChain.getChainHead(); - } else { - return blockChain.getChainHead(); - } + return blockChain.getChainHead(); } public void waitForBootstrapLoaded() throws ExecutionException, InterruptedException { @@ -132,8 +121,10 @@ public enum SaveOptions { long tipHeight; Sha256Hash tipBlockHash; - AbstractBlockChain blockChain; - AbstractBlockChain headersChain; + //AbstractBlockChain blockChain; + //AbstractBlockChain headersChain; + + DualBlockChain blockChain; boolean loadedFromFile; boolean requiresLoadingFromFile; @@ -307,7 +298,7 @@ public void processMasternodeListDiff(Peer peer, SimplifiedMasternodeListDiff mn public void processMasternodeListDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlistdiff, boolean isLoadingBootStrap) { try { - quorumState.processDiff(peer, mnlistdiff, headersChain, blockChain, isLoadingBootStrap, context.peerGroup.getSyncStage()); + quorumState.processDiff(peer, mnlistdiff, blockChain, isLoadingBootStrap, context.peerGroup.getSyncStage()); processMasternodeList(mnlistdiff); processQuorumList(quorumState.getQuorumListAtTip()); @@ -344,7 +335,7 @@ public void processQuorumRotationInfo(@Nullable Peer peer, QuorumRotationInfo qu @Override public void run() { try { - quorumRotationState.processDiff(peer, quorumRotationInfo, headersChain, blockChain, isLoadingBootStrap, PeerGroup.SyncStage.BLOCKS); + quorumRotationState.processDiff(peer, quorumRotationInfo, blockChain, isLoadingBootStrap, PeerGroup.SyncStage.BLOCKS); processMasternodeList(quorumRotationInfo.getMnListDiffAtH()); unCache(); @@ -397,21 +388,20 @@ private void resetQuorumState() { quorumRotationState.clearState(); } - public void setBlockChain(AbstractBlockChain blockChain, @Nullable AbstractBlockChain headersChain, @Nullable PeerGroup peerGroup, + public void setBlockChain(DualBlockChain blockChain, @Nullable PeerGroup peerGroup, QuorumManager quorumManager, QuorumSnapshotManager quorumSnapshotManager, ChainLocksHandler chainLocksHandler) { this.blockChain = blockChain; this.peerGroup = peerGroup; - this.headersChain = headersChain; this.quorumManager = quorumManager; this.quorumSnapshotManager = quorumSnapshotManager; - AbstractBlockChain activeChain = headersChain != null ? headersChain : blockChain; - quorumState.setBlockChain(peerGroup, headersChain, blockChain); - quorumRotationState.setBlockChain(peerGroup, headersChain, blockChain); + //AbstractBlockChain activeChain = headersChain != null ? headersChain : blockChain; + quorumState.setBlockChain(peerGroup, blockChain); + quorumRotationState.setBlockChain(peerGroup, blockChain); quorumState.setChainLocksHandler(chainLocksHandler); quorumRotationState.setChainLocksHandler(chainLocksHandler); if(shouldProcessMNListDiff()) { - quorumState.addEventListeners(blockChain, peerGroup); - quorumRotationState.addEventListeners(blockChain, peerGroup); + quorumState.addEventListeners(blockChain.getBlockChain(), peerGroup); + quorumRotationState.addEventListeners(blockChain.getBlockChain(), peerGroup); } if (threadPool.isShutdown()) { threadPool = Executors.newFixedThreadPool(1, new ContextPropagatingThreadFactory("process-qrinfo")); @@ -421,8 +411,8 @@ public void setBlockChain(AbstractBlockChain blockChain, @Nullable AbstractBlock @Override public void close() { if (shouldProcessMNListDiff()) { - quorumState.removeEventListeners(blockChain, peerGroup); - quorumRotationState.removeEventListeners(blockChain, peerGroup); + quorumState.removeEventListeners(blockChain.getBlockChain(), peerGroup); + quorumRotationState.removeEventListeners(blockChain.getBlockChain(), peerGroup); try { threadPool.shutdown(); @@ -456,8 +446,7 @@ public boolean isQuorumRotationEnabled(LLMQParameters.LLMQType type) { if (blockChain == null) { return formatVersion == QUORUM_ROTATION_FORMAT_VERSION; } - boolean quorumRotationActive = blockChain.getBestChainHeight() >= params.getDIP0024BlockHeight() || - (headersChain != null && headersChain.getBestChainHeight() >= params.getDIP0024BlockHeight()); + boolean quorumRotationActive = blockChain.getBestChainHeight() >= params.getDIP0024BlockHeight(); return params.getLlmqDIP0024InstantSend() == type && quorumRotationActive; } @@ -504,22 +493,16 @@ public SimplifiedQuorumList getQuorumListForBlock(Sha256Hash blockHash, LLMQPara try { // TODO: Chainlocks problems are from this? if (isQuorumRotationEnabled(llmqType)) { - try { - LLMQParameters llmqParameters = params.getLlmqs().get(llmqType); - StoredBlock block = blockChain.getBlockStore().get(blockHash); - if (block == null) - block = headersChain.getBlockStore().get(blockHash); - StoredBlock lastQuorumBlock = block.getAncestor(blockChain.getBlockStore(), - block.getHeight() - block.getHeight() % llmqParameters.getDkgInterval() - SigningManager.SIGN_HEIGHT_OFFSET); - if (lastQuorumBlock == null) - lastQuorumBlock = block.getAncestor(headersChain.getBlockStore(), - block.getHeight() - block.getHeight() % llmqParameters.getDkgInterval() - SigningManager.SIGN_HEIGHT_OFFSET); - - return quorumRotationState.getQuorumListForBlock(lastQuorumBlock); - } catch (BlockStoreException x) { - throw new RuntimeException(x); + LLMQParameters llmqParameters = params.getLlmqs().get(llmqType); + StoredBlock block = blockChain.getBlock(blockHash); + StoredBlock lastQuorumBlock = blockChain.getBlockAncestor(block, + block.getHeight() - block.getHeight() % llmqParameters.getDkgInterval() - SigningManager.SIGN_HEIGHT_OFFSET); + if (lastQuorumBlock == null) { + log.info("last quorum block is null"); + return null; } + return quorumRotationState.getQuorumListForBlock(lastQuorumBlock); } else { return getQuorumListCache(llmqType).get(blockHash); } diff --git a/core/src/main/java/org/bitcoinj/quorums/GetQuorumRotationInfo.java b/core/src/main/java/org/bitcoinj/quorums/GetQuorumRotationInfo.java index 9303cf9da..11e4f4f73 100644 --- a/core/src/main/java/org/bitcoinj/quorums/GetQuorumRotationInfo.java +++ b/core/src/main/java/org/bitcoinj/quorums/GetQuorumRotationInfo.java @@ -17,13 +17,12 @@ package org.bitcoinj.quorums; import com.google.common.collect.Lists; -import org.bitcoinj.core.AbstractBlockChain; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.ProtocolException; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.VarInt; import org.bitcoinj.evolution.AbstractQuorumRequest; -import org.bitcoinj.store.BlockStoreException; import java.io.IOException; import java.io.OutputStream; @@ -88,16 +87,14 @@ public String toString() { } @Override - public String toString(AbstractBlockChain blockChain) { + public String toString(DualBlockChain blockChain) { List baseHeights = Lists.newArrayList(); int blockHeight = -1; try { for (Sha256Hash baseBlockHash : baseBlockHashes) { - baseHeights.add(blockChain.getBlockStore().get(baseBlockHash).getHeight()); + baseHeights.add(blockChain.getBlock(baseBlockHash).getHeight()); } - blockHeight = blockChain.getBlockStore().get(blockRequestHash).getHeight(); - } catch (BlockStoreException x) { - throw new RuntimeException(x); + blockHeight = blockChain.getBlock(blockRequestHash).getHeight(); } catch (NullPointerException x) { // swallow } diff --git a/core/src/main/java/org/bitcoinj/quorums/QuorumRotationInfo.java b/core/src/main/java/org/bitcoinj/quorums/QuorumRotationInfo.java index a71e5f50c..41e9add93 100644 --- a/core/src/main/java/org/bitcoinj/quorums/QuorumRotationInfo.java +++ b/core/src/main/java/org/bitcoinj/quorums/QuorumRotationInfo.java @@ -16,7 +16,7 @@ package org.bitcoinj.quorums; -import org.bitcoinj.core.AbstractBlockChain; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.ProtocolException; import org.bitcoinj.core.Sha256Hash; @@ -24,14 +24,9 @@ import org.bitcoinj.core.VarInt; import org.bitcoinj.evolution.AbstractDiffMessage; import org.bitcoinj.evolution.SimplifiedMasternodeListDiff; -import org.bitcoinj.store.BlockStore; -import org.bitcoinj.store.BlockStoreException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -58,6 +53,7 @@ public class QuorumRotationInfo extends AbstractDiffMessage { ArrayList quorumSnapshotList; ArrayList mnListDiffLists; + @Deprecated QuorumRotationInfo(NetworkParameters params) { super(params); } @@ -227,29 +223,24 @@ public String toString() { '}'; } - private static int getHeight(Sha256Hash hash, AbstractBlockChain chain) { - try { - StoredBlock block = chain.getBlockStore().get(hash); - return block != null ? block.getHeight() : -1; - } catch (BlockStoreException x) { - throw new RuntimeException(x); - } + private static int getHeight(Sha256Hash hash, DualBlockChain chain) { + StoredBlock block = chain.getBlock(hash); + return block != null ? block.getHeight() : -1; } - public String toString(AbstractBlockChain chain) { - BlockStore blockStore = chain.getBlockStore(); + public String toString(DualBlockChain chain) { StringBuilder builder = new StringBuilder(); builder.append("QuorumRotationInfo{" + ",\n quorumSnapshotAtHMinusC=" + quorumSnapshotAtHMinusC + ",\n quorumSnapshotAtHMinus2C=" + quorumSnapshotAtHMinus2C + ",\n quorumSnapshotAtHMinus3C=" + quorumSnapshotAtHMinus3C + - ",\n mnListDiffTip=" + mnListDiffTip.toString(blockStore) + - ",\n mnListDiffAtH=" + mnListDiffAtH.toString(blockStore) + - ",\n mnListDiffAtHMinusC=" + mnListDiffAtHMinusC.toString(blockStore) + - ",\n mnListDiffAtHMinus2C=" + mnListDiffAtHMinus2C.toString(blockStore) + - ",\n mnListDiffAtHMinus3C=" + mnListDiffAtHMinus3C.toString(blockStore)); + ",\n mnListDiffTip=" + mnListDiffTip.toString(chain) + + ",\n mnListDiffAtH=" + mnListDiffAtH.toString(chain) + + ",\n mnListDiffAtHMinusC=" + mnListDiffAtHMinusC.toString(chain) + + ",\n mnListDiffAtHMinus2C=" + mnListDiffAtHMinus2C.toString(chain) + + ",\n mnListDiffAtHMinus3C=" + mnListDiffAtHMinus3C.toString(chain)); if (mnListDiffAtHMinus4C != null) { - builder.append(",\n mnListDiffAtHMinus4C=").append(mnListDiffAtHMinus4C.toString(blockStore)); + builder.append(",\n mnListDiffAtHMinus4C=").append(mnListDiffAtHMinus4C.toString(chain)); } builder.append("------------------------------\n"); @@ -262,7 +253,7 @@ public String toString(AbstractBlockChain chain) { } for (SimplifiedMasternodeListDiff mnlistdiff : mnListDiffLists) { - builder.append("mnlistdiff: ").append(mnlistdiff.toString(chain.getBlockStore())).append("\n"); + builder.append("mnlistdiff: ").append(mnlistdiff.toString(chain)).append("\n"); } builder.append('}'); return builder.toString(); diff --git a/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java b/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java index 366ada436..0141b4f0c 100644 --- a/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java +++ b/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java @@ -4,7 +4,6 @@ import org.bitcoinj.crypto.BLSSignature; import org.bitcoinj.evolution.*; import org.bitcoinj.evolution.Masternode; -import org.bitcoinj.store.BlockStore; import org.bitcoinj.store.BlockStoreException; import org.bitcoinj.utils.Pair; import org.bitcoinj.utils.Threading; @@ -123,7 +122,7 @@ BLSSignature getSignatureForIndex(HashMap> quorum return answer.map(Map.Entry::getKey).orElse(null); } - public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean isLoadingBootstrap, AbstractBlockChain chain, boolean doDIP24, boolean validateOldQuorums) throws MasternodeListDiffException{ + public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean isLoadingBootstrap, DualBlockChain chain, boolean doDIP24, boolean validateOldQuorums) throws MasternodeListDiffException{ lock.lock(); try { CoinbaseTx cbtx = (CoinbaseTx) diff.getCoinBaseTx().getExtraPayloadObject(); @@ -162,7 +161,7 @@ public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean } } - public void verifyQuorums(boolean isLoadingBootstrap, AbstractBlockChain chain, boolean validateOldQuorums) throws BlockStoreException, ProtocolException{ + public void verifyQuorums(boolean isLoadingBootstrap, DualBlockChain chain, boolean validateOldQuorums) throws BlockStoreException, ProtocolException{ lock.lock(); try { int verifiedCount = 0; @@ -177,8 +176,8 @@ public void verifyQuorums(boolean isLoadingBootstrap, AbstractBlockChain chain, } } - private boolean verifyQuorum(boolean isLoadingBootstrap, AbstractBlockChain chain, boolean validateOldQuorums, FinalCommitment entry) throws BlockStoreException { - StoredBlock block = chain.getBlockStore().get(entry.getQuorumHash()); + private boolean verifyQuorum(boolean isLoadingBootstrap, DualBlockChain chain, boolean validateOldQuorums, FinalCommitment entry) throws BlockStoreException { + StoredBlock block = chain.getBlock(entry.getQuorumHash()); if (block != null) { LLMQParameters llmqParameters = params.getLlmqs().get(entry.getLlmqType()); if (llmqParameters == null) @@ -469,14 +468,14 @@ public void syncWithMasternodeList(SimplifiedMasternodeList masternodeList) { } private boolean checkCommitment(FinalCommitment commitment, StoredBlock prevBlock, SimplifiedMasternodeListManager manager, - AbstractBlockChain chain, boolean validateQuorums) throws BlockStoreException + DualBlockChain chain, boolean validateQuorums) throws BlockStoreException { if (commitment.getVersion() == 0 || commitment.getVersion() > FinalCommitment.MAX_VERSION) { throw new VerificationException("invalid quorum commitment version: " + commitment.getVersion()); } - BlockStore blockStore = chain.getBlockStore(); - StoredBlock quorumBlock = blockStore.get(commitment.quorumHash); + //BlockStore blockStore = chain.getBlockStore(); + StoredBlock quorumBlock = chain.getBlock(commitment.quorumHash); if(quorumBlock == null) throw new VerificationException("invalid quorum hash: " + commitment.quorumHash); @@ -484,7 +483,7 @@ private boolean checkCommitment(FinalCommitment commitment, StoredBlock prevBloc while(cursor != null) { if(cursor.getHeader().getHash().equals(quorumBlock.getHeader().getHash())) break; - cursor = cursor.getPrev(blockStore); + cursor = chain.getBlock(cursor.getHeader().getHash()); } if(cursor == null) diff --git a/core/src/main/java/org/bitcoinj/wallet/AnyKeyChainGroup.java b/core/src/main/java/org/bitcoinj/wallet/AnyKeyChainGroup.java index 2e2198985..d0535ea6b 100644 --- a/core/src/main/java/org/bitcoinj/wallet/AnyKeyChainGroup.java +++ b/core/src/main/java/org/bitcoinj/wallet/AnyKeyChainGroup.java @@ -224,7 +224,7 @@ protected AnyKeyChainGroup(NetworkParameters params, @Nullable AnyBasicKeyChain @Nullable EnumMap currentKeys, @Nullable KeyCrypter crypter, KeyFactory keyFactory) { this.params = params; - this.basic = basicKeyChain == null ? new AnyBasicKeyChain(keyFactory) : basicKeyChain; + this.basic = basicKeyChain == null ? new AnyBasicKeyChain(crypter, keyFactory) : basicKeyChain; this.keyFactory = keyFactory; if (chains != null) { if (lookaheadSize > -1) @@ -686,8 +686,9 @@ public void encrypt(KeyCrypter keyCrypter, KeyParameter aesKey) { AnyBasicKeyChain newBasic = basic.toEncrypted(keyCrypter, aesKey); List newChains = new ArrayList<>(); if (chains != null) { - for (AnyDeterministicKeyChain chain : chains) + for (AnyDeterministicKeyChain chain : chains) { newChains.add(chain.toEncrypted(keyCrypter, aesKey)); + } } // Code below this point must be exception safe. diff --git a/core/src/main/java/org/bitcoinj/wallet/AuthenticationKeyChainGroup.java b/core/src/main/java/org/bitcoinj/wallet/AuthenticationKeyChainGroup.java index 115b75d00..b6b01b230 100644 --- a/core/src/main/java/org/bitcoinj/wallet/AuthenticationKeyChainGroup.java +++ b/core/src/main/java/org/bitcoinj/wallet/AuthenticationKeyChainGroup.java @@ -50,6 +50,7 @@ public static class Builder { private final List chains = new LinkedList<>(); private int lookaheadSize = -1, lookaheadThreshold = -1; private KeyFactory keyFactory; + private KeyCrypter keyCrypter; private Builder(NetworkParameters params, KeyChainGroupStructure structure) { this.params = params; @@ -132,8 +133,18 @@ public AuthenticationKeyChainGroup.Builder lookaheadThreshold(int lookaheadThres return this; } + /** + * Set the keyCrypter. + * @param keyCrypter to use + */ + public AuthenticationKeyChainGroup.Builder keyCrypter(KeyCrypter keyCrypter) { + this.keyCrypter = keyCrypter; + return this; + } + + public AuthenticationKeyChainGroup build() { - return new AuthenticationKeyChainGroup(params, null, chains, lookaheadSize, lookaheadThreshold, null, null, keyFactory); + return new AuthenticationKeyChainGroup(params, null, chains, lookaheadSize, lookaheadThreshold, null, keyCrypter, keyFactory); } } diff --git a/core/src/main/java/org/bitcoinj/wallet/authentication/AuthenticationGroupExtension.java b/core/src/main/java/org/bitcoinj/wallet/authentication/AuthenticationGroupExtension.java index 36d4d09b7..d63192b10 100644 --- a/core/src/main/java/org/bitcoinj/wallet/authentication/AuthenticationGroupExtension.java +++ b/core/src/main/java/org/bitcoinj/wallet/authentication/AuthenticationGroupExtension.java @@ -92,7 +92,7 @@ public class AuthenticationGroupExtension extends AbstractKeyChainGroupExtension public static String EXTENSION_ID = "org.dashj.wallet.authentication"; private static final Logger log = LoggerFactory.getLogger(AuthenticationGroupExtension.class); - private final AuthenticationKeyChainGroup keyChainGroup; + private AuthenticationKeyChainGroup keyChainGroup; private final HashMap keyUsage = Maps.newHashMap(); private final CopyOnWriteArrayList> creditFundingListeners @@ -293,6 +293,7 @@ public void deserializeWalletExtension(Wallet containingWallet, byte[] data) thr KeyCrypter keyCrypter = wallet.getKeyCrypter(); AuthenticationKeyChainFactory factory = new AuthenticationKeyChainFactory(); Protos.AuthenticationGroupExtension walletExtension = Protos.AuthenticationGroupExtension.parseFrom(data); + keyChainGroup = AuthenticationKeyChainGroup.authenticationBuilder(wallet.getParams()).keyCrypter(keyCrypter).build(); // extended chains for (Protos.ExtendedKeyChain extendedKeyChain : walletExtension.getAuthenticationKeyChainsList()) { diff --git a/core/src/test/java/org/bitcoinj/core/DualBlockChainTest.java b/core/src/test/java/org/bitcoinj/core/DualBlockChainTest.java new file mode 100644 index 000000000..62c680110 --- /dev/null +++ b/core/src/test/java/org/bitcoinj/core/DualBlockChainTest.java @@ -0,0 +1,103 @@ +package org.bitcoinj.core; + +import com.google.common.collect.Lists; +import org.bitcoinj.params.TestNet3Params; +import org.bitcoinj.store.BlockStore; +import org.bitcoinj.store.BlockStoreException; +import org.bitcoinj.store.MemoryBlockStore; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; + +import java.math.BigInteger; + +public class DualBlockChainTest { + + AbstractBlockChain headersChain; + BlockStore headersStore; + + AbstractBlockChain blockChain; + BlockStore blockStore; + + TestNet3Params TESTNET = TestNet3Params.get(); + Context context = new Context(TESTNET); + + DualBlockChain dualBlockChain; + + static Sha256Hash block1Hash = Sha256Hash.wrap("0000047d24635e347be3aaaeb66c26be94901a2f962feccd4f95090191f208c1"); + + @Before + public void setUp() throws BlockStoreException { + StoredBlock genesisBlock = new StoredBlock(TESTNET.getGenesisBlock(), BigInteger.ZERO, 0); + blockStore = new MemoryBlockStore(TESTNET); + blockStore.put(genesisBlock); + blockChain = new BlockChain(TESTNET, blockStore); + blockChain.setChainHead(genesisBlock); + + StoredBlock block1 = new StoredBlock( + new Block( + TESTNET, + 2, + TESTNET.getGenesisBlock().getHash(), + Sha256Hash.wrap("b4fd581bc4bfe51a5a66d8b823bd6ee2b492f0ddc44cf7e820550714cedc117f"), + 1398712771, + 0x1e0fffff, + 31475, + Lists.newArrayList() + ), + BigInteger.ONE, + 1 + ); + + headersStore = new MemoryBlockStore(TESTNET); + headersStore.put(new StoredBlock(TESTNET.getGenesisBlock(), BigInteger.ZERO, 0)); + headersStore.put(block1); + headersChain = new BlockChain(TESTNET, headersStore); + headersChain.setChainHead(block1); + dualBlockChain = new DualBlockChain(headersChain, blockChain); + } + + @Test + public void testGetBlockChain() { + assertEquals(blockChain, dualBlockChain.getBlockChain()); + } + + @Test + public void testGetHeadersChain() { + assertEquals(headersChain, dualBlockChain.getHeadersChain()); + } + + @Test + public void testGetBlockHeight() { + assertEquals(0, dualBlockChain.getBlockHeight(TESTNET.getGenesisBlock().getHash())); + assertEquals(1, dualBlockChain.getBlockHeight(block1Hash)); + } + + @Test + public void testGetBestChainHeight() { + assertEquals(block1Hash, dualBlockChain.getBlock(1).getHeader().getHash()); + } + + @Test + public void testGetBlockUsingHash() { + assertEquals(TESTNET.getGenesisBlock().getHash(), dualBlockChain.getBlock(TESTNET.getGenesisBlock().getHash()).getHeader().getHash()); + assertEquals(block1Hash, dualBlockChain.getBlock(1).getHeader().getHash()); + } + + @Test + public void testGetBlockAncestor() { + StoredBlock block = dualBlockChain.getChainHead(); + assertEquals(TESTNET.getGenesisBlock().getHash(), dualBlockChain.getBlockAncestor(block, block.getHeight() - 1).getHeader().getHash()); + } + + @Test + public void testGetBlockUsingHeight() { + assertEquals(block1Hash, dualBlockChain.getBlock(1).getHeader().getHash()); + } + + @Test + public void testGetChainHead() { + assertEquals(block1Hash, dualBlockChain.getChainHead().getHeader().getHash()); + } +} + diff --git a/core/src/test/java/org/bitcoinj/quorums/QuorumRotationStateTest.java b/core/src/test/java/org/bitcoinj/quorums/QuorumRotationStateTest.java index f92cb9cc9..1c69a00a5 100644 --- a/core/src/test/java/org/bitcoinj/quorums/QuorumRotationStateTest.java +++ b/core/src/test/java/org/bitcoinj/quorums/QuorumRotationStateTest.java @@ -2,6 +2,7 @@ import org.bitcoinj.core.BlockChain; import org.bitcoinj.core.Context; +import org.bitcoinj.core.DualBlockChain; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.PeerGroup; import org.bitcoinj.crypto.BLSScheme; @@ -32,7 +33,7 @@ public class QuorumRotationStateTest { static MainNetParams MAINPARAMS; static PeerGroup peerGroup; static BlockChain blockChain; - + static DualBlockChain dualBlockChain; @BeforeClass public static void startup() throws BlockStoreException { MAINPARAMS = MainNetParams.get(); @@ -48,6 +49,7 @@ private static void initContext(NetworkParameters params, String blockchainFile) blockChain = null; } blockChain = new BlockChain(context, new SPVBlockStore(params, new File(SimplifiedMasternodesTest.class.getResource(blockchainFile).getFile()))); + dualBlockChain = new DualBlockChain(blockChain, blockChain); peerGroup = new PeerGroup(context.getParams(), blockChain, blockChain); context.initDash(true, true); @@ -108,11 +110,11 @@ public void loadQuorumRotationStateFromFile() throws Exception { FlatDB db = new FlatDB<>(Context.get(), datafile.getFile(), true); SimplifiedMasternodeListManager managerDefaultNames = new SimplifiedMasternodeListManager(Context.get()); - managerDefaultNames.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerDefaultNames.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); assertTrue(db.load(managerDefaultNames)); SimplifiedMasternodeListManager managerSpecific = new SimplifiedMasternodeListManager(Context.get()); - managerSpecific.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecific.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db2 = new FlatDB<>(Context.get(), datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 3); assertTrue(db2.load(managerSpecific)); @@ -121,7 +123,7 @@ public void loadQuorumRotationStateFromFile() throws Exception { //load a file with version 3, expecting version 4 SimplifiedMasternodeListManager managerSpecificFail = new SimplifiedMasternodeListManager(Context.get()); - managerSpecificFail.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecificFail.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db3 = new FlatDB<>(Context.get(), datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 4); assertFalse(db3.load(managerSpecificFail)); } @@ -139,11 +141,11 @@ public void loadBasicSchemeQuorumRotationStateFromFile() throws Exception { FlatDB db = new FlatDB(context, datafile.getFile(), true); SimplifiedMasternodeListManager managerDefaultNames = new SimplifiedMasternodeListManager(context); - managerDefaultNames.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerDefaultNames.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); assertTrue(db.load(managerDefaultNames)); SimplifiedMasternodeListManager managerSpecific = new SimplifiedMasternodeListManager(context); - managerSpecific.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecific.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db2 = new FlatDB(context, datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 4); assertTrue(db2.load(managerSpecific)); @@ -152,7 +154,7 @@ public void loadBasicSchemeQuorumRotationStateFromFile() throws Exception { //load a file with version 3, expecting version 4 SimplifiedMasternodeListManager managerSpecificFail = new SimplifiedMasternodeListManager(context); - managerSpecificFail.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecificFail.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db3 = new FlatDB<>(context, datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 5); assertFalse(db3.load(managerSpecificFail)); } @@ -169,11 +171,11 @@ public void loadQuorumRotationStateFromFile_70227_v3() throws Exception { FlatDB db = new FlatDB(context, datafile.getFile(), true); SimplifiedMasternodeListManager managerDefaultNames = new SimplifiedMasternodeListManager(context); - managerDefaultNames.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerDefaultNames.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); assertTrue(db.load(managerDefaultNames)); SimplifiedMasternodeListManager managerSpecific = new SimplifiedMasternodeListManager(context); - managerSpecific.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecific.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db2 = new FlatDB(context, datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 3); assertTrue(db2.load(managerSpecific)); @@ -182,7 +184,7 @@ public void loadQuorumRotationStateFromFile_70227_v3() throws Exception { //load a file with version 3, expecting version 4 SimplifiedMasternodeListManager managerSpecificFail = new SimplifiedMasternodeListManager(context); - managerSpecificFail.setBlockChain(blockChain, blockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); + managerSpecificFail.setBlockChain(dualBlockChain, null, context.quorumManager, context.quorumSnapshotManager, context.chainLockHandler); FlatDB db3 = new FlatDB<>(context, datafile.getFile(), true, managerSpecific.getDefaultMagicMessage(), 5); assertFalse(db3.load(managerSpecificFail)); } diff --git a/core/src/test/java/org/bitcoinj/wallet/authentication/AuthenticationKeyChainGroupTest.java b/core/src/test/java/org/bitcoinj/wallet/authentication/AuthenticationKeyChainGroupTest.java index 9f62f1ba4..4ba1fd5ab 100644 --- a/core/src/test/java/org/bitcoinj/wallet/authentication/AuthenticationKeyChainGroupTest.java +++ b/core/src/test/java/org/bitcoinj/wallet/authentication/AuthenticationKeyChainGroupTest.java @@ -201,4 +201,14 @@ public void serializationTest() throws UnreadableWalletException { assertEquals(authenticationGroupExtension.currentKey(AuthenticationKeyChain.KeyChainType.MASTERNODE_PLATFORM_OPERATOR), authenticationGroupExtensionCopy.currentKey(AuthenticationKeyChain.KeyChainType.MASTERNODE_PLATFORM_OPERATOR)); } + + @Test + public void encryptionTest() throws UnreadableWalletException { + wallet.encrypt("hello"); + Protos.Wallet protos = new WalletProtobufSerializer().walletToProto(wallet); + AuthenticationGroupExtension authenticationGroupExtensionCopy = new AuthenticationGroupExtension(wallet.getParams()); + Wallet walletCopy = new WalletProtobufSerializer().readWallet(PARAMS, new WalletExtension[]{authenticationGroupExtensionCopy}, protos); + //walletCopy.encrypt("hello"); + walletCopy.decrypt("hello"); + } }