From 16c31bb0d54f95e8c03f8706c1c7ec9c23232f27 Mon Sep 17 00:00:00 2001
From: HashEngineering
Date: Wed, 22 Jan 2025 08:50:35 -0800
Subject: [PATCH] refactor: reduce Context dependencies and replace with
DashSystem (#264)
* refactor: move components from Context to DashSystem
* tests: simplify tests
* refactor: update BuildCheckpoints to use DashSystem
* chore: add TODO comment to SimplifiedMasternodeList.p
* refactor: update WalletTool to use DashSystem
* refactor: add default ctor for DownloadProgressTracker
* refactor: move components from Context to DashSystem
* refactor: update BuildCheckpoints to use DashSystem
* chore: add TODO comment to SimplifiedMasternodeList.p
* refactor: update WalletTool to use DashSystem
* refactor: add default ctor for DownloadProgressTracker
* chore: update run configurations
* feat: add getters to RecoveredSignature
* feat: add lock time to Transaction Report
* fix: account for 0 diff transactions when emitting events
* fix: compile issue on checkCommitment
---
.run/WalletTool CJ Create.run.xml | 2 +-
.run/WalletTool CJ Dump.run.xml | 2 +-
.run/WalletTool CJ Sync.run.xml | 2 +-
.../java/org/bitcoinj/coinjoin/CoinJoin.java | 13 +-
.../coinjoin/CoinJoinBroadcastTx.java | 6 +-
.../coinjoin/CoinJoinClientManager.java | 39 +-
.../coinjoin/CoinJoinClientQueueManager.java | 35 +-
.../coinjoin/CoinJoinClientSession.java | 79 ++--
.../coinjoin/utils/CoinJoinManager.java | 53 ++-
.../coinjoin/utils/MasternodeGroup.java | 36 +-
.../coinjoin/utils/TransactionBuilder.java | 16 +-
.../org/bitcoinj/core/AbstractBlockChain.java | 1 -
.../main/java/org/bitcoinj/core/Context.java | 322 +------------
.../org/bitcoinj/core/MasternodePayments.java | 2 +-
.../org/bitcoinj/core/MasternodeSync.java | 52 ++-
.../src/main/java/org/bitcoinj/core/Peer.java | 172 ++-----
.../java/org/bitcoinj/core/PeerGroup.java | 39 +-
.../java/org/bitcoinj/core/SporkManager.java | 62 ++-
.../listeners/DownloadProgressTracker.java | 9 +-
.../evolution/AbstractQuorumState.java | 30 +-
.../evolution/MasternodeListManager.java | 24 +
.../evolution/QuorumRotationState.java | 30 +-
.../org/bitcoinj/evolution/QuorumState.java | 16 +-
.../evolution/SimplifiedMasternodeList.java | 4 +-
.../SimplifiedMasternodeListManager.java | 60 ++-
.../governance/GovernanceManager.java | 147 ++++--
.../bitcoinj/governance/GovernanceObject.java | 37 +-
.../governance/GovernanceTriggerManager.java | 21 +-
.../bitcoinj/governance/GovernanceVote.java | 15 +-
.../org/bitcoinj/governance/Superblock.java | 8 +-
.../governance/SuperblockManager.java | 46 +-
.../bitcoinj/kits/FullPrunedWalletAppKit.java | 26 +-
.../java/org/bitcoinj/kits/WalletAppKit.java | 50 +-
.../java/org/bitcoinj/manager/DashSystem.java | 430 ++++++++++++++++++
.../masternode/owner/MasternodeControl.java | 37 +-
.../bitcoinj/quorums/ChainLocksHandler.java | 70 ++-
.../org/bitcoinj/quorums/FinalCommitment.java | 18 +-
.../bitcoinj/quorums/InstantSendManager.java | 139 +++++-
.../quorums/LLMQBackgroundThread.java | 33 +-
.../java/org/bitcoinj/quorums/LLMQUtils.java | 13 +-
.../bitcoinj/quorums/RecoveredSignature.java | 20 +
.../org/bitcoinj/quorums/SigningManager.java | 23 +-
.../quorums/SimplifiedQuorumList.java | 19 +-
.../signers/CoinJoinTransactionSigner.java | 8 +-
.../main/java/org/bitcoinj/wallet/Wallet.java | 7 -
.../org/bitcoinj/coinjoin/CoinJoinServer.java | 15 +-
.../coinjoin/CoinJoinSessionTest.java | 69 ++-
.../coinjoin/CoinJoinSignedInputsTest.java | 6 +-
.../coinjoin/TestWithMasternodeGroup.java | 11 +-
.../utils/CoinJoinTransactionTypeTest.java | 2 +-
.../org/bitcoinj/core/BlockChainTest.java | 2 +-
.../core/ChainLockBlockChainTest.java | 17 +-
.../org/bitcoinj/core/ChainSplitTest.java | 1 -
...ilteredBlockAndPartialMerkleTreeTests.java | 2 +-
.../org/bitcoinj/core/SporkMessageTest.java | 5 -
.../evolution/LoadBootstrapFilesTest.java | 9 +-
.../QuorumStateValidateQuorumsTest.java | 13 +-
.../evolution/SimplifiedMasternodesTest.java | 13 +-
.../quorums/ChainLocksHandlerTest.java | 16 +-
.../quorums/QuorumRotationStateTest.java | 37 +-
...uorumRotationStateValidateQuorumsTest.java | 12 +-
.../testing/TestWithNetworkConnections.java | 2 +-
.../org/bitcoinj/testing/TestWithWallet.java | 3 +-
.../bitcoinj/wallet/CoinJoinWalletTest.java | 11 +-
.../bitcoinj/examples/CoinJoinMonitor.java | 4 +-
.../ConvertBootStrapToManagerFile.java | 17 +-
.../bitcoinj/examples/ForwardingService.java | 4 +-
.../examples/FullPrunedForwardingService.java | 2 +-
.../examples/debug/TransactionReport.java | 22 +-
.../org/bitcoinj/tools/BuildCheckpoints.java | 6 +-
.../java/org/bitcoinj/tools/WalletTool.java | 45 +-
71 files changed, 1640 insertions(+), 979 deletions(-)
create mode 100644 core/src/main/java/org/bitcoinj/evolution/MasternodeListManager.java
create mode 100644 core/src/main/java/org/bitcoinj/manager/DashSystem.java
diff --git a/.run/WalletTool CJ Create.run.xml b/.run/WalletTool CJ Create.run.xml
index de02784d62..001aa641e9 100644
--- a/.run/WalletTool CJ Create.run.xml
+++ b/.run/WalletTool CJ Create.run.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/.run/WalletTool CJ Dump.run.xml b/.run/WalletTool CJ Dump.run.xml
index f9f823a15b..4d5dce0b4e 100644
--- a/.run/WalletTool CJ Dump.run.xml
+++ b/.run/WalletTool CJ Dump.run.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/.run/WalletTool CJ Sync.run.xml b/.run/WalletTool CJ Sync.run.xml
index c61cb37f2a..f38b105857 100644
--- a/.run/WalletTool CJ Sync.run.xml
+++ b/.run/WalletTool CJ Sync.run.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoin.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoin.java
index 4b94013cbf..fbb13d095a 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoin.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoin.java
@@ -27,6 +27,7 @@
import org.bitcoinj.core.TransactionConfidence;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutput;
+import org.bitcoinj.quorums.ChainLocksHandler;
import org.bitcoinj.script.ScriptPattern;
import org.bitcoinj.utils.Threading;
import org.slf4j.Logger;
@@ -226,13 +227,13 @@ public static long calculateAmountPriority(Coin inputAmount) {
return -1L * inputAmount.div(Coin.COIN.value).value;
}
- private static void checkDSTXes(StoredBlock block) {
+ private static void checkDSTXes(StoredBlock block, ChainLocksHandler chainLocksHandler) {
mapdstxLock.lock();
try {
Iterator> it = mapDSTX.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
- if (entry.getValue().isExpired(block)) {
+ if (entry.getValue().isExpired(block, chainLocksHandler)) {
it.remove();
}
}
@@ -248,11 +249,11 @@ public static CoinJoinBroadcastTx getDSTX(Sha256Hash hash) {
return mapDSTX.get(hash);
}
- public static void updatedBlockTip(StoredBlock block){
- checkDSTXes(block);
+ public static void updatedBlockTip(StoredBlock block, ChainLocksHandler chainLocksHandler) {
+ checkDSTXes(block, chainLocksHandler);
}
- public static void notifyChainLock(StoredBlock block) {
- checkDSTXes(block);
+ public static void notifyChainLock(StoredBlock block, ChainLocksHandler chainLocksHandler) {
+ checkDSTXes(block, chainLocksHandler);
}
public static void updateDSTXConfirmedHeight(Transaction tx, int nHeight) {
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinBroadcastTx.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinBroadcastTx.java
index efb3675af3..3ad3ed92bf 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinBroadcastTx.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinBroadcastTx.java
@@ -31,6 +31,8 @@
import org.bitcoinj.crypto.BLSPublicKey;
import org.bitcoinj.crypto.BLSSecretKey;
import org.bitcoinj.crypto.BLSSignature;
+import org.bitcoinj.manager.DashSystem;
+import org.bitcoinj.quorums.ChainLocksHandler;
import org.bitcoinj.script.ScriptPattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -149,12 +151,12 @@ public void setConfirmedHeight(int confirmedHeight) {
this.confirmedHeight = confirmedHeight;
}
- public boolean isExpired(StoredBlock block) {
+ public boolean isExpired(StoredBlock block, ChainLocksHandler chainLocksHandler) {
// expire confirmed DSTXes after ~1h since confirmation or chainlocked confirmation
if (confirmedHeight == -1 || block.getHeight() < confirmedHeight) return false; // not mined yet
if (block.getHeight() - confirmedHeight > 24) return true; // mined more than an hour ago
// TODO: this may crash
- return Context.get().chainLockHandler.hasChainLock(block.getHeight(), block.getHeader().getHash());
+ return chainLocksHandler.hasChainLock(block.getHeight(), block.getHeader().getHash());
}
public boolean isValidStructure() {
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientManager.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientManager.java
index a561e948e8..c318afbbdf 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientManager.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientManager.java
@@ -22,6 +22,7 @@
import org.bitcoinj.coinjoin.listeners.MixingStartedListener;
import org.bitcoinj.coinjoin.listeners.SessionCompleteListener;
import org.bitcoinj.coinjoin.listeners.SessionStartedListener;
+import org.bitcoinj.coinjoin.utils.CoinJoinManager;
import org.bitcoinj.core.AbstractBlockChain;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Context;
@@ -36,8 +37,10 @@
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.MasternodeMetaDataManager;
import org.bitcoinj.evolution.SimplifiedMasternodeList;
import org.bitcoinj.evolution.SimplifiedMasternodeListEntry;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.Wallet;
@@ -88,6 +91,10 @@ public class CoinJoinClientManager implements WalletCoinsReceivedEventListener {
private String strAutoDenomResult = "";
private final Context context;
+ private final MasternodeSync masternodeSync;
+ private final CoinJoinManager coinJoinManager;
+ private final SimplifiedMasternodeListManager masternodeListManager;
+ private final MasternodeMetaDataManager masternodeMetaDataManager;
private final WalletEx mixingWallet;
// Keep track of current block height
@@ -104,8 +111,8 @@ public class CoinJoinClientManager implements WalletCoinsReceivedEventListener {
= new CopyOnWriteArrayList<>();
private boolean waitForAnotherBlock() {
- if (context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) &&
- !mixingWallet.getContext().masternodeSync.isBlockchainSynced()) return true;
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) &&
+ !masternodeSync.isBlockchainSynced()) return true;
if (CoinJoinClientOptions.isMultiSessionEnabled()) return false;
@@ -124,23 +131,31 @@ private boolean checkAutomaticBackup() {
public int cachedNumBlocks = Integer.MAX_VALUE; // used for the overview screen
- public CoinJoinClientManager(Wallet wallet) {
+ public CoinJoinClientManager(Wallet wallet, MasternodeSync masternodeSync, CoinJoinManager coinJoinManager, SimplifiedMasternodeListManager masternodeListManager, MasternodeMetaDataManager masternodeMetaDataManager) {
checkArgument(wallet instanceof WalletEx);
mixingWallet = (WalletEx) wallet;
context = wallet.getContext();
+ this.masternodeSync = masternodeSync;
+ this.coinJoinManager = coinJoinManager;
+ this.masternodeMetaDataManager = masternodeMetaDataManager;
+ this.masternodeListManager = masternodeListManager;
mixingWallet.addCoinsReceivedEventListener(this);
}
- public CoinJoinClientManager(WalletEx wallet) {
+ public CoinJoinClientManager(WalletEx wallet, MasternodeSync masternodeSync, CoinJoinManager coinJoinManager, SimplifiedMasternodeListManager masternodeListManager, MasternodeMetaDataManager masternodeMetaDataManager) {
mixingWallet = wallet;
context = wallet.getContext();
+ this.masternodeSync = masternodeSync;
+ this.coinJoinManager = coinJoinManager;
+ this.masternodeMetaDataManager = masternodeMetaDataManager;
+ this.masternodeListManager = masternodeListManager;
mixingWallet.addCoinsReceivedEventListener(this);
}
public void processMessage(Peer from, Message message, boolean enable_bip61) {
if (!CoinJoinClientOptions.isEnabled())
return;
- if (context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) && !context.masternodeSync.isBlockchainSynced())
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) && !masternodeSync.isBlockchainSynced())
return;
if (message instanceof CoinJoinStatusUpdate ||
@@ -225,17 +240,17 @@ public boolean doAutomaticDenominating(boolean dryRun) {
if (!CoinJoinClientOptions.isEnabled() || (!dryRun && !isMixing()))
return false;
- if (context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) && !mixingWallet.getContext().masternodeSync.isBlockchainSynced()) {
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) && !masternodeSync.isBlockchainSynced()) {
strAutoDenomResult = "Can't mix while sync in progress.";
return false;
}
- if (!dryRun && mixingWallet.isEncrypted() && context.coinJoinManager.requestKeyParameter(mixingWallet) == null) {
+ if (!dryRun && mixingWallet.isEncrypted() && coinJoinManager.requestKeyParameter(mixingWallet) == null) {
strAutoDenomResult = "Wallet is locked.";
return false;
}
- int mnCountEnabled = context.masternodeListManager.getListAtChainTip().getValidMNsCount();
+ int mnCountEnabled = masternodeListManager.getListAtChainTip().getValidMNsCount();
// If we've used 90% of the Masternode list then drop the oldest first ~30%
int thresholdHigh = (int) (mnCountEnabled * 0.9);
@@ -274,7 +289,7 @@ public boolean doAutomaticDenominating(boolean dryRun) {
lock.lock();
try {
if (deqSessions.size() < CoinJoinClientOptions.getSessions()) {
- CoinJoinClientSession newSession = new CoinJoinClientSession(mixingWallet);
+ CoinJoinClientSession newSession = new CoinJoinClientSession(mixingWallet, coinJoinManager, masternodeListManager, masternodeMetaDataManager, masternodeSync);
log.info("creating new session: {}: ", newSession.getId());
for (ListenerRegistration listener : sessionCompleteListeners) {
newSession.addSessionCompleteListener(listener.executor, listener.listener);
@@ -378,7 +393,7 @@ public void addUsedMasternode(Sha256Hash proTxHash) {
masternodesUsed.add(proTxHash);
}
public Masternode getRandomNotUsedMasternode() {
- SimplifiedMasternodeList mnList = context.masternodeListManager.getListAtChainTip();
+ SimplifiedMasternodeList mnList = masternodeListManager.getListAtChainTip();
int nCountEnabled = mnList.getValidMNsCount();
int nCountNotExcluded = nCountEnabled - masternodesUsed.size();
@@ -443,8 +458,8 @@ public void doMaintenance() {
if (!CoinJoinClientOptions.isEnabled())
return;
- if (context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)
- &&!context.masternodeSync.isBlockchainSynced())
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)
+ &&!masternodeSync.isBlockchainSynced())
return;
nTick++;
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientQueueManager.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientQueueManager.java
index 73ae24bf70..c3c385958f 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientQueueManager.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientQueueManager.java
@@ -15,13 +15,16 @@
*/
package org.bitcoinj.coinjoin;
+import org.bitcoinj.coinjoin.utils.CoinJoinManager;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.MasternodeSync;
import org.bitcoinj.core.Peer;
import org.bitcoinj.core.Sha256Hash;
import org.bitcoinj.core.Utils;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.MasternodeMetaDataManager;
import org.bitcoinj.evolution.SimplifiedMasternodeList;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -32,11 +35,19 @@
public class CoinJoinClientQueueManager extends CoinJoinBaseManager {
private final Context context;
+ private final CoinJoinManager coinJoinManager;
+ private final SimplifiedMasternodeListManager masternodeListManager;
+ private final MasternodeMetaDataManager masternodeMetaDataManager;
+ private final MasternodeSync masternodeSync;
private final Logger log = LoggerFactory.getLogger(CoinJoinClientManager.class);
private final HashMap spammingMasternodes = new HashMap();
- public CoinJoinClientQueueManager(Context context) {
+ public CoinJoinClientQueueManager(Context context, CoinJoinManager coinJoinManager, SimplifiedMasternodeListManager masternodeListManager, MasternodeMetaDataManager masternodeMetaDataManager, MasternodeSync masternodeSync) {
super();
+ this.coinJoinManager = coinJoinManager;
+ this.masternodeListManager = masternodeListManager;
+ this.masternodeMetaDataManager = masternodeMetaDataManager;
+ this.masternodeSync = masternodeSync;
this.context = context;
}
@@ -69,7 +80,7 @@ public void processDSQueue(Peer from, CoinJoinQueue dsq, boolean enable_bip61) {
if (dsq.isTimeOutOfBounds())
return;
- SimplifiedMasternodeList mnList = context.masternodeListManager.getListAtChainTip();
+ SimplifiedMasternodeList mnList = masternodeListManager.getListAtChainTip();
Masternode dmn = mnList.getMN(dsq.getProTxHash());
if (dmn == null)
return;
@@ -83,12 +94,12 @@ public void processDSQueue(Peer from, CoinJoinQueue dsq, boolean enable_bip61) {
if (dsq.isReady() && isTrySubmitDenominate(dmn)) {
log.info("coinjoin: DSQUEUE: {} is ready on masternode {}", dsq, dmn.getService());
} else {
- long nLastDsq = context.masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
- long nDsqThreshold = context.masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), mnList.getValidMNsCount());
+ long nLastDsq = masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
+ long nDsqThreshold = masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), mnList.getValidMNsCount());
log.info(COINJOIN_EXTRA, "coinjoin: DSQUEUE -- lastDsq: {} dsqThreshold: {} dsqCount: {}",
- nLastDsq, nDsqThreshold, context.masternodeMetaDataManager.getDsqCount());
+ nLastDsq, nDsqThreshold, masternodeMetaDataManager.getDsqCount());
// don't allow a few nodes to dominate the queuing process
- if (nLastDsq != 0 && nDsqThreshold > context.masternodeMetaDataManager.getDsqCount()) {
+ if (nLastDsq != 0 && nDsqThreshold > masternodeMetaDataManager.getDsqCount()) {
if (!spammingMasternodes.containsKey(dsq.getProTxHash())) {
spammingMasternodes.put(dsq.getProTxHash(), Utils.currentTimeMillis());
log.info(COINJOIN_EXTRA, "coinjoin: DSQUEUE: Masternode {} is sending too many dsq messages", dmn.getProTxHash());
@@ -96,11 +107,11 @@ public void processDSQueue(Peer from, CoinJoinQueue dsq, boolean enable_bip61) {
return;
}
- context.masternodeMetaDataManager.allowMixing(dmn.getProTxHash());
+ masternodeMetaDataManager.allowMixing(dmn.getProTxHash());
log.info("coinjoin: DSQUEUE: new {} from masternode {}", dsq, dmn.getService().getAddr());
- context.coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate() {
+ coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate() {
@Override
public boolean test(CoinJoinClientManager coinJoinClientManager) {
return coinJoinClientManager.markAlreadyJoinedQueueAsTried(dsq);
@@ -119,7 +130,7 @@ public boolean test(CoinJoinClientManager coinJoinClientManager) {
}
private boolean isTrySubmitDenominate(Masternode dmn) {
- return context.coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate() {
+ return coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate() {
@Override
public boolean test(CoinJoinClientManager coinJoinClientManager) {
return coinJoinClientManager.trySubmitDenominate(dmn.getService());
@@ -131,11 +142,11 @@ public void doMaintenance() {
if (!CoinJoinClientOptions.isEnabled())
return;
- if (context.masternodeSync == null)
+ if (masternodeSync == null)
return;
- if (context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) &&
- !context.masternodeSync.isBlockchainSynced())
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) &&
+ !masternodeSync.isBlockchainSynced())
return;
checkQueue();
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java
index 96d11c473f..9180330530 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientSession.java
@@ -19,6 +19,7 @@
import org.bitcoinj.coinjoin.listeners.CoinJoinTransactionListener;
import org.bitcoinj.coinjoin.listeners.SessionCompleteListener;
import org.bitcoinj.coinjoin.listeners.SessionStartedListener;
+import org.bitcoinj.coinjoin.utils.CoinJoinManager;
import org.bitcoinj.coinjoin.utils.CoinJoinTransactionType;
import org.bitcoinj.coinjoin.utils.CompactTallyItem;
import org.bitcoinj.coinjoin.utils.KeyHolderStorage;
@@ -42,7 +43,9 @@
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.core.Utils;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.MasternodeMetaDataManager;
import org.bitcoinj.evolution.SimplifiedMasternodeList;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.bitcoinj.script.ScriptException;
@@ -110,6 +113,10 @@ public class CoinJoinClientSession extends CoinJoinBaseSession {
private final KeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate
+ private final MasternodeSync masternodeSync;
+ private final CoinJoinManager coinJoinManager;
+ private final SimplifiedMasternodeListManager masternodeListManager;
+ private final MasternodeMetaDataManager masternodeMetaDataManager;
private final WalletEx mixingWallet;
private final AtomicBoolean hasNothingToDo = new AtomicBoolean(false); // is mixing finished?
@@ -198,7 +205,7 @@ private boolean createDenominated(Coin balanceToDenominate, CompactTallyItem tal
return false;
}
- try (TransactionBuilder txBuilder = new TransactionBuilder(mixingWallet, tallyItem, dryRun)) {
+ try (TransactionBuilder txBuilder = new TransactionBuilder(mixingWallet, coinJoinManager, tallyItem, dryRun)) {
log.info("coinjoin: Start {}", txBuilder);
// ****** Add an output for mixing collaterals ************ /
@@ -376,7 +383,7 @@ public int process(Coin amount) {
}
// use the same nCachedLastSuccessBlock as for DS mixing to prevent race
- mixingWallet.getContext().coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).updatedSuccessBlock();
+ coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).updatedSuccessBlock();
log.info("coinjoin: txid: {}", strResult);
@@ -447,7 +454,7 @@ private boolean makeCollateralAmounts(CompactTallyItem tallyItem, boolean fTryDe
return false;
}
- try (TransactionBuilder txBuilder = new TransactionBuilder(wallet, tallyItem, false)) {
+ try (TransactionBuilder txBuilder = new TransactionBuilder(wallet, coinJoinManager, tallyItem, false)) {
log.info("coinjoin: Start {}", txBuilder);
// Skip way too tiny amounts. Smallest we want is minimum collateral amount in a one output tx
@@ -508,7 +515,7 @@ private boolean makeCollateralAmounts(CompactTallyItem tallyItem, boolean fTryDe
return false;
}
- mixingWallet.getContext().coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).updatedSuccessBlock();
+ coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).updatedSuccessBlock();
log.info("coinjoin: txid: {}", strResult);
queueTransactionListeners(txBuilder.getTransaction(), CoinJoinTransactionType.MakeCollateralInputs);
@@ -558,7 +565,7 @@ private boolean createCollateralTransaction(Transaction txCollateral, StringBuil
// otherwise when the masternodes do submit these transactions to the network, they will be
// ignored by DashJ and when they are received
SendRequest req = SendRequest.forTx(txCollateral);
- req.aesKey = context.coinJoinManager.requestKeyParameter(mixingWallet);
+ req.aesKey = coinJoinManager.requestKeyParameter(mixingWallet);
mixingWallet.signTransaction(req);
} catch (ScriptException x) {
strReason.append("Unable to sign collateral transaction!");
@@ -573,15 +580,15 @@ private boolean createCollateralTransaction(Transaction txCollateral, StringBuil
private boolean joinExistingQueue(Coin balanceNeedsAnonymized) {
if (!CoinJoinClientOptions.isEnabled()) return false;
- if (mixingWallet.getContext().coinJoinManager.getCoinJoinClientQueueManager() == null) return false;
+ if (coinJoinManager.getCoinJoinClientQueueManager() == null) return false;
- SimplifiedMasternodeList mnList = mixingWallet.getContext().masternodeListManager.getListAtChainTip();
+ SimplifiedMasternodeList mnList = masternodeListManager.getListAtChainTip();
// Dash Core checks for recent winners, but we cannot do that
// Look through the queues and see if anything matches
CoinJoinQueue dsq;
- while ((dsq = mixingWallet.getContext().coinJoinManager.getCoinJoinClientQueueManager().getQueueItemAndTry()) != null) {
+ while ((dsq = coinJoinManager.getCoinJoinClientQueueManager().getQueueItemAndTry()) != null) {
Masternode dmn = mnList.getMN(dsq.getProTxHash());
if (dmn == null) {
@@ -603,9 +610,9 @@ private boolean joinExistingQueue(Coin balanceNeedsAnonymized) {
continue;
}
- mixingWallet.getContext().coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).addUsedMasternode(dsq.getProTxHash());
+ coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).addUsedMasternode(dsq.getProTxHash());
- if (mixingWallet.getContext().coinJoinManager.isMasternodeOrDisconnectRequested(dmn.getService())) {
+ if (coinJoinManager.isMasternodeOrDisconnectRequested(dmn.getService())) {
log.info("coinjoin: skipping masternode connection, addr={}", dmn.getService());
continue;
}
@@ -613,7 +620,7 @@ private boolean joinExistingQueue(Coin balanceNeedsAnonymized) {
sessionDenom = dsq.getDenomination();
mixingMasternode = dmn;
pendingDsaRequest = new PendingDsaRequest(dmn.getService(), new CoinJoinAccept(mixingWallet.getContext().getParams(), sessionDenom, txMyCollateral));
- mixingWallet.getContext().coinJoinManager.addPendingMasternode(this);
+ coinJoinManager.addPendingMasternode(this);
setState(POOL_STATE_QUEUE);
timeLastSuccessfulStep.set(Utils.currentTimeSeconds());
log.info("coinjoin: join existing queue -> pending connection, denom: {} ({}), addr={}",
@@ -633,7 +640,7 @@ private boolean startNewQueue(Coin balanceNeedsAnonymized) {
return false;
int nTries = 0;
- SimplifiedMasternodeList mnList = context.masternodeListManager.getListAtChainTip();
+ SimplifiedMasternodeList mnList = masternodeListManager.getListAtChainTip();
int nMnCount = mnList.getValidMNsCount();
// find available denominated amounts
@@ -649,27 +656,27 @@ private boolean startNewQueue(Coin balanceNeedsAnonymized) {
// otherwise, try one randomly
while (nTries < 10) {
- Masternode dmn = context.coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).getRandomNotUsedMasternode();
+ Masternode dmn = coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).getRandomNotUsedMasternode();
if (dmn == null) {
setStatus(PoolStatus.ERR_MASTERNODE_NOT_FOUND);
return false;
}
- context.coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).addUsedMasternode(dmn.getProTxHash());
+ coinJoinManager.coinJoinClientManagers.get(mixingWallet.getDescription()).addUsedMasternode(dmn.getProTxHash());
- long nLastDsq = context.masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
- long nDsqThreshold = context.masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), nMnCount);
- if (nLastDsq != 0 && nDsqThreshold > context.masternodeMetaDataManager.getDsqCount()) {
+ long nLastDsq = masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
+ long nDsqThreshold = masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), nMnCount);
+ if (nLastDsq != 0 && nDsqThreshold > masternodeMetaDataManager.getDsqCount()) {
log.info("coinjoin: warning: Too early to mix on this masternode!" + /* Continued */
" masternode={} addr={} nLastDsq={} nDsqThreshold={} nDsqCount={}",
dmn.getProTxHash(), dmn.getService(), nLastDsq,
- nDsqThreshold, context.masternodeMetaDataManager.getDsqCount());
+ nDsqThreshold, masternodeMetaDataManager.getDsqCount());
nTries++;
continue;
}
- if (context.coinJoinManager.isMasternodeOrDisconnectRequested(dmn.getService())) {
+ if (coinJoinManager.isMasternodeOrDisconnectRequested(dmn.getService())) {
log.info("coinjoin: warning: skipping masternode connection, addr={}", dmn.getService());
nTries++;
continue;
@@ -688,13 +695,13 @@ private boolean startNewQueue(Coin balanceNeedsAnonymized) {
}
mixingMasternode = dmn;
- context.coinJoinManager.addPendingMasternode(this);
+ coinJoinManager.addPendingMasternode(this);
pendingDsaRequest = new PendingDsaRequest(dmn.getService(), new CoinJoinAccept(context.getParams(), sessionDenom, txMyCollateral));
setState(POOL_STATE_QUEUE);
timeLastSuccessfulStep.set(Utils.currentTimeSeconds());
log.info("coinjoin: start new queue -> pending connection, nSessionDenom: {} ({}), addr={}",
sessionDenom, CoinJoin.denominationToString(sessionDenom), dmn.getService());
- context.coinJoinManager.startAsync();
+ coinJoinManager.startAsync();
setStatus(PoolStatus.CONNECTING);
joined = false;
return true;
@@ -708,7 +715,7 @@ private boolean selectDenominate(StringBuilder strErrorRet, List schedule;
private AbstractBlockChain blockChain;
@@ -78,10 +90,16 @@ public class CoinJoinManager {
private RequestDecryptedKey requestDecryptedKey;
private final ScheduledExecutorService scheduledExecutorService;
- public CoinJoinManager(Context context, ScheduledExecutorService scheduledExecutorService) {
+ public CoinJoinManager(Context context, ScheduledExecutorService scheduledExecutorService,
+ SimplifiedMasternodeListManager masternodeListManager,
+ MasternodeMetaDataManager masternodeMetaDataManager,
+ MasternodeSync masternodeSync,
+ ChainLocksHandler chainLocksHandler) {
this.context = context;
coinJoinClientManagers = new HashMap<>();
- coinJoinClientQueueManager = new CoinJoinClientQueueManager(context);
+ this.masternodeListManager = masternodeListManager;
+ this.chainLocksHandler = chainLocksHandler;
+ coinJoinClientQueueManager = new CoinJoinClientQueueManager(context, this, masternodeListManager, masternodeMetaDataManager, masternodeSync);
this.scheduledExecutorService = scheduledExecutorService;
}
@@ -159,7 +177,7 @@ public void stop() {
for (CoinJoinClientManager clientManager: coinJoinClientManagers.values()) {
clientManager.resetPool();
clientManager.stopMixing();
- clientManager.close(context.blockChain);
+ clientManager.close(blockChain);
}
stopAsync();
}
@@ -170,7 +188,7 @@ public boolean isRunning() {
public void initMasternodeGroup(AbstractBlockChain blockChain) {
this.blockChain = blockChain;
- masternodeGroup = new MasternodeGroup(context, blockChain);
+ masternodeGroup = new MasternodeGroup(context, blockChain, masternodeListManager);
masternodeGroup.setCoinJoinManager(this);
blockChain.addTransactionReceivedListener(transactionReceivedInBlockListener);
}
@@ -178,7 +196,7 @@ public void initMasternodeGroup(AbstractBlockChain blockChain) {
NewBestBlockListener newBestBlockListener = new NewBestBlockListener() {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
- CoinJoin.updatedBlockTip(block);
+ CoinJoin.updatedBlockTip(block, chainLocksHandler);
}
};
@@ -194,9 +212,13 @@ public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block,
}
};
- public void setBlockchain(AbstractBlockChain blockChain) {
+ public void setBlockchain(AbstractBlockChain blockChain, PeerGroup peerGroup) {
this.blockChain = blockChain;
+ this.peerGroup = peerGroup;
blockChain.addNewBestBlockListener(newBestBlockListener);
+ if (peerGroup != null) {
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
}
public void close() {
@@ -204,6 +226,9 @@ public void close() {
blockChain.removeNewBestBlockListener(newBestBlockListener);
blockChain.removeTransactionReceivedListener(transactionReceivedInBlockListener);
}
+ if (peerGroup != null) {
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
+ }
}
public boolean isMasternodeOrDisconnectRequested(MasternodeAddress address) {
@@ -221,15 +246,15 @@ public boolean forPeer(MasternodeAddress address, MasternodeGroup.ForPeer forPee
public void startAsync() {
if (!masternodeGroup.isRunning()) {
log.info("coinjoin: broadcasting senddsq(true) to all peers");
- context.peerGroup.shouldSendDsq(true);
+ peerGroup.shouldSendDsq(true);
masternodeGroup.startAsync();
}
}
public void stopAsync() {
if (masternodeGroup != null && masternodeGroup.isRunning()) {
- if (context.peerGroup != null)
- context.peerGroup.shouldSendDsq(false);
+ if (peerGroup != null)
+ peerGroup.shouldSendDsq(false);
masternodeGroup.stopAsync();
masternodeGroup = null;
}
@@ -416,4 +441,12 @@ public boolean isMixing() {
public void processTransaction(Transaction tx) {
coinJoinClientManagers.values().forEach(coinJoinClientManager -> coinJoinClientManager.processTransaction(tx));
}
+
+ public final PreMessageReceivedEventListener preMessageReceivedEventListener = (peer, m) -> {
+ if (isCoinJoinMessage(m)) {
+ processMessage(peer, m);
+ return null;
+ }
+ return m;
+ };
}
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/utils/MasternodeGroup.java b/core/src/main/java/org/bitcoinj/coinjoin/utils/MasternodeGroup.java
index dc3a653e06..6074ba86b4 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/utils/MasternodeGroup.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/utils/MasternodeGroup.java
@@ -35,6 +35,8 @@
import org.bitcoinj.core.VerificationException;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.MasternodeListManager;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.net.ClientConnectionManager;
import org.bitcoinj.net.discovery.PeerDiscovery;
import org.bitcoinj.net.discovery.PeerDiscoveryException;
@@ -68,6 +70,7 @@ public class MasternodeGroup extends PeerGroup implements NewBestBlockListener {
protected final HashMap masternodeMap = new HashMap<>();
protected final HashMap addressMap = new HashMap<>();
+ private MasternodeListManager masternodeListManager;
private final ArrayList pendingClosingMasternodes = new ArrayList<>();
private final PeerDiscovery masternodeDiscovery = new PeerDiscovery() {
@@ -116,27 +119,14 @@ public MasternodeGroup(Context context) {
super(context);
}
- /**
- * See {@link #MasternodeGroup(Context, AbstractBlockChain)}
- *
- * @param params
- * @param chain
- */
public MasternodeGroup(NetworkParameters params, @Nullable AbstractBlockChain chain) {
super(params, chain);
- init();
+ init(null);
}
- /**
- * See {@link #MasternodeGroup(Context, AbstractBlockChain)}
- *
- * @param params
- * @param chain
- * @param headerChain
- */
public MasternodeGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, @Nullable AbstractBlockChain headerChain) {
super(params, chain, headerChain);
- init();
+ init(null);
}
/**
@@ -146,12 +136,13 @@ public MasternodeGroup(NetworkParameters params, @Nullable AbstractBlockChain ch
* @param context
* @param chain
*/
- public MasternodeGroup(Context context, @Nullable AbstractBlockChain chain) {
+ public MasternodeGroup(Context context, @Nullable AbstractBlockChain chain, SimplifiedMasternodeListManager masternodeListManager) {
super(context, chain, false);
- init();
+ init(masternodeListManager);
}
- private void init() {
+ private void init(MasternodeListManager masternodeListManager) {
+ this.masternodeListManager = masternodeListManager;
addPeerDiscovery(masternodeDiscovery);
setUseLocalhostPeerWhenPossible(false);
setDropPeersAfterBroadcast(false);
@@ -165,9 +156,10 @@ private void init() {
* @param chain
* @param connectionManager
*/
- public MasternodeGroup(NetworkParameters params, @Nullable AbstractBlockChain chain, ClientConnectionManager connectionManager) {
+ public MasternodeGroup(NetworkParameters params, @Nullable AbstractBlockChain chain,
+ MasternodeListManager masternodeListManager, ClientConnectionManager connectionManager) {
super(params, chain, connectionManager);
- init();
+ init(masternodeListManager);
}
public boolean addPendingMasternode(CoinJoinClientSession session) {
@@ -315,7 +307,7 @@ protected Peer connectTo(PeerAddress address, boolean incrementMaxConnections, i
return null; // do not connect to the same peer again
}
- Masternode mn = context.masternodeListManager.getListAtChainTip().getMNByAddress(address.getSocketAddress());
+ Masternode mn = masternodeListManager.getListAtChainTip().getMNByAddress(address.getSocketAddress());
CoinJoinClientSession session;
pendingMasternodesLock.lock();
@@ -386,7 +378,7 @@ private void checkMasternodesWithoutSessions() {
}
log.info("need to drop {} masternodes", masternodesToDrop.size());
masternodesToDrop.forEach(peer -> {
- Masternode mn = context.masternodeListManager.getListAtChainTip().getMNByAddress(peer.getAddress().getSocketAddress());
+ Masternode mn = masternodeListManager.getListAtChainTip().getMNByAddress(peer.getAddress().getSocketAddress());
//pendingSessions.remove(mn.getProTxHash());
log.info("masternode will be disconnected: {}: {}", peer, mn.getProTxHash());
peer.close();
diff --git a/core/src/main/java/org/bitcoinj/coinjoin/utils/TransactionBuilder.java b/core/src/main/java/org/bitcoinj/coinjoin/utils/TransactionBuilder.java
index 0bdfd9198f..92dd2aa15c 100644
--- a/core/src/main/java/org/bitcoinj/coinjoin/utils/TransactionBuilder.java
+++ b/core/src/main/java/org/bitcoinj/coinjoin/utils/TransactionBuilder.java
@@ -42,6 +42,7 @@
import static com.google.common.base.Preconditions.checkState;
public class TransactionBuilder implements AutoCloseable {
+ private final CoinJoinManager coinJoinManager;
/// Wallet the transaction will be build for
private final WalletEx wallet;
/// See CTransactionBuilder() for initialization
@@ -69,8 +70,9 @@ public class TransactionBuilder implements AutoCloseable {
private Transaction transaction;
- public TransactionBuilder(WalletEx wallet, final CompactTallyItem tallyItem, boolean dryRun) {
+ public TransactionBuilder(WalletEx wallet, CoinJoinManager coinJoinManager, final CompactTallyItem tallyItem, boolean dryRun) {
this.dryRun = dryRun;
+ this.coinJoinManager = coinJoinManager;
this.wallet = wallet;
dummyReserveDestination = new ReserveDestination(wallet);
this.tallyItem = tallyItem;
@@ -94,7 +96,7 @@ public TransactionBuilder(WalletEx wallet, final CompactTallyItem tallyItem, boo
ECKey secret = new ECKey();
Script dummyScript = ScriptBuilder.createP2PKHOutputScript(secret);
// Calculate required bytes for the dummy signed tx with tallyItem's inputs only
- bytesBase = calculateMaximumSignedTxSize(dummyTx, wallet, false);
+ bytesBase = calculateMaximumSignedTxSize(dummyTx, wallet, coinJoinManager, false);
// Calculate the output size
bytesOutput = new TransactionOutput(wallet.getParams(), null, Coin.ZERO, dummyScript.getProgram()).getMessageSize();
@@ -178,7 +180,7 @@ public boolean commit(StringBuilder strResult) {
try {
SendRequest request = SendRequest.forTx(req.tx);
- request.aesKey = wallet.getContext().coinJoinManager.requestKeyParameter(wallet);
+ request.aesKey = coinJoinManager.requestKeyParameter(wallet);
request.coinControl = coinControl;
wallet.sendCoins(request);
transaction = request.tx;
@@ -280,7 +282,7 @@ int getSizeOfCompactSizeDiff(int oldSize, int newSize) {
return VarInt.sizeOf(oldSize) - VarInt.sizeOf(newSize);
}
- static int calculateMaximumSignedTxSize(Transaction tx, Wallet wallet, boolean useMaxSig)
+ static int calculateMaximumSignedTxSize(Transaction tx, Wallet wallet, CoinJoinManager coinJoinManager, boolean useMaxSig)
{
ArrayList txouts = Lists.newArrayList();
for (TransactionInput input : tx.getInputs()) {
@@ -292,18 +294,18 @@ static int calculateMaximumSignedTxSize(Transaction tx, Wallet wallet, boolean u
checkState(input.getOutpoint().getIndex() < mi.getOutputs().size());
txouts.add(mi.getOutput(input.getOutpoint().getIndex()));
}
- return calculateMaximumSignedTxSize(tx, wallet, txouts, useMaxSig);
+ return calculateMaximumSignedTxSize(tx, wallet, coinJoinManager, txouts, useMaxSig);
}
// txouts needs to be in the order of tx.vin
- static int calculateMaximumSignedTxSize(Transaction tx, Wallet wallet, List txouts, boolean useMaxSig)
+ static int calculateMaximumSignedTxSize(Transaction tx, Wallet wallet, CoinJoinManager coinJoinManager, List txouts, boolean useMaxSig)
{
SendRequest req = SendRequest.forTx(tx);
for (TransactionOutput output : txouts) {
ECKey key = wallet.findKeyFromPubKeyHash(ScriptPattern.extractHashFromP2PKH(output.getScriptPubKey()), Script.ScriptType.P2PKH);
checkState(key != null, "there must be a key for this output");
if (key.isEncrypted()) {
- key = wallet.getContext().coinJoinManager.requestDecryptKey(key);
+ key = coinJoinManager.requestDecryptKey(key);
}
req.tx.addSignedInputNoOutputsCheck(output.getOutPointFor(),output.getScriptPubKey(), key, Transaction.SigHash.ALL, false);
diff --git a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java
index 231ad8434e..338465622d 100644
--- a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java
+++ b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java
@@ -905,7 +905,6 @@ protected void setChainHead(StoredBlock chainHead) throws BlockStoreException {
synchronized (chainHeadLock) {
this.chainHead = chainHead;
}
- Context.get().updatedChainHead(chainHead);
}
/**
diff --git a/core/src/main/java/org/bitcoinj/core/Context.java b/core/src/main/java/org/bitcoinj/core/Context.java
index b0b4b73c5c..ae0e47807b 100644
--- a/core/src/main/java/org/bitcoinj/core/Context.java
+++ b/core/src/main/java/org/bitcoinj/core/Context.java
@@ -75,36 +75,8 @@ public class Context {
final private Coin feePerKb;
//Dash Specific
- private boolean liteMode = true;
- private boolean allowInstantX = true; //allow InstantX in litemode
private boolean debugMode = false;
- public PeerGroup peerGroup;
- public AbstractBlockChain blockChain;
- @Nullable public AbstractBlockChain headerChain;
- public SporkManager sporkManager;
- public MasternodePayments masternodePayments;
- public MasternodeSync masternodeSync;
- public HashStore hashStore;
- public GovernanceManager governanceManager;
- public GovernanceTriggerManager triggerManager;
- public NetFullfilledRequestManager netFullfilledRequestManager;
- public SimplifiedMasternodeListManager masternodeListManager;
private VoteConfidenceTable voteConfidenceTable;
- private InstantSendDatabase instantSendDB;
- public InstantSendManager instantSendManager;
- public SigningManager signingManager;
- public QuorumManager quorumManager;
- public QuorumSnapshotManager quorumSnapshotManager;
- private RecoveredSignaturesDatabase recoveredSigsDB;
- public ChainLocksHandler chainLockHandler;
- private LLMQBackgroundThread llmqBackgroundThread;
- public MasternodeMetaDataManager masternodeMetaDataManager;
-
- public CoinJoinManager coinJoinManager;
- private final ScheduledExecutorService scheduledExecutorService;
- private ScheduledFuture> scheduledMasternodeSync;
- private ScheduledFuture> scheduledNetFulfilled;
- private ScheduledFuture> scheduledGovernance;
/**
@@ -134,7 +106,6 @@ public Context(NetworkParameters params, int eventHorizon, Coin feePerKb, boolea
this.ensureMinRequiredFee = ensureMinRequiredFee;
this.feePerKb = feePerKb;
lastConstructed = this;
- scheduledExecutorService = Executors.newScheduledThreadPool(2, new ContextPropagatingThreadFactory("context-thread-pool"));
slot.set(this);
BLSJniLibrary.init(false);
}
@@ -239,249 +210,7 @@ public int getEventHorizon() {
return eventHorizon;
}
- //
- // Dash Specific
- //
- private boolean initializedObjects = false;
- private boolean initializedFiles = false;
- @Deprecated
- public boolean isInitializedDash() {
- return initializedObjects;
- }
-
- public void initDash(boolean liteMode, boolean allowInstantX) {
- initDash(liteMode, allowInstantX, null);
- }
-
- public void initDash(boolean liteMode, boolean allowInstantX, @Nullable EnumSet syncFlags) {
- initDash(liteMode, allowInstantX, syncFlags, null);
- }
- public void initDash(boolean liteMode, boolean allowInstantX, @Nullable EnumSet syncFlags,
- @Nullable EnumSet verifyFlags) {
-
- this.liteMode = liteMode;
- this.allowInstantX = allowInstantX;
-
- //Dash Specific
- sporkManager = new SporkManager(this);
-
- masternodePayments = new MasternodePayments(this);
- masternodeSync = syncFlags != null ? new MasternodeSync(this, syncFlags, verifyFlags) : new MasternodeSync(this);
- governanceManager = new GovernanceManager(this);
- triggerManager = new GovernanceTriggerManager(this);
-
- netFullfilledRequestManager = new NetFullfilledRequestManager(this);
- masternodeListManager = new SimplifiedMasternodeListManager(this);
- recoveredSigsDB = new SPVRecoveredSignaturesDatabase(this);
- quorumManager = new SPVQuorumManager(this, masternodeListManager);
- quorumSnapshotManager = new QuorumSnapshotManager(this);
- signingManager = new SigningManager(this, recoveredSigsDB);
-
- instantSendDB = new SPVInstantSendDatabase(this);
- instantSendManager = new InstantSendManager(this, instantSendDB);
- chainLockHandler = new ChainLocksHandler(this);
- llmqBackgroundThread = new LLMQBackgroundThread(this);
- masternodeMetaDataManager = new MasternodeMetaDataManager(this);
- coinJoinManager = new CoinJoinManager(this, scheduledExecutorService);
- initializedObjects = true;
- }
-
- public void setMasternodeListManager(SimplifiedMasternodeListManager masternodeListManager) {
- this.masternodeListManager = masternodeListManager;
- DualBlockChain dualBlockChain = new DualBlockChain(headerChain, blockChain);
- masternodeListManager.setBlockChain(dualBlockChain, peerGroup, quorumManager, quorumSnapshotManager, chainLockHandler);
- }
-
- public void closeDash() {
- //Dash Specific
- close();
- sporkManager = null;
-
- masternodePayments = null;
- masternodeSync = null;
- initializedObjects = false;
- governanceManager = null;
- masternodeListManager = null;
- }
-
- public boolean initDashSync(final String directory) {
- return initDashSync(directory, null);
- }
-
- /**
- * Initializes objects by loading files from the specified directory
- *
- * @param directory location of the files
- * @param filePrefix file prefix of the files, typically the network name
- * @return true if the files are loaded. false if the files were already loaded
- */
- public boolean initDashSync(final String directory, @Nullable String filePrefix) {
- if (!initializedFiles) {
- // remove mncache.dat if it exists
- File oldMnCacheFile = new File(directory, "mncache.dat");
- if (oldMnCacheFile.exists()) {
- if (oldMnCacheFile.delete())
- log.info("removed obsolete mncache.dat");
- }
-
- // load governance data
- if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
- FlatDB gmdb;
- if (filePrefix != null) {
- gmdb = new FlatDB<>(Context.this, directory + File.separator + filePrefix + ".gobjects", true);
- } else {
- gmdb = new FlatDB<>(Context.this, directory, false);
- }
- gmdb.load(governanceManager);
- }
-
- // load masternode data
- FlatDB smnl;
- if (filePrefix != null) {
- smnl = new FlatDB<>(Context.this, directory + File.separator + filePrefix + ".mnlist", true);
- } else {
- smnl = new FlatDB<>(Context.this, directory, false);
- }
- smnl.load(masternodeListManager);
- masternodeListManager.setLoadedFromFile(true);
- masternodeListManager.onFirstSaveComplete();
-
-
- // Load chainlocks
- FlatDB clh;
- if (filePrefix != null) {
- clh = new FlatDB<>(Context.this, directory + File.separator + filePrefix + ".chainlocks", true);
- } else {
- clh = new FlatDB<>(Context.this, directory, false);
- }
- clh.load(chainLockHandler);
-
- // Load Masternode Metadata
- FlatDB mmdm;
- if (filePrefix != null) {
- mmdm = new FlatDB<>(Context.this, directory + File.separator + filePrefix + ".mnmetadata", true);
- } else {
- mmdm = new FlatDB<>(Context.this, directory, false);
- }
- mmdm.load(masternodeMetaDataManager);
-
- signingManager.initializeSignatureLog(directory);
- initializedFiles = true;
- return true;
- }
- return false;
- }
-
- private void startLLMQThread() {
- if (llmqBackgroundThread == null || !llmqBackgroundThread.isAlive()) {
- llmqBackgroundThread = new LLMQBackgroundThread(Context.this);
- log.info("starting LLMQThread");
- llmqBackgroundThread.start();
- }
- }
-
- private void stopLLMQThread() {
- if (llmqBackgroundThread.isAlive()) {
- log.info("stopping LLMQThread");
- llmqBackgroundThread.interrupt();
- }
- }
-
- public void close() {
- if (initializedObjects) {
- sporkManager.close(peerGroup);
- masternodeSync.close();
- masternodeListManager.close();
- instantSendManager.close(peerGroup);
- signingManager.close();
- chainLockHandler.close();
- quorumManager.close();
- coinJoinManager.close();
- if(masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS))
- llmqBackgroundThread.interrupt();
- blockChain.removeNewBestBlockListener(newBestBlockListener);
- if (scheduledMasternodeSync != null)
- scheduledMasternodeSync.cancel(true);
- blockChain.close();
- if (headerChain != null)
- headerChain.close();
- peerGroup = null;
- }
- }
-
- public void setPeerGroupAndBlockChain(PeerGroup peerGroup, AbstractBlockChain blockChain, @Nullable AbstractBlockChain headerChain) {
- if (this.peerGroup == null/* && initializedObjects*/) { 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());
- if (initializedObjects) {
- sporkManager.setBlockChain(blockChain, peerGroup);
- masternodeSync.setBlockChain(blockChain, netFullfilledRequestManager);
- masternodeListManager.setBlockChain(
- dualBlockChain,
- peerGroup,
- quorumManager,
- quorumSnapshotManager,
- chainLockHandler
- );
- instantSendManager.setBlockChain(blockChain, peerGroup);
- signingManager.setBlockChain(blockChain, headerChain);
- chainLockHandler.setBlockChain(blockChain, headerChain);
- blockChain.setChainLocksHandler(chainLockHandler);
- quorumManager.setBlockChain(blockChain);
- updatedChainHead(blockChain.getChainHead());
- coinJoinManager.initMasternodeGroup(blockChain);
- coinJoinManager.setBlockchain(blockChain);
-
- // trigger saving mechanisms
- governanceManager.resume();
- masternodeListManager.resume();
- chainLockHandler.resume();
- }
- params.setDIPActiveAtTip(blockChain.getBestChainHeight() >= params.getDIP0001BlockHeight());
- }
- }
-
- public boolean isLiteMode() {
- return liteMode;
- }
- public void setLiteMode(boolean liteMode)
- {
- boolean current = this.liteMode;
- if(current == liteMode)
- return;
-
- this.liteMode = liteMode;
- }
-
- public boolean allowInstantXinLiteMode() {
- return allowInstantX;
- }
-
- public void setAllowInstantXinLiteMode(boolean allow) {
- this.allowInstantX = allow;
- }
-
- NewBestBlockListener newBestBlockListener = new NewBestBlockListener() {
- @Override
- public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
- handleActivations(block);
- boolean fInitialDownload = blockChain.getChainHead().getHeader().getTimeSeconds() < (Utils.currentTimeSeconds() - 6 * 60 * 60); // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin
- if(masternodeSync != null)
- masternodeSync.updateBlockTip(block, fInitialDownload);
- }
- };
-
- private void handleActivations(StoredBlock block) {
- // 24 hours before the hard fork (v19.2) connect only to v19.2 nodes on mainnet
- if (params.isV19Active(block.getHeight())) {
- BLSScheme.setLegacyDefault(false);
- }
- }
/**
* The default fee per 1000 bytes of transaction data to pay when completing transactions. For details, see {@link SendRequest#feePerKb}.
@@ -497,61 +226,12 @@ public boolean isEnsureMinRequiredFee() {
return ensureMinRequiredFee;
}
- @Deprecated
- public void updatedChainHead(StoredBlock chainHead)
- {
- params.setDIPActiveAtTip(chainHead.getHeight() >= params.getDIP0001BlockHeight());
- if(initializedObjects) {
- masternodeListManager.updatedBlockTip(chainHead);
- }
- }
+
public VoteConfidenceTable getVoteConfidenceTable() {
return voteConfidenceTable;
}
- public Set getSyncFlags() {
- if (masternodeSync != null) {
- return masternodeSync.syncFlags;
- } else {
- return MasternodeSync.SYNC_DEFAULT_SPV;
- }
- }
-
- public void start() {
- if(getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
- startLLMQThread();
- }
-
- if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
- scheduledMasternodeSync = scheduledExecutorService.scheduleWithFixedDelay(
- () -> masternodeSync.doMaintenance(), 1, 1, TimeUnit.SECONDS);
- scheduledNetFulfilled = scheduledExecutorService.scheduleWithFixedDelay(
- () -> netFullfilledRequestManager.doMaintenance(), 60, 60, TimeUnit.SECONDS);
-
- scheduledGovernance = scheduledExecutorService.scheduleWithFixedDelay(
- () -> governanceManager.doMaintenance(), 60, 5, TimeUnit.MINUTES);
- }
- }
-
- public void shutdown() {
- if(getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
- stopLLMQThread();
- }
-
- if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
- scheduledMasternodeSync.cancel(false);
- scheduledMasternodeSync = null;
- scheduledNetFulfilled.cancel(false);
- scheduledNetFulfilled = null;
- scheduledGovernance.cancel(false);
- scheduledGovernance = null;
- }
- if (initializedObjects) {
- coinJoinManager.stop();
- }
- }
-
public boolean isDebugMode() {
return debugMode;
}
diff --git a/core/src/main/java/org/bitcoinj/core/MasternodePayments.java b/core/src/main/java/org/bitcoinj/core/MasternodePayments.java
index 358ed857cc..00bc52d743 100644
--- a/core/src/main/java/org/bitcoinj/core/MasternodePayments.java
+++ b/core/src/main/java/org/bitcoinj/core/MasternodePayments.java
@@ -15,7 +15,7 @@ public class MasternodePayments {
final float nStorageCoeff = 1.25f;
final int nMinBlocksToStore = 5000;
- MasternodePayments(Context context)
+ public MasternodePayments(Context context)
{
this.context = context;
}
diff --git a/core/src/main/java/org/bitcoinj/core/MasternodeSync.java b/core/src/main/java/org/bitcoinj/core/MasternodeSync.java
index 684d245ba5..48f003e162 100644
--- a/core/src/main/java/org/bitcoinj/core/MasternodeSync.java
+++ b/core/src/main/java/org/bitcoinj/core/MasternodeSync.java
@@ -1,5 +1,7 @@
package org.bitcoinj.core;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
+import org.bitcoinj.governance.GovernanceManager;
import org.bitcoinj.governance.GovernanceSyncMessage;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Threading;
@@ -20,6 +22,7 @@
import static java.lang.Math.max;
import static org.bitcoinj.core.MasternodeSync.SYNC_FLAGS.*;
import static org.bitcoinj.governance.GovernanceManager.MIN_GOVERNANCE_PEER_PROTO_VERSION;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
/**
* Created by Eric on 2/21/2016.
@@ -98,27 +101,41 @@ public enum FEATURE_FLAGS {
AtomicLong timeLastUpdateBlockTip = new AtomicLong(0);
AbstractBlockChain blockChain;
+ GovernanceManager governanceManager;
+ PeerGroup peerGroup;
Context context;
NetFullfilledRequestManager netFullfilledRequestManager;
- void setBlockChain(AbstractBlockChain blockChain, NetFullfilledRequestManager netFullfilledRequestManager) {
+ @Deprecated
+ private boolean isLiteMode;
+ @Deprecated
+ private boolean allowInstantSendInLiteMode;
+
+ public void setBlockChain(AbstractBlockChain blockChain, PeerGroup peerGroup, NetFullfilledRequestManager netFullfilledRequestManager, GovernanceManager governanceManager) {
this.blockChain = blockChain;
+ this.peerGroup = peerGroup;
+ if (peerGroup != null) {
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
this.netFullfilledRequestManager = netFullfilledRequestManager;
+ this.governanceManager = governanceManager;
updateBlockTip(blockChain.chainHead, true);
}
public void close() {
-
+ if (peerGroup != null) {
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
+ }
}
- public MasternodeSync(Context context) {
+ public MasternodeSync(Context context, boolean isLiteMode, boolean allowInstantSendInLiteMode) {
this.context = context;
this.eventListeners = new CopyOnWriteArrayList>();
- if (context.isLiteMode() && context.allowInstantXinLiteMode()) {
+ if (isLiteMode && allowInstantSendInLiteMode) {
this.syncFlags = SYNC_DEFAULT_SPV;
this.verifyFlags = VERIFY_DEFAULT_SPV;
this.featureFlags = FEATURES_SPV;
- } else if (context.isLiteMode()) {
+ } else if (isLiteMode) {
this.syncFlags = SYNC_LITE_MODE;
this.verifyFlags = VERIFY_LITE_MODE;
this.featureFlags = FEATURES_LITE_MODE;
@@ -293,14 +310,14 @@ public void processTick()
// gradually request the rest of the votes after sync finished
if (isSynced()) {
- context.governanceManager.requestGovernanceObjectVotes();
+ governanceManager.requestGovernanceObjectVotes();
return;
}
- if (context.peerGroup == null)
+ if (peerGroup == null)
return;
- ReentrantLock nodeLock = context.peerGroup.getLock();
+ ReentrantLock nodeLock = peerGroup.getLock();
if (!nodeLock.tryLock())
return;
@@ -310,7 +327,7 @@ public void processTick()
log.info("processTick -- tick {} currentAsset {} triedPeerCount {} syncProgress {}",
tick, getAssetName(), triedPeerCount, nSyncProgress);
- List nodesCopy = context.peerGroup.getConnectedPeers();
+ List nodesCopy = peerGroup.getConnectedPeers();
for (Peer peer : nodesCopy) {
// QUICK MODE (REGTEST ONLY!)
@@ -406,7 +423,7 @@ tick, getAssetName(), timeLastBumped, Utils.currentTimeSeconds(),
if (!netFullfilledRequestManager.hasFulfilledRequest(peer.getAddress(), "governance-sync")) {
continue;
}
- int objsLeftToAsk = context.governanceManager.requestGovernanceObjectVotes(peer);
+ int objsLeftToAsk = governanceManager.requestGovernanceObjectVotes(peer);
// check for data
if (objsLeftToAsk == 0) {
if (timeNoObjectsLeft == 0) {
@@ -478,7 +495,7 @@ public boolean removeEventListener(MasternodeSyncListener listener) {
public void queueOnSyncStatusChanged(final int newStatus, final double syncStatus) {
//checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration registration : eventListeners) {
- if (registration.executor == Threading.SAME_THREAD) {
+ if (registration.executor == SAME_THREAD) {
registration.listener.onSyncStatusChanged(newStatus, syncStatus);
} else {
registration.executor.execute(new Runnable() {
@@ -514,7 +531,7 @@ void notifyHeaderTip(StoredBlock blockHeader, boolean initialDownload)
}
}
- void updateBlockTip(StoredBlock storedBlock, boolean initialDownload)
+ public void updateBlockTip(StoredBlock storedBlock, boolean initialDownload)
{
if (!initialDownload && storedBlock.getHeight() % 100 == 0)
log.info("updateBlockTip: height: {} initialDownload={}", storedBlock.getHeight(), initialDownload);
@@ -585,4 +602,15 @@ public void addFeatureFlag(FEATURE_FLAGS flag) {
public String toString() {
return "MasternodeSync{"+ getAssetName()+ "}";
}
+
+ PreMessageReceivedEventListener preMessageReceivedEventListener = new PreMessageReceivedEventListener() {
+ @Override
+ public Message onPreMessageReceived(Peer peer, Message m) {
+ if (m instanceof SyncStatusCount) {
+ processSyncStatusCount(peer, (SyncStatusCount)m);
+ return null;
+ }
+ return m;
+ }
+ };
}
diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java
index e46caacd3c..86a1c89f5e 100644
--- a/core/src/main/java/org/bitcoinj/core/Peer.java
+++ b/core/src/main/java/org/bitcoinj/core/Peer.java
@@ -27,6 +27,7 @@
import org.bitcoinj.governance.GovernanceSyncMessage;
import org.bitcoinj.governance.GovernanceVote;
import org.bitcoinj.governance.GovernanceVoteConfidence;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.net.AbstractTimeoutHandler;
import org.bitcoinj.net.NioClient;
import org.bitcoinj.net.NioClientManager;
@@ -110,6 +111,7 @@ public class Peer extends PeerSocketHandler {
= new CopyOnWriteArrayList<>();
private final CopyOnWriteArrayList> masternodeListDownloadedListeners
= new CopyOnWriteArrayList<>();
+ private final DashSystem system;
// Whether to try and download blocks and transactions from this peer. Set to false by PeerGroup if not the
// primary peer. This is to avoid redundant work and concurrency problems with downloading the same chain
// in parallel.
@@ -254,7 +256,8 @@ public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddr
* used to keep track of which peers relayed transactions and offer more descriptive logging.
*/
public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress,
- @Nullable AbstractBlockChain chain, @Nullable AbstractBlockChain headers, long requiredServices, int downloadTxDependencyDepth) {
+ @Nullable AbstractBlockChain chain, @Nullable AbstractBlockChain headers,
+ long requiredServices, int downloadTxDependencyDepth) {
super(params, remoteAddress);
this.params = Preconditions.checkNotNull(params);
this.versionMessage = Preconditions.checkNotNull(ver);
@@ -277,6 +280,7 @@ public void run() {
versionHandshakeComplete();
}
}, Threading.SAME_THREAD);
+ this.system = DashSystem.get(params);
}
public Peer(NetworkParameters params, VersionMessage ver, PeerAddress remoteAddress,
@@ -569,54 +573,15 @@ protected void processMessage(Message m) throws Exception {
} else if (m instanceof RejectMessage) {
log.error("{} {}: Received {}", this, getPeerVersionMessage().subVer, m);
}
- else if(m instanceof SporkMessage)
- {
- context.sporkManager.processSpork(this, (SporkMessage)m);
- }
- else if(m instanceof SyncStatusCount) {
- context.masternodeSync.processSyncStatusCount(this, (SyncStatusCount)m);
- }
- else if(m instanceof GovernanceSyncMessage) {
- //swallow for now
- } else if(m instanceof GovernanceObject) {
- context.governanceManager.processGovernanceObject(this, (GovernanceObject)m);
- } else if(m instanceof GovernanceVote) {
- context.governanceManager.processGovernanceObjectVote(this, (GovernanceVote)m);
- } else if (m instanceof SimplifiedMasternodeListDiff) {
- context.masternodeListManager.processMasternodeListDiff(this, (SimplifiedMasternodeListDiff) m);
- } else if(m instanceof InstantSendLock) {
- context.instantSendManager.processInstantSendLock(this, (InstantSendLock) m);
- } else if(m instanceof ChainLockSignature) {
- context.chainLockHandler.processChainLockSignature(this, (ChainLockSignature)m);
- } else if (m instanceof SendHeadersMessage) {
+ else if (m instanceof SendHeadersMessage) {
// We ignore this message, because we don't announce new blocks.
} else if (m instanceof SendAddressMessageV2) {
// We ignore this message, because we don't reply to sendaddrv2 message.
- } else if (m instanceof QuorumRotationInfo) {
- context.masternodeListManager.processQuorumRotationInfo(this, (QuorumRotationInfo) m, false, null);
- } else if (CoinJoinManager.isCoinJoinMessage(m)) {
- context.coinJoinManager.processMessage(this, m);
} else {
log.warn("{}: Received unhandled message: {}", this, m);
}
}
- protected void processInstantSendLock(InstantSendLock islock) {
- if (currentFilteredBlock != null) {
- if (!currentFilteredBlock.getTransactionHashes().contains(islock.getTxId())) {
- // Got an islock that didn't fit into the filtered block, so we must have received everything.
- endFilteredBlock(currentFilteredBlock);
- currentFilteredBlock = null;
- } else {
- //if this transaction is more than 24 hours old, don't process the islock
- if (currentFilteredBlock.getBlockHeader().getTimeSeconds() + TimeUnit.DAYS.toSeconds(1) > System.currentTimeMillis()) {
- return;
- }
- }
- }
- context.instantSendManager.processInstantSendLock(this, islock);
- }
-
protected void processUTXOMessage(UTXOsMessage m) {
SettableFuture future = null;
lock.lock();
@@ -798,7 +763,7 @@ protected void processHeaders(HeadersMessage m) throws ProtocolException {
invokeOnHeadersDownloaded(lastHeader);
log.info("processing headers till {}", lastHeader.getHeight());
if (m.getBlockHeaders().size() < HeadersMessage.MAX_HEADERS) {
- context.peerGroup.triggerHeadersDownloadComplete();
+ system.triggerHeadersDownloadComplete();
} else {
lock.lock();
try {
@@ -889,24 +854,24 @@ public void startMasternodeListDownload() {
headerChain.getBlockStore().get(headerChain.getBestChainHeight() - SigningManager.SIGN_HEIGHT_OFFSET) :
blockChain.getBlockStore().get(blockChain.getBestChainHeight() - SigningManager.SIGN_HEIGHT_OFFSET);
- if (context.masternodeListManager.getListAtChainTip().getHeight() < masternodeListBlock.getHeight()) {
- if (context.masternodeListManager.requestQuorumStateUpdate(this, headerChain.getChainHead(), masternodeListBlock)) {
+ if (system.masternodeListManager.getListAtChainTip().getHeight() < masternodeListBlock.getHeight()) {
+ if (system.masternodeListManager.requestQuorumStateUpdate(this, headerChain.getChainHead(), masternodeListBlock)) {
queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Requesting, null);
} else {
log.info(
"mnlistdiff not requested though listAtChainTip({}) < masternodeListBlock({})",
- context.masternodeListManager.getListAtChainTip().getHeight(),
+ system.masternodeListManager.getListAtChainTip().getHeight(),
masternodeListBlock.getHeight()
);
- context.peerGroup.triggerMnListDownloadComplete();
+ system.triggerMnListDownloadComplete();
}
} else {
- context.peerGroup.triggerMnListDownloadComplete();
+ system.triggerMnListDownloadComplete();
}
} catch (BlockStoreException x) {
throw new RuntimeException(x);
} catch (Exception x) {
- context.peerGroup.triggerMnListDownloadComplete();
+ system.triggerMnListDownloadComplete();
}
}
@@ -1360,34 +1325,6 @@ public void run() {
}
}
- //added for dash
- boolean alreadyHave(InventoryItem inv)
- {
- switch (inv.type)
- {
- case Spork:
- return context.sporkManager.hasSpork(inv.hash);
- case MasternodePaymentVote:
- case BudgetFinalizedVote:
- case BudgetVote:
- case BudgetProposal:
- case BudgetFinalized:
- return false;
- case GovernanceObject:
- case GovernanceObjectVote:
- return !context.governanceManager.confirmInventoryRequest(inv);
- case InstantSendLock:
- case InstantSendDeterministicLock:
- return context.instantSendManager.alreadyHave(inv);
- case ChainLockSignature:
- return context.chainLockHandler.alreadyHave(inv);
- case DarkSendTransaction:
- return CoinJoin.hasDSTX(inv.hash);
- }
- // Don't know what it is, just say we already got one
- return true;
- }
-
protected void processInv(InventoryMessage inv) {
List items = inv.getItems();
@@ -1409,9 +1346,9 @@ protected void processInv(InventoryMessage inv) {
case Block:
blocks.add(item);
break;
- case Spork:
- sporks.add(item);
- break;
+// case Spork:
+// sporks.add(item);
+// break;
case MasternodePaymentVote:
break;
case MasternodePaymentBlock: break;
@@ -1420,20 +1357,20 @@ protected void processInv(InventoryMessage inv) {
case BudgetProposal: break;
case BudgetFinalized: break;
case BudgetFinalizedVote: break;
- case GovernanceObject:
- goveranceObjects.add(item);
- break;
- case GovernanceObjectVote:
- goveranceObjects.add(item);
- break;
+// case GovernanceObject:
+// goveranceObjects.add(item);
+// break;
+// case GovernanceObjectVote:
+// goveranceObjects.add(item);
+// break;
case MasternodeVerify: break;
- case InstantSendLock:
- case InstantSendDeterministicLock:
- instantSendLocks.add(item);
- break;
- case ChainLockSignature:
- chainLocks.add(item);
- break;
+// case InstantSendLock:
+// case InstantSendDeterministicLock:
+// instantSendLocks.add(item);
+// break;
+// case ChainLockSignature:
+// chainLocks.add(item);
+// break;
default:
break;
}
@@ -1490,57 +1427,6 @@ protected void processInv(InventoryMessage inv) {
}
}
- // The New InstantSendLock (ISLOCK)
- if(context.instantSendManager != null && context.instantSendManager.isInstantSendEnabled() &&
- context.masternodeSync != null && context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
- it = instantSendLocks.iterator();
- while (it.hasNext()) {
- InventoryItem item = it.next();
- if(!alreadyHave(item)) {
- getdata.addItem(item);
- }
- }
- }
-
- // The ChainLock (CLSIG)
- if(/*context.sporkManager != null && context.sporkManager.isSporkActive(SporkManager.SPORK_19_CHAINLOCKS_ENABLED) && */
- context.masternodeSync != null && context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_CHAINLOCKS)) {
- it = chainLocks.iterator();
- while (it.hasNext()) {
- InventoryItem item = it.next();
- if (!alreadyHave(item)) {
- getdata.addItem(item);
- }
- }
- }
-
- if(context.masternodeSync != null && context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_SPORKS)) {
- it = sporks.iterator();
- while (it.hasNext()) {
- InventoryItem item = it.next();
- getdata.addItem(item);
- }
- }
-
- if(context.masternodeSync != null && context.masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
- it = goveranceObjects.iterator();
-
- while (it.hasNext()) {
- InventoryItem item = it.next();
- if (!alreadyHave(item))
- getdata.addItem(item);
- else {
- // The line below can trigger confidence listeners.
- GovernanceVoteConfidence conf = context.getVoteConfidenceTable().seen(item.hash, this.getAddress());
-
- log.debug("{}: getdata on tx {}", getAddress(), item.hash);
- getdata.addItem(item);
- // Register with the garbage collector that we care about the confidence data for a while.
- pendingVotes.add(conf);
- }
- }
- }
-
// If we are requesting filteredblocks we have to send a ping after the getdata so that we have a clear
// end to the final FilteredBlock's transactions (in the form of a pong) sent to us
boolean pingAfterGetData = false;
diff --git a/core/src/main/java/org/bitcoinj/core/PeerGroup.java b/core/src/main/java/org/bitcoinj/core/PeerGroup.java
index 0b72fbcd94..0dcc1eaffc 100644
--- a/core/src/main/java/org/bitcoinj/core/PeerGroup.java
+++ b/core/src/main/java/org/bitcoinj/core/PeerGroup.java
@@ -32,6 +32,7 @@
import org.bitcoinj.governance.GovernanceVoteBroadcast;
import org.bitcoinj.governance.GovernanceVoteBroadcaster;
import org.bitcoinj.governance.GovernanceVoteConfidence;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.net.*;
import org.bitcoinj.net.discovery.*;
import org.bitcoinj.quorums.LLMQUtils;
@@ -104,6 +105,7 @@ public class PeerGroup implements TransactionBroadcaster, GovernanceVoteBroadcas
protected final Context context;
@Nullable protected final AbstractBlockChain chain;
@Nullable protected AbstractBlockChain headerChain;
+ protected final DashSystem system;
// This executor is used to queue up jobs: it's used when we don't want to use locks for mutual exclusion,
// typically because the job might call in to user provided code that needs/wants the freedom to use the API
@@ -461,8 +463,9 @@ public int compare(PeerAddress a, PeerAddress b) {
// Dash Specific - if this PeerGroup does not sync the blockchain, then syncsBlockchain should be false
// otherwise, if headerChain is null, then copy the last 100 headers over to it
+ system = DashSystem.get(params);
if (headerChain == null && syncsBlockchain) {
- if (context.getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_HEADERS_MN_LIST_FIRST)) {
+ if (system != null && getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_HEADERS_MN_LIST_FIRST)) {
try {
this.headerChain = new BlockChain(params, new MemoryBlockStore(params));
StoredBlock cursor = chain.getChainHead();
@@ -482,7 +485,9 @@ public int compare(PeerAddress a, PeerAddress b) {
} else {
this.headerChain = headerChain;
}
- context.setPeerGroupAndBlockChain(this, chain, this.headerChain);
+ if (system != null) {
+ system.setPeerGroupAndBlockChain(this, chain, this.headerChain);
+ }
}
private CountDownLatch executorStartupLatch = new CountDownLatch(1);
@@ -669,10 +674,6 @@ private List handleGetData(GetDataMessage m) {
it.remove();
break;
}
- if(item.type == InventoryItem.Type.GovernanceObjectVote) {
- if(Context.get().governanceManager.haveVoteForHash(item.hash))
- transactions.add(Context.get().governanceManager.getVoteForHash(item.hash));
- }
}
return transactions;
} finally {
@@ -1260,7 +1261,9 @@ public void run() {
channels.awaitRunning();
triggerConnections();
setupPinging();
- context.start();
+ if (system != null) {
+ system.start();
+ }
} catch (Throwable e) {
log.error("Exception when starting up", e); // The executor swallows exceptions :(
}
@@ -1290,7 +1293,9 @@ public void run() {
for (PeerDiscovery peerDiscovery : peerDiscoverers) {
peerDiscovery.shutdown();
}
- context.shutdown();
+ if (system != null) {
+ system.shutdown();
+ }
vRunning = false;
log.info("Stopped, took {}.", watch);
} catch (Throwable e) {
@@ -1630,8 +1635,8 @@ protected Peer connectTo(PeerAddress address, boolean incrementMaxConnections, i
protected Peer createPeer(PeerAddress address, VersionMessage ver) {
Peer peer = new Peer(params, ver, address, chain, headerChain, requiredServices, downloadTxDependencyDepth);
// mark this as a masternode if it is
- if (context.masternodeListManager != null) {
- SimplifiedMasternodeList mnList = context.masternodeListManager.getMasternodeList();
+ if (system != null && system.masternodeListManager != null) {
+ SimplifiedMasternodeList mnList = system.masternodeListManager.getMasternodeList();
if (mnList.size() != 0) {
if (mnList.containsMN(address)) {
peer.setMasternode(true);
@@ -1710,7 +1715,7 @@ private static void removeDataEventListenerFromPeer(Peer peer, PeerDataEventList
* from at least one peer all the blocks that are in that peer's inventory.
*/
public void downloadBlockChain() {
- DownloadProgressTracker listener = new DownloadProgressTracker();
+ DownloadProgressTracker listener = new DownloadProgressTracker(system.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_BLOCKS_AFTER_PREPROCESSING));
startBlockChainDownload(listener);
try {
listener.await();
@@ -2223,7 +2228,7 @@ public void onFailure(Throwable throwable) {
@Override
public void onSuccess(@Nullable Integer listsSynced) {
log.info("Stage masternode list download successful: {}", listsSynced);
- Set flags = context.getSyncFlags();
+ Set flags = getSyncFlags();
if (flags.contains(MasternodeSync.SYNC_FLAGS.SYNC_BLOCKS_AFTER_PREPROCESSING)) {
if(syncStage.value < SyncStage.PREBLOCKS.value) {
setSyncStage(SyncStage.PREBLOCKS);
@@ -2306,7 +2311,7 @@ void startBlockChainDownloadFromPeer(Peer peer) {
addMasternodeListDownloadListener(Threading.SAME_THREAD, chainDownloadSpeedCalculator);
// how can we download headers first, then at the end do the blockchain/merkle blocks
- Set flags = Context.get().getSyncFlags();
+ Set flags = getSyncFlags();
if (flags.contains(MasternodeSync.SYNC_FLAGS.SYNC_HEADERS_MN_LIST_FIRST)) {
log.info("Attempting to sync headers first");
if (peer.getBestHeight() > headerChain.getChainHead().getHeight() &&
@@ -2914,4 +2919,12 @@ public void shouldSendDsq(boolean shouldSendDsq) {
}
this.shouldSendDsq = shouldSendDsq;
}
+
+ private Set getSyncFlags() {
+ if (system != null) {
+ return system.getSyncFlags();
+ } else {
+ return EnumSet.noneOf(MasternodeSync.SYNC_FLAGS.class);
+ }
+ }
}
diff --git a/core/src/main/java/org/bitcoinj/core/SporkManager.java b/core/src/main/java/org/bitcoinj/core/SporkManager.java
index 0d9cdf88ab..a3a450a625 100644
--- a/core/src/main/java/org/bitcoinj/core/SporkManager.java
+++ b/core/src/main/java/org/bitcoinj/core/SporkManager.java
@@ -17,6 +17,7 @@
import com.google.common.annotations.VisibleForTesting;
import org.bitcoinj.core.listeners.PeerConnectedEventListener;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.core.listeners.SporkUpdatedEventListener;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Pair;
@@ -30,12 +31,15 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.locks.ReentrantLock;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
+
/**
* Created by Hash Engineering on 2/20/2016.
@@ -69,6 +73,7 @@ private static void makeSporkDefinition(SporkId sporkId, long defaultValue) {
@GuardedBy("lock") private final HashSet setSporkPubKeyIds = new HashSet<>();
private AbstractBlockChain blockChain;
+ private MasternodeSync masternodeSync;
private final Context context;
public SporkManager(Context context)
@@ -83,10 +88,12 @@ public SporkManager(Context context)
setMinSporkKeys(context.getParams().getMinSporkKeys());
}
- void setBlockChain(AbstractBlockChain blockChain, @Nullable PeerGroup peerGroup) {
+ public void setBlockChain(AbstractBlockChain blockChain, @Nullable PeerGroup peerGroup, MasternodeSync masternodeSync) {
this.blockChain = blockChain;
+ this.masternodeSync = masternodeSync;
if (peerGroup != null) {
peerGroup.addConnectedEventListener(peerConnectedEventListener);
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
}
}
@@ -96,13 +103,16 @@ public void clear() {
}
public void close(PeerGroup peerGroup) {
- peerGroup.removeConnectedEventListener(peerConnectedEventListener);
+ if (peerGroup != null) {
+ peerGroup.removeConnectedEventListener(peerConnectedEventListener);
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
+ }
}
void processSpork(Peer from, SporkMessage spork) {
- if (context.isLiteMode() && !context.allowInstantXinLiteMode()) {
- return; //disable all darksend/masternode related functionality
- }
+// if (context.isLiteMode() && !context.allowInstantXinLiteMode()) {
+// return; //disable all darksend/masternode related functionality
+// }
Sha256Hash hash = spork.getHash();
String logMessage = String.format("SPORK -- hash: %s id: %d (%s) value: %10d bestHeight: %d peer=%s:%d",
@@ -314,6 +324,42 @@ public void onPeerConnected(Peer peer, int peerCount) {
}
};
+ public final PreMessageReceivedEventListener preMessageReceivedEventListener = (peer, m) -> {
+ if (m instanceof InventoryMessage) {
+ if (masternodeSync != null && masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_SPORKS)) {
+ InventoryMessage inv = (InventoryMessage) m;
+ List items = inv.getItems();
+ List instantSendLocks = new LinkedList<>();
+ for (InventoryItem item : items) {
+ switch (item.type) {
+ case InstantSendLock:
+ case InstantSendDeterministicLock:
+ instantSendLocks.add(item);
+ break;
+ default:
+ break;
+ }
+ }
+ Iterator it = instantSendLocks.iterator();
+ GetDataMessage getdata = new GetDataMessage(SporkManager.this.context.getParams());
+ while (it.hasNext()) {
+ InventoryItem item = it.next();
+ if(!alreadyHave(item)) {
+ getdata.addItem(item);
+ }
+ }
+ if (!getdata.getItems().isEmpty()) {
+ // This will cause us to receive a bunch of block or tx messages.
+ peer.sendMessage(getdata);
+ }
+ }
+ } else if (m instanceof SporkMessage) {
+ processSpork(peer, (SporkMessage) m);
+ return null;
+ }
+ return m;
+ };
+
private transient CopyOnWriteArrayList> eventListeners;
/**
@@ -344,7 +390,7 @@ public boolean removeEventListener(SporkUpdatedEventListener listener) {
public void queueOnUpdate(final SporkMessage spork) {
//checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration registration : eventListeners) {
- if (registration.executor == Threading.SAME_THREAD) {
+ if (registration.executor == SAME_THREAD) {
registration.listener.onSporkUpdated(spork);
} else {
registration.executor.execute(new Runnable() {
@@ -365,6 +411,10 @@ public List getSporks() {
return sporkList;
}
+ public boolean alreadyHave(InventoryItem item) {
+ return hasSpork(item.hash);
+ }
+
public boolean hasSpork(Sha256Hash hashSpork) {
return mapSporksByHash.containsKey(hashSpork);
}
diff --git a/core/src/main/java/org/bitcoinj/core/listeners/DownloadProgressTracker.java b/core/src/main/java/org/bitcoinj/core/listeners/DownloadProgressTracker.java
index d65ef5f2ad..3b05dead43 100644
--- a/core/src/main/java/org/bitcoinj/core/listeners/DownloadProgressTracker.java
+++ b/core/src/main/java/org/bitcoinj/core/listeners/DownloadProgressTracker.java
@@ -61,10 +61,11 @@ public class DownloadProgressTracker extends AbstractPeerDataEventListener {
public double blocksWeight;
public DownloadProgressTracker() {
- Context context = Context.get();
- if (context != null) {
- hasPreBlockProcessing = context.getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_BLOCKS_AFTER_PREPROCESSING);
- }
+ this(false);
+ }
+
+ public DownloadProgressTracker(boolean hasPreBlockProcessing) {
+ this.hasPreBlockProcessing = hasPreBlockProcessing;
}
protected void updateBlocksWeight() {
diff --git a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java
index b8fccb917d..c4d8b0d1d8 100644
--- a/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java
+++ b/core/src/main/java/org/bitcoinj/evolution/AbstractQuorumState.java
@@ -97,6 +97,7 @@ public abstract class AbstractQuorumState lastRequest;
@@ -105,7 +106,7 @@ public abstract class AbstractQuorumState PeerGroup.SyncStage.MNLIST.value;
+ return peerGroup != null && peerGroup.getSyncStage().value > PeerGroup.SyncStage.MNLIST.value;
}
BlockQueue pendingBlocks = new BlockQueue();
@@ -171,8 +172,9 @@ public void setBootstrap(String bootstrapFilePath, InputStream bootstrapStream,
}
// TODO: Do we need to keep track of the header chain also?
- public void setBlockChain(PeerGroup peerGroup, DualBlockChain blockChain) {
+ public void setBlockChain(PeerGroup peerGroup, DualBlockChain blockChain, MasternodeSync masternodeSync) {
this.blockChain = blockChain;
+ this.masternodeSync = masternodeSync;
if (peerGroup != null) {
this.peerGroup = peerGroup;
}
@@ -215,7 +217,7 @@ public SettableFuture getBootStrapLoadedFuture() {
abstract boolean needsUpdate(StoredBlock nextBlock);
public abstract void processDiff(@Nullable Peer peer, DiffMessage difference,
- DualBlockChain blockChain,
+ DualBlockChain blockChain, MasternodeListManager masternodeListManager,
boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage)
throws VerificationException;
@@ -336,8 +338,8 @@ public boolean requestMNListDiff(Peer peer, StoredBlock block) {
}
protected boolean shouldProcessMNListDiff() {
- return context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_DMN_LIST) ||
- context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_QUORUM_LIST);
+ return masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_DMN_LIST) ||
+ masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_QUORUM_LIST);
}
boolean requestNextMNListDiff() {
@@ -345,7 +347,7 @@ boolean requestNextMNListDiff() {
return false;
log.info("download peer = {}, but obtaining backup from peerGroup downloadPeer", downloadPeer);
- Peer downloadPeerBackup = downloadPeer == null ? context.peerGroup.getDownloadPeer() : downloadPeer;
+ Peer downloadPeerBackup = downloadPeer == null ? peerGroup.getDownloadPeer() : downloadPeer;
log.info("backup download peer = {}", downloadPeerBackup);
lock.lock();
try {
@@ -434,7 +436,7 @@ boolean maybeGetMNListDiffFresh() {
if (downloadPeer == null) {
log.info("using peerGroup downloadPeer in maybeGetMNListDiffFresh ");
- downloadPeer = context.peerGroup.getDownloadPeer();
+ downloadPeer = peerGroup.getDownloadPeer();
log.info("using peerGroup downloadPeer in maybeGetMNListDiffFresh {}", downloadPeer);
}
@@ -563,7 +565,7 @@ public void removeEventListeners(AbstractBlockChain blockChain, PeerGroup peerGr
public final NewBestBlockListener newBestBlockListener = new NewBestBlockListener() {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
- boolean value = initChainTipSyncComplete() || !context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_HEADERS_MN_LIST_FIRST);
+ boolean value = initChainTipSyncComplete() || !masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_HEADERS_MN_LIST_FIRST);
boolean needsUpdate = needsUpdate(block);
if (needsUpdate && value && getMasternodeListAtTip().getHeight() < block.getHeight() && isDeterministicMNsSporkActive() && stateManager.isLoadedFromFile()) {
long timePeriod = syncOptions == MasternodeListSyncOptions.SYNC_SNAPSHOT_PERIOD ? SNAPSHOT_TIME_PERIOD : MAX_CACHE_SIZE * 3 * 600L;
@@ -595,7 +597,7 @@ public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
public final PeerConnectedEventListener peerConnectedEventListener = new PeerConnectedEventListener() {
@Override
public void onPeerConnected(Peer peer, int peerCount) {
- downloadPeer = context.peerGroup.getDownloadPeer();
+ downloadPeer = peerGroup.getDownloadPeer();
log.info("peer connected and setting download peer to {} with onPeerConnected", downloadPeer);
}
};
@@ -604,7 +606,7 @@ public void onPeerConnected(Peer peer, int peerCount) {
@Override
public void onPeerDisconnected(Peer peer, int peerCount) {
if (downloadPeer == peer) {
- downloadPeer = context.peerGroup.getDownloadPeer();
+ downloadPeer = peerGroup.getDownloadPeer();
log.info("setting download peer to {} with onPeerDisconnected, previously was {}", downloadPeer, peer);
if (downloadPeer == null)
chooseRandomDownloadPeer();
@@ -651,7 +653,7 @@ public void reorganize(StoredBlock splitPoint, List oldBlocks, List
};
void chooseRandomDownloadPeer() {
- List peers = context.peerGroup.getConnectedPeers();
+ List peers = peerGroup.getConnectedPeers();
if (peers != null && !peers.isEmpty()) {
downloadPeer = peers.get(random.nextInt(peers.size()));
log.info("setting download peer with chooseRandomDownloadPeer: {}", downloadPeer);
@@ -745,10 +747,10 @@ private void retryLastRequest(Peer peer, Exception e) {
return;
}
// use tryLock to avoid deadlocks
- boolean isLocked = context.peerGroup.getLock().tryLock(500, TimeUnit.MILLISECONDS);
+ boolean isLocked = peerGroup.getLock().tryLock(500, TimeUnit.MILLISECONDS);
try {
if (isLocked) {
- downloadPeer = context.peerGroup.getDownloadPeer();
+ downloadPeer = peerGroup.getDownloadPeer();
log.info("{}: peergroup lock acquired, obtaining downloadPeer from peerGroup: {}",
Thread.currentThread().getName(), downloadPeer);
if (downloadPeer == null) {
@@ -758,7 +760,7 @@ private void retryLastRequest(Peer peer, Exception e) {
}
} finally {
if (isLocked) {
- context.peerGroup.getLock().unlock();
+ peerGroup.getLock().unlock();
}
}
} catch (InterruptedException x) {
diff --git a/core/src/main/java/org/bitcoinj/evolution/MasternodeListManager.java b/core/src/main/java/org/bitcoinj/evolution/MasternodeListManager.java
new file mode 100644
index 0000000000..152f9fc7b1
--- /dev/null
+++ b/core/src/main/java/org/bitcoinj/evolution/MasternodeListManager.java
@@ -0,0 +1,24 @@
+package org.bitcoinj.evolution;
+
+import org.bitcoinj.core.AbstractManager;
+import org.bitcoinj.core.Context;
+import org.bitcoinj.core.NetworkParameters;
+import org.bitcoinj.core.Sha256Hash;
+import org.bitcoinj.quorums.LLMQParameters;
+
+import java.util.List;
+
+public abstract class MasternodeListManager extends AbstractManager implements QuorumStateManager {
+
+ public MasternodeListManager(Context context) {
+ super(context);
+ }
+
+ public MasternodeListManager(NetworkParameters params, byte[] payload, int cursor) {
+ super(params, payload, cursor);
+ }
+
+ public abstract List getAllQuorumMembers(LLMQParameters.LLMQType llmqType, Sha256Hash blockHash);
+
+ public abstract SimplifiedMasternodeList getListAtChainTip();
+}
diff --git a/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java b/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java
index 1eab02c9a5..1c48e25c0d 100644
--- a/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java
+++ b/core/src/main/java/org/bitcoinj/evolution/QuorumRotationState.java
@@ -157,7 +157,7 @@ public QuorumRotationState(Context context, byte[] payload, int offset, int prot
finishInitialization();
}
- public void applyDiff(Peer peer, DualBlockChain blockChain,
+ public void applyDiff(Peer peer, DualBlockChain blockChain, MasternodeListManager masternodeListManager,
QuorumRotationInfo quorumRotationInfo, boolean isLoadingBootStrap)
throws BlockStoreException, MasternodeListDiffException {
StoredBlock blockAtTip;
@@ -168,7 +168,7 @@ public void applyDiff(Peer peer, DualBlockChain blockChain,
StoredBlock blockMinus4C = null;
long newHeight = ((CoinbaseTx) quorumRotationInfo.getMnListDiffAtH().coinBaseTx.getExtraPayloadObject()).getHeight();
- boolean isSyncingHeadersFirst = context.peerGroup != null && context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
+ boolean isSyncingHeadersFirst = peerGroup != null && peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
log.info("processing {} qrinfo between (atH): {} & {}; {} from {}",
isLoadingBootStrap ? "bootstrap" : "requested",
@@ -235,7 +235,7 @@ public void applyDiff(Peer peer, DualBlockChain blockChain,
// need to handle the case where there is only 1 masternode list, or 2 -- not enough to do all verification
- if (context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_MNLIST)) {
+ if (masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_MNLIST)) {
// TODO: do we actually need to keep track of the blockchain tip mnlist?
// newMNListTip.verify(quorumRotationInfo.getMnListDiffTip().coinBaseTx, quorumRotationInfo.getMnListDiffTip(), mnListTip);
newMNListAtH.verify(quorumRotationInfo.getMnListDiffAtH().coinBaseTx, quorumRotationInfo.getMnListDiffAtH(), mnListAtH);
@@ -308,22 +308,22 @@ public void applyDiff(Peer peer, DualBlockChain blockChain,
if (quorumRotationInfo.hasExtraShare()) {
baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus4C().getPrevBlockHash());
if (baseQuorumList != null)
- newQuorumListAtHMinus4C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus4C(), isLoadingBootStrap, blockChain, true, false);
+ newQuorumListAtHMinus4C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus4C(), isLoadingBootStrap, blockChain, masternodeListManager, chainLocksHandler,true, false);
}
baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus3C().getPrevBlockHash());
- SimplifiedQuorumList newQuorumListAtHMinus3C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus3C(), isLoadingBootStrap, blockChain, true, false);
+ SimplifiedQuorumList newQuorumListAtHMinus3C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus3C(), isLoadingBootStrap, blockChain, masternodeListManager, chainLocksHandler,true, false);
baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinus2C().getPrevBlockHash());
- SimplifiedQuorumList newQuorumListAtHMinus2C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus2C(), isLoadingBootStrap, blockChain, true, false);
+ SimplifiedQuorumList newQuorumListAtHMinus2C = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinus2C(), isLoadingBootStrap, blockChain, masternodeListManager,chainLocksHandler,true, false);
baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtHMinusC().getPrevBlockHash());
- SimplifiedQuorumList newQuorumListAtHMinusC = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinusC(), isLoadingBootStrap, blockChain, true, false);
+ SimplifiedQuorumList newQuorumListAtHMinusC = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtHMinusC(), isLoadingBootStrap, blockChain, masternodeListManager,chainLocksHandler,true, false);
baseQuorumList = quorumsCache.get(quorumRotationInfo.getMnListDiffAtH().getPrevBlockHash());
- SimplifiedQuorumList newQuorumListAtH = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtH(), isLoadingBootStrap, blockChain, true, false);
+ SimplifiedQuorumList newQuorumListAtH = baseQuorumList.applyDiff(quorumRotationInfo.getMnListDiffAtH(), isLoadingBootStrap, blockChain, masternodeListManager,chainLocksHandler,true, false);
- if (context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM)) {
+ if (masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM)) {
// verify the merkle root of the quorums at H
newQuorumListAtH.verify(quorumRotationInfo.getMnListDiffAtH().coinBaseTx, quorumRotationInfo.getMnListDiffAtH(), quorumListAtH, newMNListAtH);
}
@@ -369,7 +369,7 @@ public void applyDiff(Peer peer, DualBlockChain blockChain,
}
if (!hasList) {
newList.setBlock(blockAtH != null ? blockAtH : blockChain.getChainHead());
- newList.verifyQuorums(isLoadingBootStrap, blockChain, true);
+ newList.verifyQuorums(isLoadingBootStrap, blockChain, masternodeListManager,true);
activeQuorumLists.put((int) newList.getHeight(), newList);
}
log.info("activeQuorumLists: {}", activeQuorumLists.size());
@@ -448,10 +448,10 @@ public boolean isSynced() {
if(mnListAtH.getHeight() == -1)
return false;
- if (context.peerGroup == null)
+ if (peerGroup == null)
return false;
- int mostCommonHeight = context.peerGroup.getMostCommonHeight();
+ int mostCommonHeight = peerGroup.getMostCommonHeight();
// determine when the last QR height was
LLMQParameters llmqParameters = params.getLlmqs().get(llmqType);
@@ -1162,7 +1162,7 @@ public String toString() {
}
@Override
- public void processDiff(@Nullable Peer peer, QuorumRotationInfo quorumRotationInfo, DualBlockChain blockChain,
+ public void processDiff(@Nullable Peer peer, QuorumRotationInfo quorumRotationInfo, DualBlockChain blockChain, MasternodeListManager masternodeListManager,
boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException {
long newHeight = ((CoinbaseTx) quorumRotationInfo.getMnListDiffTip().coinBaseTx.getExtraPayloadObject()).getHeight();
if (peer != null) {
@@ -1180,8 +1180,8 @@ public void processDiff(@Nullable Peer peer, QuorumRotationInfo quorumRotationIn
lock.lock();
try {
- setBlockChain(peerGroup, blockChain);
- applyDiff(peer, blockChain, quorumRotationInfo, isLoadingBootStrap);
+ setBlockChain(peerGroup, blockChain, masternodeSync);
+ applyDiff(peer, blockChain, masternodeListManager, 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 cfda263f66..0ba5d79ecf 100644
--- a/core/src/main/java/org/bitcoinj/evolution/QuorumState.java
+++ b/core/src/main/java/org/bitcoinj/evolution/QuorumState.java
@@ -116,16 +116,17 @@ public void requestUpdate(Peer peer, StoredBlock nextBlock) {
}
public void applyDiff(Peer peer, DualBlockChain blockChain,
+ MasternodeListManager masternodeListManager,
SimplifiedMasternodeListDiff mnlistdiff, boolean isLoadingBootStrap)
throws BlockStoreException, MasternodeListDiffException {
StoredBlock block;
- boolean isSyncingHeadersFirst = context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
+ boolean isSyncingHeadersFirst = peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
if (peer != null && isSyncingHeadersFirst) peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Processing, mnlistdiff);
Stopwatch mnWatch = Stopwatch.createStarted();
SimplifiedMasternodeList newMNList = mnList.applyDiff(mnlistdiff);
- if(context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_MNLIST))
+ if(masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_MNLIST))
newMNList.verify(mnlistdiff.coinBaseTx, mnlistdiff, mnList);
mnWatch.stop();
if (peer != null && isSyncingHeadersFirst) peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.ProcessedMasternodes, mnlistdiff);
@@ -133,8 +134,8 @@ public void applyDiff(Peer peer, DualBlockChain blockChain,
Stopwatch qWatch = Stopwatch.createStarted();
SimplifiedQuorumList newQuorumList = quorumList;
if (mnlistdiff.coinBaseTx.getExtraPayloadObject().getVersion() >= SimplifiedMasternodeListManager.LLMQ_FORMAT_VERSION) {
- newQuorumList = quorumList.applyDiff(mnlistdiff, isLoadingBootStrap, blockChain, false, true);
- if (context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM))
+ newQuorumList = quorumList.applyDiff(mnlistdiff, isLoadingBootStrap, blockChain, masternodeListManager, chainLocksHandler, false, true);
+ if (masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.MNLISTDIFF_QUORUM))
newQuorumList.verify(mnlistdiff.coinBaseTx, mnlistdiff, quorumList, newMNList);
} else {
quorumList.syncWithMasternodeList(newMNList);
@@ -249,13 +250,14 @@ public SimplifiedQuorumList getQuorumListAtTip() {
@Override
public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlistdiff, DualBlockChain blockChain,
+ MasternodeListManager masternodeListManager,
boolean isLoadingBootStrap, PeerGroup.SyncStage syncStage) throws VerificationException {
long newHeight = ((CoinbaseTx) mnlistdiff.coinBaseTx.getExtraPayloadObject()).getHeight();
if (peer != null) peer.queueMasternodeListDownloadedListeners(MasternodeListDownloadedListener.Stage.Received, mnlistdiff);
Stopwatch watch = Stopwatch.createStarted();
Stopwatch watchMNList = Stopwatch.createUnstarted();
Stopwatch watchQuorums = Stopwatch.createUnstarted();
- boolean isSyncingHeadersFirst = context.peerGroup != null && context.peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
+ boolean isSyncingHeadersFirst = peerGroup != null && peerGroup.getSyncStage() == PeerGroup.SyncStage.MNLIST;
log.info("processing {} mnlistdiff (headersFirst={}) between : {} & {}; {} from {}",
isLoadingBootStrap ? "bootstrap" : "requested", isSyncingHeadersFirst,
getMnList().getHeight(), newHeight, mnlistdiff, peer);
@@ -266,7 +268,7 @@ public void processDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlist
lock.lock();
try {
log.info("lock acquired when processing mnlistdiff");
- applyDiff(peer, blockChain, mnlistdiff, isLoadingBootStrap);
+ applyDiff(peer, blockChain, masternodeListManager, mnlistdiff, isLoadingBootStrap);
log.info("{}", this);
lastRequest.setFulfilled();
@@ -343,7 +345,7 @@ protected void finishDiff(boolean isLoadingBootStrap) {
waitingForMNListDiff = false;
if (!initChainTipSyncComplete() && !isLoadingBootStrap) {
log.info("initChainTipSync=false");
- context.peerGroup.triggerMnListDownloadComplete();
+ peerGroup.triggerMnListDownloadComplete();
log.info("initChainTipSync=true");
}
}
diff --git a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeList.java b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeList.java
index 7e72665ee4..2ae2ccc605 100644
--- a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeList.java
+++ b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeList.java
@@ -19,6 +19,7 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import org.bitcoinj.core.*;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.quorums.LLMQUtils;
import org.bitcoinj.utils.MerkleRoot;
import org.bitcoinj.utils.Pair;
@@ -116,7 +117,8 @@ protected void parse() throws ProtocolException {
size = (int)readVarInt();
Preconditions.checkArgument(size == 0, "There is an offset error with this data file, rejecting...");
- if(Context.get().masternodeListManager.getFormatVersion() >= 2) {
+ // TODO: we need to find a way out of this
+ if (DashSystem.get(params).masternodeListManager.getFormatVersion() >= 2) {
ByteBuffer buffer = ByteBuffer.allocate(StoredBlock.COMPACT_SERIALIZED_SIZE);
buffer.put(readBytes(StoredBlock.COMPACT_SERIALIZED_SIZE));
buffer.rewind();
diff --git a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java
index bce0758599..c41018b93a 100644
--- a/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java
+++ b/core/src/main/java/org/bitcoinj/evolution/SimplifiedMasternodeListManager.java
@@ -22,6 +22,9 @@
import org.bitcoinj.core.AbstractManager;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.DualBlockChain;
+import org.bitcoinj.core.GetDataMessage;
+import org.bitcoinj.core.InventoryItem;
+import org.bitcoinj.core.InventoryMessage;
import org.bitcoinj.core.MasternodeSync;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Peer;
@@ -32,8 +35,10 @@
import org.bitcoinj.core.Utils;
import org.bitcoinj.core.VarInt;
import org.bitcoinj.core.VerificationException;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.quorums.ChainLocksHandler;
import org.bitcoinj.quorums.FinalCommitment;
+import org.bitcoinj.quorums.InstantSendLock;
import org.bitcoinj.quorums.LLMQParameters;
import org.bitcoinj.quorums.Quorum;
import org.bitcoinj.quorums.QuorumManager;
@@ -57,6 +62,8 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
+
/**
* This class manages the state of the masternode lists and quorums. It does so with help from
* {@link QuorumState} for DIP4 quorums and {@link QuorumRotationState} for DIP24 quorums
@@ -65,7 +72,7 @@
* class {@link AbstractManager}
*/
-public class SimplifiedMasternodeListManager extends AbstractManager implements QuorumStateManager {
+public class SimplifiedMasternodeListManager extends MasternodeListManager {
private static final Logger log = LoggerFactory.getLogger(SimplifiedMasternodeListManager.class);
private final ReentrantLock lock = Threading.lock("SimplifiedMasternodeListManager");
@@ -127,7 +134,7 @@ public enum SaveOptions {
boolean requiresLoadingFromFile;
PeerGroup peerGroup;
-
+ protected MasternodeSync masternodeSync;
QuorumSnapshotManager quorumSnapshotManager;
QuorumManager quorumManager;
@@ -148,6 +155,22 @@ public SimplifiedMasternodeListManager(Context context) {
quorumRotationState.setStateManager(this);
}
+ public SimplifiedMasternodeListManager(Context context, DualBlockChain blockChain, @Nullable PeerGroup peerGroup,
+ QuorumManager quorumManager, QuorumSnapshotManager quorumSnapshotManager, ChainLocksHandler chainLocksHandler) {
+ super(context);
+ tipBlockHash = params.getGenesisBlock().getHash();
+
+ saveOptions = SaveOptions.SAVE_EVERY_CHANGE;
+ loadedFromFile = false;
+ requiresLoadingFromFile = true;
+
+ quorumState = new QuorumState(context, MasternodeListSyncOptions.SYNC_MINIMUM);
+ quorumState.setStateManager(this);
+ quorumRotationState = new QuorumRotationState(context);
+ quorumRotationState.setStateManager(this);
+ setBlockChain(blockChain, peerGroup, quorumManager, quorumSnapshotManager, chainLocksHandler, masternodeSync);
+ }
+
@Override
public int calculateMessageSizeInBytes() {
return 0;
@@ -277,8 +300,9 @@ public void updatedBlockTip(StoredBlock tip) {
}
protected boolean shouldProcessMNListDiff() {
- return context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_DMN_LIST) ||
- context.masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_QUORUM_LIST);
+
+ return masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_DMN_LIST) ||
+ masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_QUORUM_LIST);
}
@Override
@@ -295,7 +319,7 @@ public void processMasternodeListDiff(Peer peer, SimplifiedMasternodeListDiff mn
public void processMasternodeListDiff(@Nullable Peer peer, SimplifiedMasternodeListDiff mnlistdiff, boolean isLoadingBootStrap) {
try {
- quorumState.processDiff(peer, mnlistdiff, blockChain, isLoadingBootStrap, context.peerGroup.getSyncStage());
+ quorumState.processDiff(peer, mnlistdiff, blockChain, this, isLoadingBootStrap, peerGroup.getSyncStage());
processMasternodeList(mnlistdiff);
processQuorumList(quorumState.getQuorumListAtTip());
@@ -333,7 +357,7 @@ public void processQuorumRotationInfo(@Nullable Peer peer, QuorumRotationInfo qu
@Override
public void run() {
try {
- quorumRotationState.processDiff(peer, quorumRotationInfo, blockChain, isLoadingBootStrap, PeerGroup.SyncStage.BLOCKS);
+ quorumRotationState.processDiff(peer, quorumRotationInfo, blockChain, SimplifiedMasternodeListManager.this, isLoadingBootStrap, PeerGroup.SyncStage.BLOCKS);
processMasternodeList(quorumRotationInfo.getMnListDiffAtH());
unCache();
@@ -387,13 +411,18 @@ private void resetQuorumState() {
}
public void setBlockChain(DualBlockChain blockChain, @Nullable PeerGroup peerGroup,
- QuorumManager quorumManager, QuorumSnapshotManager quorumSnapshotManager, ChainLocksHandler chainLocksHandler) {
+ QuorumManager quorumManager, QuorumSnapshotManager quorumSnapshotManager, ChainLocksHandler chainLocksHandler,
+ MasternodeSync masternodeSync) {
this.blockChain = blockChain;
this.peerGroup = peerGroup;
+ if (peerGroup != null) {
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
this.quorumManager = quorumManager;
this.quorumSnapshotManager = quorumSnapshotManager;
- quorumState.setBlockChain(peerGroup, blockChain);
- quorumRotationState.setBlockChain(peerGroup, blockChain);
+ this.masternodeSync = masternodeSync;
+ quorumState.setBlockChain(peerGroup, blockChain, masternodeSync);
+ quorumRotationState.setBlockChain(peerGroup, blockChain, masternodeSync);
quorumState.setChainLocksHandler(chainLocksHandler);
quorumRotationState.setChainLocksHandler(chainLocksHandler);
if(shouldProcessMNListDiff()) {
@@ -415,6 +444,7 @@ public void close() {
quorumState.close();
quorumRotationState.close();
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
try {
threadPool.shutdown();
threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
@@ -509,6 +539,7 @@ public SimplifiedQuorumList getQuorumListForBlock(Sha256Hash blockHash, LLMQPara
}
}
+ @Override
public List getAllQuorumMembers(LLMQParameters.LLMQType llmqType, Sha256Hash blockHash)
{
if (isQuorumRotationEnabled(llmqType)) {
@@ -612,4 +643,15 @@ public void completeQuorumState(Peer peer) {
public ReentrantLock getLock() {
return lock;
}
+
+ public final PreMessageReceivedEventListener preMessageReceivedEventListener = (peer, m) -> {
+ if (m instanceof SimplifiedMasternodeListDiff) {
+ processMasternodeListDiff(peer, (SimplifiedMasternodeListDiff) m);
+ return null;
+ } else if (m instanceof QuorumRotationInfo) {
+ processQuorumRotationInfo(peer, (QuorumRotationInfo) m, false, null);
+ return null;
+ }
+ return m;
+ };
}
diff --git a/core/src/main/java/org/bitcoinj/governance/GovernanceManager.java b/core/src/main/java/org/bitcoinj/governance/GovernanceManager.java
index f04217aa19..0fd2f92183 100644
--- a/core/src/main/java/org/bitcoinj/governance/GovernanceManager.java
+++ b/core/src/main/java/org/bitcoinj/governance/GovernanceManager.java
@@ -1,11 +1,18 @@
package org.bitcoinj.governance;
import org.bitcoinj.core.*;
+import org.bitcoinj.core.listeners.GetDataEventListener;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
+import org.bitcoinj.evolution.MasternodeMetaDataManager;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.governance.listeners.GovernanceObjectAddedEventListener;
import org.bitcoinj.governance.listeners.GovernanceVoteConfidenceEventListener;
import org.bitcoinj.utils.*;
+import org.bitcoinj.wallet.Wallet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
@@ -19,6 +26,7 @@
import static org.bitcoinj.governance.GovernanceException.Type.GOVERNANCE_EXCEPTION_PERMANENT_ERROR;
import static org.bitcoinj.governance.GovernanceException.Type.GOVERNANCE_EXCEPTION_WARNING;
import static org.bitcoinj.governance.GovernanceObject.*;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
/**
* Created by HashEngineering on 5/11/2018.
@@ -80,6 +88,12 @@ public class GovernanceManager extends AbstractManager {
private HashSet setRequestedVotes;
private boolean fRateChecksEnabled;
+ private MasternodeSync masternodeSync;
+ private PeerGroup peerGroup;
+ private SimplifiedMasternodeListManager masternodeListManager;
+ private MasternodeMetaDataManager masternodeMetaDataManager;
+ private NetFullfilledRequestManager netFullfilledRequestManager;
+ private GovernanceTriggerManager triggerManager;
public GovernanceManager(Context context) {
super(context);
@@ -149,6 +163,7 @@ protected void parse() throws ProtocolException {
for(int i = 0; i < size; ++i) {
Sha256Hash hash = readHash();
GovernanceObjectFromFile govobj = new GovernanceObjectFromFile(params, payload, cursor);
+ govobj.setObjects(masternodeListManager, masternodeMetaDataManager, this, masternodeSync);
cursor += govobj.getMessageSize();
mapObjects.put(hash, govobj);
}
@@ -251,12 +266,89 @@ public AbstractManager createEmpty() {
return new GovernanceManager(Context.get());
}
+ public void setBlockChain(PeerGroup peerGroup, MasternodeSync masternodeSync, SimplifiedMasternodeListManager masternodeListManager, MasternodeMetaDataManager masternodeMetaDataManager, NetFullfilledRequestManager netFullfilledRequestManager, GovernanceTriggerManager triggerManager) {
+ this.peerGroup = peerGroup;
+ this.masternodeSync = masternodeSync;
+ this.masternodeListManager = masternodeListManager;
+ this.masternodeMetaDataManager = masternodeMetaDataManager;
+ this.netFullfilledRequestManager = netFullfilledRequestManager;
+ this.triggerManager = triggerManager;
+ if (peerGroup != null) {
+ peerGroup.addGetDataEventListener(SAME_THREAD, getDataEventListener);
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
+ }
+
+ GetDataEventListener getDataEventListener = new GetDataEventListener() {
+ @Nullable
+ @Override
+ public List getData(Peer peer, GetDataMessage m) {
+ lock.lock();
+ try {
+ LinkedList votes = new LinkedList<>();
+ LinkedList items = new LinkedList<>(m.getItems());
+ for (InventoryItem item : items) {
+ if (item.type == InventoryItem.Type.GovernanceObjectVote) {
+ if (haveVoteForHash(item.hash))
+ votes.add(getVoteForHash(item.hash));
+ }
+ }
+ return votes;
+ } finally {
+ lock.unlock();
+ }
+ }
+ };
+
+ PreMessageReceivedEventListener preMessageReceivedEventListener = new PreMessageReceivedEventListener() {
+ @Override
+ public Message onPreMessageReceived(Peer peer, Message m) {
+ if (m instanceof InventoryMessage) {
+ if (masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
+ InventoryMessage inv = (InventoryMessage) m;
+ List items = inv.getItems();
+ List instantSendLocks = new LinkedList<>();
+ for (InventoryItem item : items) {
+ switch (item.type) {
+ case GovernanceObject:
+ case GovernanceObjectVote:
+ instantSendLocks.add(item);
+ break;
+ default:
+ break;
+ }
+ }
+ Iterator it = instantSendLocks.iterator();
+ GetDataMessage getdata = new GetDataMessage(context.getParams());
+ while (it.hasNext()) {
+ InventoryItem item = it.next();
+ if(!confirmInventoryRequest(item)) {
+ getdata.addItem(item);
+ }
+ }
+ if (!getdata.getItems().isEmpty()) {
+ // This will cause us to receive a bunch of block or tx messages.
+ peer.sendMessage(getdata);
+ }
+ }
+ } else if (m instanceof GovernanceObject) {
+ processGovernanceObject(peer, (GovernanceObject)m);
+ return null;
+ } else if (m instanceof GovernanceVote) {
+ processGovernanceObjectVote(peer, (GovernanceVote)m);
+ return null;
+ }
+ return m;
+ }
+ };
+
public void processGovernanceObject(Peer peer, GovernanceObject govobj) {
Sha256Hash nHash = govobj.getHash();
+ govobj.setObjects(masternodeListManager, masternodeMetaDataManager, this, masternodeSync);
peer.setAskFor.remove(nHash);
- if(!context.masternodeSync.isBlockchainSynced()) {
+ if(!masternodeSync.isBlockchainSynced()) {
log.info("gobject--MNGOVERNANCEOBJECT -- masternode list not synced");
return;
}
@@ -340,7 +432,7 @@ public void processGovernanceObjectVote(Peer peer, GovernanceVote vote) {
peer.setAskFor.remove(nHash);
// Ignore such messages until masternode list is synced
- if (!context.masternodeSync.isBlockchainSynced()) {
+ if (!masternodeSync.isBlockchainSynced()) {
log.info("gobject--MNGOVERNANCEOBJECTVOTE -- masternode list not synced");
return;
}
@@ -357,11 +449,11 @@ public void processGovernanceObjectVote(Peer peer, GovernanceVote vote) {
GovernanceException exception = new GovernanceException();
if (processVote(peer, vote, exception)) {
log.info("gobject--MNGOVERNANCEOBJECTVOTE -- {} new", strHash);
- context.masternodeSync.bumpAssetLastTime("processGovernanceObjectVote");
+ masternodeSync.bumpAssetLastTime("processGovernanceObjectVote");
vote.relay();
} else {
log.info("gobject--MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = {}", exception.getMessage());
- if ((exception.getNodePenalty() != 0) && context.masternodeSync.isSynced()) {
+ if ((exception.getNodePenalty() != 0) && masternodeSync.isSynced()) {
//Misbehaving(pfrom.GetId(), exception.GetNodePenalty());
}
return;
@@ -496,7 +588,7 @@ public Pair masternodeRateCheck(GovernanceObject govobj, boole
result.setSecond(false);
- if (!context.masternodeSync.isSynced()) {
+ if (!masternodeSync.isSynced()) {
result.setFirst(true);
return result;
}
@@ -715,7 +807,7 @@ void addGovernanceObject(GovernanceObject govobj, Peer pfrom)
switch(govobj.getObjectType()) {
case GOVERNANCE_OBJECT_TRIGGER:
log.info("CGovernanceManager::AddGovernanceObject Before AddNewTrigger");
- context.triggerManager.addNewTrigger(nHash);
+ triggerManager.addNewTrigger(nHash);
log.info("CGovernanceManager::AddGovernanceObject After AddNewTrigger");
break;
case GOVERNANCE_OBJECT_WATCHDOG:
@@ -732,7 +824,7 @@ void addGovernanceObject(GovernanceObject govobj, Peer pfrom)
// Update the rate buffer
masternodeRateUpdate(govobj);
- context.masternodeSync.bumpAssetLastTime("addGovernanceObject");
+ masternodeSync.bumpAssetLastTime("addGovernanceObject");
// WE MIGHT HAVE PENDING/ORPHAN VOTES FOR THIS OBJECT
@@ -791,7 +883,7 @@ public GovernanceObject findGovernanceObject(Sha256Hash nHash)
public void doMaintenance()
{
- if(context.isLiteMode() || !context.masternodeSync.isSynced()) return;
+ if(masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE) || !masternodeSync.isSynced()) return;
// CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES
@@ -848,8 +940,6 @@ public boolean confirmInventoryRequest(InventoryItem inv) {
setHash.add(inv.hash);
log.info("gobject--CGovernanceManager::ConfirmInventoryRequest added inv to requested set, {}, object = {}", inv.type, inv);
}
-
- //log.info("gobject--CGovernanceManager::ConfirmInventoryRequest reached end, returning true");
return true;
} finally {
lock.unlock();
@@ -863,7 +953,7 @@ public void checkAndRemove() {
public void updateCachesAndClean() {
log.info("gobject--CGovernanceManager::UpdateCachesAndClean");
- List vecDirtyHashes = context.masternodeMetaDataManager.getAndClearDirtyGovernanceObjectHashes();
+ List vecDirtyHashes = masternodeMetaDataManager.getAndClearDirtyGovernanceObjectHashes();
lock.lock();
try {
@@ -914,7 +1004,7 @@ public void updateCachesAndClean() {
Iterator> it = mapObjects.entrySet().iterator();
// Clean up any expired or invalid triggers
- context.triggerManager.cleanAndRemove();
+ triggerManager.cleanAndRemove();
while (it.hasNext()) {
Map.Entry entry = it.next();
@@ -949,7 +1039,7 @@ public void updateCachesAndClean() {
if ((pObj.isSetCachedDelete() || pObj.isSetExpired()) && (nTimeSinceDeletion >= GOVERNANCE_DELETION_DELAY)) {
log.info("CGovernanceManager::UpdateCachesAndClean -- erase obj {}", entry.getValue());
- context.masternodeMetaDataManager.removeGovernanceObject(pObj.getHash());
+ masternodeMetaDataManager.removeGovernanceObject(pObj.getHash());
// Remove vote references
final LinkedList> listItems = mapVoteToObject.getItemList();
@@ -1067,11 +1157,9 @@ public void requestOrphanObjects() {
log.info("gobject--CGovernanceObject::RequestOrphanObjects -- number objects = {}\n", vecHashesFiltered.size());
- PeerGroup peerGroup = context.peerGroup;
peerGroup.getLock().lock();
try {
- for (int i = 0; i < vecHashesFiltered.size(); ++i) {
- final Sha256Hash nHash = vecHashesFiltered.get(i);
+ for (final Sha256Hash nHash : vecHashesFiltered) {
for (int j = 0; j < peerGroup.getConnectedPeers().size(); ++j) {
Peer node = peerGroup.getConnectedPeers().get(j);
if (node.isMasternode()) {
@@ -1144,7 +1232,7 @@ public void requestGovernanceObject(Peer pfrom, Sha256Hash nHash, boolean fUseFi
}
public void checkPostponedObjects() {
- if (!context.masternodeSync.isSynced()) {
+ if (!masternodeSync.isSynced()) {
return;
}
@@ -1241,7 +1329,7 @@ public int requestGovernanceObjectVotes() {
int nMaxObjRequestsPerNode = 1;
int nProjectedVotes = 2000;
if (params.getId() != NetworkParameters.ID_MAINNET) {
- nMaxObjRequestsPerNode = Math.max(1, (int)(nProjectedVotes / Math.max(1, context.masternodeListManager.getListAtChainTip().size())));
+ nMaxObjRequestsPerNode = Math.max(1, (int)(nProjectedVotes / Math.max(1, masternodeListManager.getListAtChainTip().size())));
}
@@ -1298,7 +1386,7 @@ public int requestGovernanceObjectVotes() {
nHashGovobj = vpGovObjsTmp.get(vpGovObjsTmp.size() - 1).getHash();
}
boolean fAsked = false;
- for (Peer pnode : context.peerGroup.getConnectedPeers()) {
+ for (Peer pnode : peerGroup.getConnectedPeers()) {
// Only use regular peers, don't try to ask from outbound "masternode" connections -
// they stay connected for a short period of time and it's possible that we won't get everything we should.
// Only use outbound connections - inbound connection could be a "masternode" connection
@@ -1368,7 +1456,7 @@ public void processGovernanceSyncMessage(Peer peer, GovernanceSyncMessage messag
// Ignore such requests until we are fully synced.
// We could start processing this after masternode list is synced
// but this is a heavy one so it's better to finish sync first.
- if (!context.masternodeSync.isSynced()) return;
+ if (!masternodeSync.isSynced()) return;
if(message.prop.isZero()) {
syncAll(peer);
@@ -1380,7 +1468,7 @@ public void processGovernanceSyncMessage(Peer peer, GovernanceSyncMessage messag
public void syncSingleObjAndItsVotes(Peer pnode, Sha256Hash nProp, BloomFilter filter) {
// do not provide any data until our node is synced
- if (!context.masternodeSync.isSynced()) {
+ if (!masternodeSync.isSynced()) {
return;
}
@@ -1418,7 +1506,7 @@ public void syncSingleObjAndItsVotes(Peer pnode, Sha256Hash nProp, BloomFilter f
//C++ TO JAVA CONVERTER TODO TASK: There is no equivalent to implicit typing in Java unless the Java 10 inferred typing option is selected:
for (GovernanceVote vote : fileVotes.getVotes()) {
Sha256Hash nVoteHash = vote.getHash();
- if (filter.contains(nVoteHash.getReversedBytes()) || !vote.isValid(true)) {
+ if (filter.contains(nVoteHash.getReversedBytes()) || !vote.isValid(true, masternodeListManager, masternodeSync)) {
continue;
}
pnode.pushInventory(new InventoryItem(InventoryItem.Type.GovernanceObjectVote, nVoteHash));
@@ -1435,18 +1523,18 @@ public void syncSingleObjAndItsVotes(Peer pnode, Sha256Hash nProp, BloomFilter f
public void syncAll(Peer pnode) {
// do not provide any data until our node is synced
- if (!context.masternodeSync.isSynced()) {
+ if (!masternodeSync.isSynced()) {
return;
}
- if (context.netFullfilledRequestManager.hasFulfilledRequest(pnode.getAddress(), "govsync")) {
+ if (netFullfilledRequestManager.hasFulfilledRequest(pnode.getAddress(), "govsync")) {
//LOCK(cs_main);
// Asking for the whole list multiple times in a short period of time is no good
log.info("gobject--CGovernanceManager:: -- peer already asked me for the list");
//Misbehaving(pnode.GetId(), 20);
return;
}
- context.netFullfilledRequestManager.addFulfilledRequest(pnode.getAddress(), "govsync");
+ netFullfilledRequestManager.addFulfilledRequest(pnode.getAddress(), "govsync");
int nObjCount = 0;
int nVoteCount = 0;
@@ -1568,7 +1656,7 @@ public boolean removeVoteConfidenceEventListener(GovernanceVoteConfidenceEventLi
private void queueOnTransactionConfidenceChanged(final GovernanceVote vote) {
checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration registration : voteConfidenceListeners) {
- if (registration.executor == Threading.SAME_THREAD) {
+ if (registration.executor == SAME_THREAD) {
registration.listener.onVoteConfidenceChanged(vote);
} else {
registration.executor.execute(new Runnable() {
@@ -1612,7 +1700,7 @@ public boolean removeGovernanceObjectAddedListener(GovernanceObjectAddedEventLis
private void queueOnGovernanceObjectAdded(final Sha256Hash nHash, final GovernanceObject object) {
checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration registration : governanceObjectAddedListeners) {
- if (registration.executor == Threading.SAME_THREAD) {
+ if (registration.executor == SAME_THREAD) {
registration.listener.onGovernanceObjectAdded(nHash, object);
} else {
registration.executor.execute(new Runnable() {
@@ -1627,6 +1715,9 @@ public void run() {
@Override
public void close() {
-
+ if (peerGroup != null) {
+ peerGroup.removeGetDataEventListener(getDataEventListener);
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
+ }
}
}
diff --git a/core/src/main/java/org/bitcoinj/governance/GovernanceObject.java b/core/src/main/java/org/bitcoinj/governance/GovernanceObject.java
index ef7ba4475b..f9b203c06a 100644
--- a/core/src/main/java/org/bitcoinj/governance/GovernanceObject.java
+++ b/core/src/main/java/org/bitcoinj/governance/GovernanceObject.java
@@ -20,6 +20,8 @@
import org.bitcoinj.crypto.BLSPublicKey;
import org.bitcoinj.crypto.BLSSignature;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.MasternodeMetaDataManager;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.utils.Pair;
import org.bitcoinj.utils.Threading;
import org.slf4j.Logger;
@@ -146,6 +148,12 @@ public void setDirtyCache(boolean fDirtyCache) {
private GovernanceObjectVoteFile fileVotes;
+ protected SimplifiedMasternodeListManager masternodeListManager;
+ protected GovernanceManager governanceManager;
+ private MasternodeMetaDataManager masternodeMetaDataManager;
+ protected MasternodeSync masternodeSync;
+
+
Context context;
public GovernanceObject(NetworkParameters params) {
super(params);
@@ -163,6 +171,13 @@ public GovernanceObject(NetworkParameters params, byte[] payload, int cursor) {
mapCurrentMNVotes = new HashMap<>();
}
+ public void setObjects(SimplifiedMasternodeListManager masternodeListManager, MasternodeMetaDataManager masternodeMetaDataManager, GovernanceManager governanceManager, MasternodeSync masternodeSync) {
+ this.masternodeListManager = masternodeListManager;
+ this. masternodeMetaDataManager = masternodeMetaDataManager;
+ this.governanceManager = governanceManager;
+ this.masternodeSync = masternodeSync;
+ }
+
public final long getCreationTime() {
return nTime;
}
@@ -377,7 +392,7 @@ public boolean isValidLocally(Validity validity, boolean fCheckCollateral) {
if (fCheckCollateral) {
if ((nObjectType == GOVERNANCE_OBJECT_TRIGGER) || (nObjectType == GOVERNANCE_OBJECT_WATCHDOG)) {
String strOutpoint = masternodeOutpoint.toStringShort();
- Masternode infoMn = context.masternodeListManager.getListAtChainTip().getMNByCollateral(masternodeOutpoint);
+ Masternode infoMn = masternodeListManager.getListAtChainTip().getMNByCollateral(masternodeOutpoint);
if (infoMn == null ) {
/* TODO: fix this
@@ -571,10 +586,10 @@ public String getDataAsPlainString() {
public void updateSentinelVariables() {
// CALCULATE MINIMUM SUPPORT LEVELS REQUIRED
- if(context.masternodeListManager.getLock().isHeldByCurrentThread()) {
+ if(masternodeListManager.getLock().isHeldByCurrentThread()) {
}
- int nMnCount = context.masternodeListManager.getListAtChainTip().countEnabled();
+ int nMnCount = masternodeListManager.getListAtChainTip().countEnabled();
if (nMnCount == 0) {
return;
}
@@ -664,13 +679,13 @@ public void relay() {
}
public boolean processVote(Peer pfrom, GovernanceVote vote, GovernanceException exception) {
- if (context.masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_MASTERNODE_LIST) &&
- context.masternodeListManager.getListAtChainTip().getMNByCollateral(vote.getMasternodeOutpoint()) == null) {
+ if (masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_MASTERNODE_LIST) &&
+ masternodeListManager.getListAtChainTip().getMNByCollateral(vote.getMasternodeOutpoint()) == null) {
String message = "CGovernanceObject::ProcessVote -- Masternode index not found";
exception.setException(message, GOVERNANCE_EXCEPTION_WARNING);
if (mapOrphanVotes.put(vote.getMasternodeOutpoint(), new Pair<>((int)(Utils.currentTimeSeconds() + GOVERNANCE_ORPHAN_EXPIRATION_TIME), vote))) {
if (pfrom != null) {
- //TODO: context.masternodeManager.askForMN(pfrom, vote.getMasternodeOutpoint());
+ //TODO: masternodeManager.askForMN(pfrom, vote.getMasternodeOutpoint());
}
log.info("{}", message);
} else {
@@ -714,7 +729,7 @@ public boolean processVote(Peer pfrom, GovernanceVote vote, GovernanceException
long nNow = Utils.currentTimeSeconds();
long nVoteTimeUpdate = voteInstance.nTime;
- if (context.governanceManager.areRateChecksEnabled()) {
+ if (governanceManager.areRateChecksEnabled()) {
long nTimeDelta = nNow - voteInstance.nTime;
if (nTimeDelta < GOVERNANCE_UPDATE_MIN) {
String oftenMessage = "CGovernanceObject::ProcessVote -- Masternode voting too often, MN outpoint = " +
@@ -727,14 +742,14 @@ public boolean processVote(Peer pfrom, GovernanceVote vote, GovernanceException
}
}
// Finally check that the vote is actually valid (done last because of cost of signature verification)
- if (!vote.isValid(true)) {
+ if (!vote.isValid(true, masternodeListManager, masternodeSync)) {
String validMessage = "CGovernanceObject::ProcessVote -- Invalid vote" + ", MN outpoint = " + vote.getMasternodeOutpoint().toStringShort() + ", governance object hash = " + getHash().toString() + ", vote hash = " + vote.getHash().toString();
log.info("gobject--{}", validMessage);
exception.setException(validMessage, GOVERNANCE_EXCEPTION_PERMANENT_ERROR, 20);
- context.governanceManager.addInvalidVote(vote);
+ governanceManager.addInvalidVote(vote);
return false;
}
- if (!context.masternodeMetaDataManager.addGovernanceVote(vote.getMasternodeOutpoint(), vote.getParentHash())) {
+ if (!masternodeMetaDataManager.addGovernanceVote(vote.getMasternodeOutpoint(), vote.getParentHash())) {
String unableMessage = "CGovernanceObject::ProcessVote -- Unable to add governance vote" + ", MN outpoint = " + vote.getMasternodeOutpoint().toStringShort() + ", governance object hash = " + getHash().toString();
log.info("gobject--{}", unableMessage);
exception.setException(unableMessage, GOVERNANCE_EXCEPTION_PERMANENT_ERROR);
@@ -758,7 +773,7 @@ public void clearMasternodeVotes() {
Iterator> it = mapCurrentMNVotes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
- if (context.masternodeListManager.getListAtChainTip().getMNByCollateral(entry.getKey()) == null) {
+ if (masternodeListManager.getListAtChainTip().getMNByCollateral(entry.getKey()) == null) {
fileVotes.removeVotesFromMasternode(entry.getKey());
it.remove();
}
diff --git a/core/src/main/java/org/bitcoinj/governance/GovernanceTriggerManager.java b/core/src/main/java/org/bitcoinj/governance/GovernanceTriggerManager.java
index 8f6d02f773..de0e3c803d 100644
--- a/core/src/main/java/org/bitcoinj/governance/GovernanceTriggerManager.java
+++ b/core/src/main/java/org/bitcoinj/governance/GovernanceTriggerManager.java
@@ -17,6 +17,7 @@ public class GovernanceTriggerManager {
Context context;
private HashMap mapTrigger;
+ private GovernanceManager governanceManager;
/**
* Add Governance Object
@@ -24,7 +25,7 @@ public class GovernanceTriggerManager {
public boolean addNewTrigger(Sha256Hash nHash) {
log.info("CGovernanceTriggerManager::AddNewTrigger: Start");
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
// IF WE ALREADY HAVE THIS HASH, RETURN
@@ -55,11 +56,11 @@ public boolean addNewTrigger(Sha256Hash nHash) {
return true;
} finally {
- context.governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
}
- public GovernanceTriggerManager(Context context) {
+ public GovernanceTriggerManager(Context context, GovernanceManager governanceManager) {
this.mapTrigger = new HashMap();
this.context = context;
}
@@ -72,13 +73,13 @@ public GovernanceTriggerManager(Context context) {
public void cleanAndRemove() {
log.info("gobject--CGovernanceTriggerManager::CleanAndRemove -- Start");
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
// LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS
for (Map.Entry it : mapTrigger.entrySet()) {
//int nNewStatus = -1;
- GovernanceObject pObj = context.governanceManager.findGovernanceObject(it.getKey());
+ GovernanceObject pObj = governanceManager.findGovernanceObject(it.getKey());
if (pObj == null) {
continue;
}
@@ -116,7 +117,7 @@ public void cleanAndRemove() {
// Rough approximation: a cycle of Superblock ++
int nExpirationBlock = nTriggerBlock + GOVERNANCE_TRIGGER_EXPIRATION_BLOCKS;
log.info("gobject--CGovernanceTriggerManager::CleanAndRemove -- nTriggerBlock = {}, nExpirationBlock = {}", nTriggerBlock, nExpirationBlock);
- if (context.governanceManager.getCachedBlockHeight() > nExpirationBlock) {
+ if (governanceManager.getCachedBlockHeight() > nExpirationBlock) {
log.info("gobject--CGovernanceTriggerManager::CleanAndRemove -- Outdated trigger found");
remove = true;
GovernanceObject pgovobj = pSuperblock.getGovernanceObject();
@@ -145,7 +146,7 @@ public void cleanAndRemove() {
}
}
} finally {
- context.governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
log.info("CGovernanceTriggerManager::CleanAndRemove: End");
@@ -159,7 +160,7 @@ public void cleanAndRemove() {
*/
public ArrayList getActiveTriggers() {
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
ArrayList vecResults = new ArrayList();
@@ -171,7 +172,7 @@ public ArrayList getActiveTriggers() {
Map.Entry entry = it.next();
- GovernanceObject pObj = context.governanceManager.findGovernanceObject(entry.getKey());
+ GovernanceObject pObj = governanceManager.findGovernanceObject(entry.getKey());
if (pObj != null) {
log.info("GetActiveTriggers: pObj->GetDataAsString() = " + pObj.getDataAsPlainString());
@@ -183,7 +184,7 @@ public ArrayList getActiveTriggers() {
return vecResults;
} finally {
- context.governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
}
diff --git a/core/src/main/java/org/bitcoinj/governance/GovernanceVote.java b/core/src/main/java/org/bitcoinj/governance/GovernanceVote.java
index 2bface3c73..42ce21b20a 100644
--- a/core/src/main/java/org/bitcoinj/governance/GovernanceVote.java
+++ b/core/src/main/java/org/bitcoinj/governance/GovernanceVote.java
@@ -19,6 +19,7 @@
import org.bitcoinj.crypto.BLSPublicKey;
import org.bitcoinj.crypto.BLSSignature;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -339,7 +340,7 @@ protected void bitcoinSerializeToStream(OutputStream stream) throws IOException
vchSig.bitcoinSerialize(stream);
}
- public boolean isValid(boolean useVotingKey) {
+ public boolean isValid(boolean useVotingKey, SimplifiedMasternodeListManager masternodeListManager, MasternodeSync masternodeSync) {
if (nTime > Utils.currentTimeSeconds() + (60 * 60)) {
log.info("gobject--CGovernanceVote::IsValid -- vote is too far ahead of current time - {} - nTime {} - Max Time {}", getHash().toString(), nTime, Utils.currentTimeSeconds() + (60 * 60));
return false;
@@ -357,8 +358,8 @@ public boolean isValid(boolean useVotingKey) {
return false;
}
- if(context.masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_MASTERNODE_LIST)) {
- Masternode dmn = context.masternodeListManager.getListAtChainTip().getMNByCollateral(masternodeOutpoint);
+ if(masternodeSync.syncFlags.contains(MasternodeSync.SYNC_FLAGS.SYNC_MASTERNODE_LIST)) {
+ Masternode dmn = masternodeListManager.getListAtChainTip().getMNByCollateral(masternodeOutpoint);
if (dmn == null) {
log.info("gobject--CGovernanceVote::IsValid -- Unknown Masternode - {}", masternodeOutpoint.toStringShort());
return false;
@@ -376,10 +377,10 @@ public boolean isValid(boolean useVotingKey) {
void relay () {
// Do not relay until fully synced
- if(!context.masternodeSync.isSynced()) {
- log.info("gobject--CGovernanceVote::Relay -- won't relay until fully synced");
- return;
- }
+// if(!context.masternodeSync.isSynced()) {
+// log.info("gobject--CGovernanceVote::Relay -- won't relay until fully synced");
+// return;
+// }
//InventoryItem inv = new InventoryItem(InventoryItem.Type.GovernanceObjectVote, getHash());
//context.peerGroup.relayInventory(inv, MIN_GOVERNANCE_PEER_PROTO_VERSION);
diff --git a/core/src/main/java/org/bitcoinj/governance/Superblock.java b/core/src/main/java/org/bitcoinj/governance/Superblock.java
index 754b424fa5..fb5edb8bfc 100644
--- a/core/src/main/java/org/bitcoinj/governance/Superblock.java
+++ b/core/src/main/java/org/bitcoinj/governance/Superblock.java
@@ -15,7 +15,7 @@ public class Superblock extends GovernanceObject {
private int nEpochStart;
private int nStatus;
- private ArrayList vecPayments;;
+ private ArrayList vecPayments;
Superblock(NetworkParameters params) {
super(params);
@@ -83,11 +83,11 @@ public final void setExecuted() {
}
public final GovernanceObject getGovernanceObject() {
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
- return context.governanceManager.findGovernanceObject(nGovObjHash);
+ return governanceManager.findGovernanceObject(nGovObjHash);
} finally {
- context.governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
}
diff --git a/core/src/main/java/org/bitcoinj/governance/SuperblockManager.java b/core/src/main/java/org/bitcoinj/governance/SuperblockManager.java
index 1dee8e2ef1..55cc978a49 100644
--- a/core/src/main/java/org/bitcoinj/governance/SuperblockManager.java
+++ b/core/src/main/java/org/bitcoinj/governance/SuperblockManager.java
@@ -12,18 +12,19 @@
* Created by Hash Engineering on 6/6/2018.
*/
public class SuperblockManager {
+ private GovernanceManager governanceManager;
private static final Logger log = LoggerFactory.getLogger(SuperblockManager.class);
- public static boolean isSuperblockTriggered(int nBlockHeight) {
+ public static boolean isSuperblockTriggered(int nBlockHeight, GovernanceManager governanceManager, GovernanceTriggerManager triggerManager) {
log.info("gobject--CSuperblockManager::IsSuperblockTriggered -- Start nBlockHeight = {}", nBlockHeight);
if (!Superblock.isValidBlockHeight(Context.get().getParams(), nBlockHeight)) {
return false;
}
- Context.get().governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
// GET ALL ACTIVE TRIGGERS
- ArrayList vecTriggers = Context.get().triggerManager.getActiveTriggers();
+ ArrayList vecTriggers = triggerManager.getActiveTriggers();
log.info("gobject--CSuperblockManager::IsSuperblockTriggered -- vecTriggers.size() = {}", vecTriggers.size());
@@ -67,21 +68,21 @@ public static boolean isSuperblockTriggered(int nBlockHeight) {
return false;
} finally {
- Context.get().governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
}
- public static Superblock getBestSuperblock(int nBlockHeight) {
+ public static Superblock getBestSuperblock(int nBlockHeight, GovernanceManager governanceManager, GovernanceTriggerManager triggerManager) {
Context context = Context.get();
if (!Superblock.isValidBlockHeight(context.getParams(), nBlockHeight)) {
return null;
}
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
Superblock superblockResult = null;
- ArrayList vecTriggers = context.triggerManager.getActiveTriggers();
+ ArrayList vecTriggers = triggerManager.getActiveTriggers();
int nYesCount = 0;
for (Superblock pSuperblock : vecTriggers) {
@@ -115,21 +116,21 @@ public static Superblock getBestSuperblock(int nBlockHeight) {
return nYesCount > 0 ? superblockResult : null;
} finally {
- context.governanceManager.lock.unlock();
+ governanceManager.lock.unlock();
}
}
- public static Transaction createSuperblock(int nBlockHeight, ArrayList voutSuperblockRet) {
+ public static Transaction createSuperblock(int nBlockHeight, ArrayList voutSuperblockRet, GovernanceManager governanceManager, GovernanceTriggerManager triggerManager) {
log.info( "CSuperblockManager::CreateSuperblock Start");
Context context = Context.get();
- context.governanceManager.lock.lock();
+ governanceManager.lock.lock();
try {
Transaction tx = new Transaction(context.getParams());
// GET THE BEST SUPERBLOCK FOR THIS BLOCK HEIGHT
- Superblock pSuperblock = SuperblockManager.getBestSuperblock(nBlockHeight);
+ Superblock pSuperblock = SuperblockManager.getBestSuperblock(nBlockHeight, governanceManager, triggerManager);
if (pSuperblock == null) {
log.info("gobject--CSuperblockManager::CreateSuperblock -- Can't find superblock for height {}", nBlockHeight);
log.info("CSuperblockManager::CreateSuperblock Failed to get superblock for height, returning");
@@ -175,39 +176,36 @@ public static Transaction createSuperblock(int nBlockHeight, ArrayList scheduledMasternodeSync;
+ private ScheduledFuture> scheduledNetFulfilled;
+ private ScheduledFuture> scheduledGovernance;
+
+ Context context;
+
+ public DashSystem(Context context) {
+ String id = context.getParams().getId();
+// if (systemMap.containsKey(id)) {
+// throw new IllegalArgumentException("There is already a system for " + id);
+// }
+ this.context = context;
+ scheduledExecutorService = Executors.newScheduledThreadPool(2, new ContextPropagatingThreadFactory("context-thread-pool"));
+ systemMap.put(id, this);
+ }
+
+ public Context getContext() {
+ return context;
+ }
+
+ public NetworkParameters getParams() {
+ return context.getParams();
+ }
+
+ //
+ // Dash Specific
+ //
+ private boolean initializedObjects = false;
+ private boolean initializedFiles = false;
+
+ @Deprecated
+ public boolean isInitializedDash() {
+ return initializedObjects;
+ }
+
+ public void initDash(boolean liteMode, boolean allowInstantX) {
+ initDash(liteMode, allowInstantX, null);
+ }
+
+ public void initDash(boolean liteMode, boolean allowInstantX, @Nullable EnumSet syncFlags) {
+ initDash(liteMode, allowInstantX, syncFlags, null);
+ }
+ public void initDash(boolean liteMode, boolean allowInstantX, @Nullable EnumSet syncFlags,
+ @Nullable EnumSet verifyFlags) {
+
+ this.liteMode = liteMode;
+ this.allowInstantX = allowInstantX;
+
+ //Dash Specific
+ sporkManager = new SporkManager(context);
+
+ masternodePayments = new MasternodePayments(context);
+ masternodeSync = syncFlags != null ? new MasternodeSync(context, syncFlags, verifyFlags) : new MasternodeSync(context, isLiteMode(), allowInstantXinLiteMode());
+ governanceManager = new GovernanceManager(context);
+ triggerManager = new GovernanceTriggerManager(context, governanceManager);
+
+ netFullfilledRequestManager = new NetFullfilledRequestManager(context);
+ masternodeListManager = new SimplifiedMasternodeListManager(context);
+ recoveredSigsDB = new SPVRecoveredSignaturesDatabase(context);
+ quorumManager = new SPVQuorumManager(context, masternodeListManager);
+ quorumSnapshotManager = new QuorumSnapshotManager(context);
+ signingManager = new SigningManager(context, recoveredSigsDB, quorumManager, masternodeSync);
+
+ instantSendDB = new SPVInstantSendDatabase(context);
+ instantSendManager = new InstantSendManager(context, instantSendDB, signingManager);
+ chainLockHandler = new ChainLocksHandler(context);
+ llmqBackgroundThread = new LLMQBackgroundThread(context, instantSendManager, chainLockHandler, signingManager, masternodeListManager);
+ masternodeMetaDataManager = new MasternodeMetaDataManager(context);
+ coinJoinManager = new CoinJoinManager(context, scheduledExecutorService, masternodeListManager, masternodeMetaDataManager, masternodeSync, chainLockHandler);
+ initializedObjects = true;
+ }
+
+ public void setMasternodeListManager(SimplifiedMasternodeListManager masternodeListManager) {
+ this.masternodeListManager = masternodeListManager;
+ DualBlockChain dualBlockChain = new DualBlockChain(headerChain, blockChain);
+ masternodeListManager.setBlockChain(dualBlockChain, peerGroup, quorumManager, quorumSnapshotManager, chainLockHandler, masternodeSync);
+ }
+
+ public void closeDash() {
+ //Dash Specific
+ close();
+ sporkManager = null;
+
+ masternodePayments = null;
+ masternodeSync = null;
+ initializedObjects = false;
+ governanceManager = null;
+ masternodeListManager = null;
+ }
+
+ public boolean initDashSync(final String directory) {
+ return initDashSync(directory, null);
+ }
+
+ /**
+ * Initializes objects by loading files from the specified directory
+ *
+ * @param directory location of the files
+ * @param filePrefix file prefix of the files, typically the network name
+ * @return true if the files are loaded. false if the files were already loaded
+ */
+ public boolean initDashSync(final String directory, @Nullable String filePrefix) {
+ if (!initializedFiles) {
+ // remove mncache.dat if it exists
+ File oldMnCacheFile = new File(directory, "mncache.dat");
+ if (oldMnCacheFile.exists()) {
+ if (oldMnCacheFile.delete())
+ log.info("removed obsolete mncache.dat");
+ }
+
+ // load governance data
+ if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
+ FlatDB gmdb;
+ if (filePrefix != null) {
+ gmdb = new FlatDB<>(context, directory + File.separator + filePrefix + ".gobjects", true);
+ } else {
+ gmdb = new FlatDB<>(context, directory, false);
+ }
+ gmdb.load(governanceManager);
+ }
+
+ // load masternode data
+ FlatDB smnl;
+ if (filePrefix != null) {
+ smnl = new FlatDB<>(context, directory + File.separator + filePrefix + ".mnlist", true);
+ } else {
+ smnl = new FlatDB<>(context, directory, false);
+ }
+ smnl.load(masternodeListManager);
+ masternodeListManager.setLoadedFromFile(true);
+ masternodeListManager.onFirstSaveComplete();
+
+
+ // Load chainlocks
+ FlatDB clh;
+ if (filePrefix != null) {
+ clh = new FlatDB<>(context, directory + File.separator + filePrefix + ".chainlocks", true);
+ } else {
+ clh = new FlatDB<>(context, directory, false);
+ }
+ clh.load(chainLockHandler);
+
+ // Load Masternode Metadata
+ FlatDB mmdm;
+ if (filePrefix != null) {
+ mmdm = new FlatDB<>(context, directory + File.separator + filePrefix + ".mnmetadata", true);
+ } else {
+ mmdm = new FlatDB<>(context, directory, false);
+ }
+ mmdm.load(masternodeMetaDataManager);
+
+ signingManager.initializeSignatureLog(directory);
+ initializedFiles = true;
+ return true;
+ }
+ return false;
+ }
+
+ private void startLLMQThread() {
+ if (llmqBackgroundThread == null || !llmqBackgroundThread.isAlive()) {
+ llmqBackgroundThread = new LLMQBackgroundThread(context, instantSendManager, chainLockHandler, signingManager, masternodeListManager);
+ log.info("starting LLMQThread");
+ llmqBackgroundThread.start();
+ }
+ }
+
+ private void stopLLMQThread() {
+ if (llmqBackgroundThread.isAlive()) {
+ log.info("stopping LLMQThread");
+ llmqBackgroundThread.interrupt();
+ }
+ }
+
+ public void close() {
+ if (initializedObjects) {
+ sporkManager.close(peerGroup);
+ masternodeSync.close();
+ masternodeListManager.close();
+ instantSendManager.close(peerGroup);
+ signingManager.close();
+ chainLockHandler.close();
+ quorumManager.close();
+ coinJoinManager.close();
+ if(masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS))
+ llmqBackgroundThread.interrupt();
+ blockChain.removeNewBestBlockListener(newBestBlockListener);
+ if (scheduledMasternodeSync != null)
+ scheduledMasternodeSync.cancel(true);
+ blockChain.close();
+ if (headerChain != null)
+ headerChain.close();
+ peerGroup = null;
+ }
+ }
+
+ public void setPeerGroupAndBlockChain(PeerGroup peerGroup, AbstractBlockChain blockChain, @Nullable AbstractBlockChain headerChain) {
+ if (this.peerGroup == null/* && initializedObjects*/) {
+ 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());
+ if (initializedObjects) {
+ sporkManager.setBlockChain(blockChain, peerGroup, masternodeSync);
+ masternodeSync.setBlockChain(blockChain, peerGroup, netFullfilledRequestManager, governanceManager);
+ masternodeListManager.setBlockChain(
+ dualBlockChain,
+ peerGroup,
+ quorumManager,
+ quorumSnapshotManager,
+ chainLockHandler,
+ masternodeSync
+ );
+ instantSendManager.setBlockChain(blockChain, peerGroup, chainLockHandler, masternodeSync, sporkManager, masternodeListManager);
+ signingManager.setBlockChain(blockChain, headerChain, masternodeListManager);
+ chainLockHandler.setBlockChain(peerGroup, blockChain, headerChain, signingManager, sporkManager, masternodeSync);
+ blockChain.setChainLocksHandler(chainLockHandler);
+ quorumManager.setBlockChain(blockChain);
+ updatedChainHead(blockChain.getChainHead());
+ governanceManager.setBlockChain(peerGroup, masternodeSync, masternodeListManager, masternodeMetaDataManager, netFullfilledRequestManager, triggerManager);
+ coinJoinManager.initMasternodeGroup(blockChain);
+ coinJoinManager.setBlockchain(blockChain, peerGroup);
+
+ // trigger saving mechanisms
+ governanceManager.resume();
+ masternodeListManager.resume();
+ chainLockHandler.resume();
+ }
+ context.getParams().setDIPActiveAtTip(blockChain.getBestChainHeight() >= context.getParams().getDIP0001BlockHeight());
+ }
+ }
+
+ public boolean isLiteMode() {
+ return liteMode;
+ }
+
+// public void setLiteMode(boolean liteMode)
+// {
+// boolean current = this.liteMode;
+// if(current == liteMode)
+// return;
+//
+// this.liteMode = liteMode;
+// }
+
+ public boolean allowInstantXinLiteMode() {
+ return allowInstantX;
+ }
+
+ public void setAllowInstantXinLiteMode(boolean allow) {
+ this.allowInstantX = allow;
+ }
+
+ NewBestBlockListener newBestBlockListener = new NewBestBlockListener() {
+ @Override
+ public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
+ handleActivations(block);
+ boolean fInitialDownload = blockChain.getChainHead().getHeader().getTimeSeconds() < (Utils.currentTimeSeconds() - 6 * 60 * 60); // ~144 blocks behind -> 2 x fork detection time, was 24 * 60 * 60 in bitcoin
+ if(masternodeSync != null)
+ masternodeSync.updateBlockTip(block, fInitialDownload);
+ }
+ };
+
+ private void handleActivations(StoredBlock block) {
+ // 24 hours before the hard fork (v19.2) connect only to v19.2 nodes on mainnet
+ if (context.getParams().isV19Active(block.getHeight())) {
+ BLSScheme.setLegacyDefault(false);
+ }
+ }
+
+ @Deprecated
+ public void updatedChainHead(StoredBlock chainHead)
+ {
+ context.getParams().setDIPActiveAtTip(chainHead.getHeight() >= context.getParams().getDIP0001BlockHeight());
+ if(initializedObjects) {
+ masternodeListManager.updatedBlockTip(chainHead);
+ }
+ }
+
+ public Set getSyncFlags() {
+ if (masternodeSync != null) {
+ return masternodeSync.syncFlags;
+ } else {
+ return MasternodeSync.SYNC_DEFAULT_SPV;
+ }
+ }
+
+ public boolean hasSyncFlag(MasternodeSync.SYNC_FLAGS syncFlag) {
+ return getSyncFlags().contains(syncFlag);
+ }
+
+ public void start() {
+ if(getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
+ startLLMQThread();
+ }
+
+ if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
+ scheduledMasternodeSync = scheduledExecutorService.scheduleWithFixedDelay(
+ () -> masternodeSync.doMaintenance(), 1, 1, TimeUnit.SECONDS);
+ scheduledNetFulfilled = scheduledExecutorService.scheduleWithFixedDelay(
+ () -> netFullfilledRequestManager.doMaintenance(), 60, 60, TimeUnit.SECONDS);
+
+ scheduledGovernance = scheduledExecutorService.scheduleWithFixedDelay(
+ () -> governanceManager.doMaintenance(), 60, 5, TimeUnit.MINUTES);
+ }
+ }
+
+ public void shutdown() {
+ if(getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
+ stopLLMQThread();
+ }
+
+ if (getSyncFlags().contains(MasternodeSync.SYNC_FLAGS.SYNC_GOVERNANCE)) {
+ scheduledMasternodeSync.cancel(false);
+ scheduledMasternodeSync = null;
+ scheduledNetFulfilled.cancel(false);
+ scheduledNetFulfilled = null;
+ scheduledGovernance.cancel(false);
+ scheduledGovernance = null;
+ }
+ if (initializedObjects) {
+ coinJoinManager.stop();
+ }
+ }
+
+ private static final HashMap systemMap = new HashMap<>(3);
+ public static DashSystem get(NetworkParameters parameters) {
+ return systemMap.get(parameters.getId());
+ }
+ public static void remove(DashSystem system) {
+ systemMap.remove(system.getParams().getId());
+ }
+ public void remove() {
+ systemMap.remove(getParams().getId());
+ }
+
+ public void triggerHeadersDownloadComplete() {
+ peerGroup.triggerHeadersDownloadComplete();
+ }
+
+ public void triggerMnListDownloadComplete() {
+ peerGroup.triggerMnListDownloadComplete();
+ }
+
+ public void addWallet(Wallet wallet) {
+ instantSendManager.addWallet(wallet);
+ }
+}
diff --git a/core/src/main/java/org/bitcoinj/masternode/owner/MasternodeControl.java b/core/src/main/java/org/bitcoinj/masternode/owner/MasternodeControl.java
index f9c7d1b9d4..2450efc68a 100644
--- a/core/src/main/java/org/bitcoinj/masternode/owner/MasternodeControl.java
+++ b/core/src/main/java/org/bitcoinj/masternode/owner/MasternodeControl.java
@@ -2,9 +2,12 @@
import org.bitcoinj.core.*;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.governance.GovernanceException;
+import org.bitcoinj.governance.GovernanceManager;
import org.bitcoinj.governance.GovernanceVote;
import org.bitcoinj.governance.GovernanceVoteBroadcast;
+import org.bitcoinj.governance.GovernanceVoteBroadcaster;
import org.bitcoinj.governance.GovernanceVoting;
import java.io.File;
@@ -24,6 +27,9 @@ public class MasternodeControl {
* The Context.
*/
Context context;
+ private final SimplifiedMasternodeListManager masternodeListManager;
+ private final GovernanceManager governanceManager;
+ private final GovernanceVoteBroadcaster broadcaster;
/**
* Instantiates a new Masternode control.
@@ -31,9 +37,15 @@ public class MasternodeControl {
* @param context the context
* @param masternodeConfigFile the masternode config file
*/
- public MasternodeControl(Context context, File masternodeConfigFile) {
+ public MasternodeControl(Context context, File masternodeConfigFile,
+ GovernanceVoteBroadcaster broadcaster,
+ SimplifiedMasternodeListManager masternodeListManager,
+ GovernanceManager governanceManager) {
this.context = context;
masternodeConfig = new MasternodeConfig(masternodeConfigFile);
+ this.masternodeListManager = masternodeListManager;
+ this.governanceManager = governanceManager;
+ this.broadcaster = broadcaster;
}
/**
@@ -42,8 +54,11 @@ public MasternodeControl(Context context, File masternodeConfigFile) {
* @param context the context
* @param masternodeConfigFile the masternode config file name
*/
- public MasternodeControl(Context context, String masternodeConfigFile) {
- this(context, new File(masternodeConfigFile));
+ public MasternodeControl(Context context, String masternodeConfigFile,
+ GovernanceVoteBroadcaster broadcaster,
+ SimplifiedMasternodeListManager masternodeListManager,
+ GovernanceManager governanceManager) {
+ this(context, new File(masternodeConfigFile), broadcaster, masternodeListManager, governanceManager);
}
public void addConfig(String alias, String ip, String privKey, String txHash, String outputIndex) {
@@ -127,7 +142,7 @@ public GovernanceVoteBroadcast voteAlias(String alias, String governanceHash, St
TransactionOutPoint outpoint = new TransactionOutPoint(context.getParams(), nOutputIndex, nTxHash);
- Masternode mn = context.masternodeListManager.getListAtChainTip().getMNByCollateral(outpoint);
+ Masternode mn = masternodeListManager.getListAtChainTip().getMNByCollateral(outpoint);
if(mn == null) {
nFailed++;
@@ -147,19 +162,19 @@ public GovernanceVoteBroadcast voteAlias(String alias, String governanceHash, St
// UPDATE LOCAL DATABASE WITH NEW OBJECT SETTINGS
GovernanceException exception = new GovernanceException();
- if(context.governanceManager.processVoteAndRelay(vote, exception)) {
+ if(governanceManager.processVoteAndRelay(vote, exception)) {
nSuccessful++;
- errorMessage.append(alias + "voting successful\n");
- broadcast = context.peerGroup.broadcastGovernanceVote(vote);
+ errorMessage.append(alias).append("voting successful\n");
+ broadcast = broadcaster.broadcastGovernanceVote(vote);
} else {
nFailed++;
- errorMessage.append(alias + "-- failure --" + exception.getMessage() + "\n");
+ errorMessage.append(alias).append("-- failure --").append(exception.getMessage()).append("\n");
}
}
// REPORT STATS TO THE USER
- errorMessage.append("overall result : " + String.format("Voted successfully %d time(s) and failed %d time(s).", nSuccessful, nFailed));
+ errorMessage.append("overall result : ").append(String.format("Voted successfully %d time(s) and failed %d time(s).", nSuccessful, nFailed));
return broadcast;
}
@@ -225,7 +240,7 @@ public boolean voteMany(String alias, String governanceHash, String voteSignal,
TransactionOutPoint outpoint = new TransactionOutPoint(context.getParams(), nOutputIndex, nTxHash);
- Masternode mn = context.masternodeListManager.getListAtChainTip().getMNByCollateral(outpoint);
+ Masternode mn = masternodeListManager.getListAtChainTip().getMNByCollateral(outpoint);
if(mn == null) {
nFailed++;
@@ -245,7 +260,7 @@ public boolean voteMany(String alias, String governanceHash, String voteSignal,
// UPDATE LOCAL DATABASE WITH NEW OBJECT SETTINGS
GovernanceException exception = new GovernanceException();
- if(context.governanceManager.processVoteAndRelay(vote, exception)) {
+ if(governanceManager.processVoteAndRelay(vote, exception)) {
nSuccessful++;
errorMessage.append(alias + "voting successful\n");
} else {
diff --git a/core/src/main/java/org/bitcoinj/quorums/ChainLocksHandler.java b/core/src/main/java/org/bitcoinj/quorums/ChainLocksHandler.java
index 8b9ea2e0fd..133f78101e 100644
--- a/core/src/main/java/org/bitcoinj/quorums/ChainLocksHandler.java
+++ b/core/src/main/java/org/bitcoinj/quorums/ChainLocksHandler.java
@@ -18,6 +18,7 @@
import com.google.common.annotations.VisibleForTesting;
import org.bitcoinj.core.*;
import org.bitcoinj.core.listeners.NewBestBlockListener;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.crypto.BLSSecretKey;
import org.bitcoinj.crypto.BLSSignature;
import org.bitcoinj.quorums.listeners.ChainLockListener;
@@ -36,12 +37,17 @@
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkState;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
/**
* Manages ChainLocks
@@ -60,6 +66,10 @@ public class ChainLocksHandler extends AbstractManager implements RecoveredSigna
boolean isEnforced;
AbstractBlockChain blockChain;
AbstractBlockChain headerChain;
+ protected PeerGroup peerGroup;
+ protected SigningManager signingManager;
+ protected SporkManager sporkManager;
+ protected MasternodeSync masternodeSync;
Sha256Hash bestChainLockHash;
ChainLockSignature bestChainLock;
@@ -94,15 +104,34 @@ public ChainLocksHandler(Context context) {
chainLockListeners = new CopyOnWriteArrayList<>();
}
- public void setBlockChain(AbstractBlockChain blockChain, AbstractBlockChain headerChain) {
+// public ChainLocksHandler(Context context, AbstractBlockChain blockChain, AbstractBlockChain headerChain) {
+// super(context);
+// seenChainLocks = new HashMap<>();
+// lastCleanupTime = 0;
+// chainLockListeners = new CopyOnWriteArrayList<>();
+// setBlockChain(blockChain, headerChain);
+// }
+
+ public void setBlockChain(PeerGroup peerGroup, AbstractBlockChain blockChain, AbstractBlockChain headerChain, SigningManager signingManager, SporkManager sporkManager, MasternodeSync masternodeSync) {
this.blockChain = blockChain;
+ this.peerGroup = peerGroup;
+ if (peerGroup != null) {
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
+ blockChain.setChainLocksHandler(this);
this.headerChain = headerChain;
- this.quorumSigningManager = context.signingManager;
+ this.quorumSigningManager = signingManager;
+ this.signingManager = signingManager;
+ this.sporkManager = sporkManager;
+ this.masternodeSync = masternodeSync;
}
@Override
public void close() {
blockChain = null;
+ headerChain = null;
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
+ peerGroup = null;
super.close();
}
@@ -164,7 +193,7 @@ public ChainLockSignature getChainLockByHash(Sha256Hash hash) {
public void processChainLockSignature(Peer peer, ChainLockSignature clsig)
{
- if (!context.sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED)) {
+ if (!sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED)) {
return;
}
@@ -191,7 +220,7 @@ void processNewChainLock(Peer from, ChainLockSignature clsig, Sha256Hash hash)
log.info("process chainlock: {}", hash);
Sha256Hash requestId = clsig.getRequestId();
Sha256Hash msgHash = clsig.blockHash;
- if(context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.CHAINLOCK)) {
+ if (masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.CHAINLOCK)) {
try {
if (!quorumSigningManager.verifyRecoveredSig(context.getParams().getLlmqChainLocks(), clsig.height, requestId, msgHash, clsig.signature)) {
log.info("invalid CLSIG ({}), peer={}", clsig, from != null ? from : "null");
@@ -313,7 +342,7 @@ void checkActiveState() {
boolean isDIP0008Active = (blockChain.getBestChainHeight() - 1) > params.getDIP0008BlockHeight();
boolean oldIsEnforced = isEnforced;
- isSporkActive = context.sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED);
+ isSporkActive = sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED);
isEnforced = (isDIP0008Active && isSporkActive);
if (!oldIsEnforced && isEnforced) {
@@ -639,4 +668,35 @@ public ChainLockSignature getCoinbaseChainLock(Sha256Hash blockHash) {
public ChainLockSignature getChainLock(Sha256Hash blockHash) {
return chainlockMap.get(blockHash);
}
+
+ public final PreMessageReceivedEventListener preMessageReceivedEventListener = (peer, m) -> {
+ if (m instanceof InventoryMessage) {
+ if (masternodeSync != null && masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_CHAINLOCKS)) {
+ InventoryMessage inv = (InventoryMessage) m;
+ List items = inv.getItems();
+ List chainLocks = new LinkedList<>();
+ for (InventoryItem item : items) {
+ if (Objects.requireNonNull(item.type) == InventoryItem.Type.ChainLockSignature) {
+ chainLocks.add(item);
+ }
+ }
+ Iterator it = chainLocks.iterator();
+ GetDataMessage getdata = new GetDataMessage(context.getParams());
+ while (it.hasNext()) {
+ InventoryItem item = it.next();
+ if(!alreadyHave(item)) {
+ getdata.addItem(item);
+ }
+ }
+ if (!getdata.getItems().isEmpty()) {
+ // This will cause us to receive a bunch of block or tx messages.
+ peer.sendMessage(getdata);
+ }
+ }
+ } else if (m instanceof ChainLockSignature) {
+ processChainLockSignature(peer, (ChainLockSignature) m);
+ return null;
+ }
+ return m;
+ };
}
diff --git a/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java b/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java
index c855c68a5c..4c48857154 100644
--- a/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java
+++ b/core/src/main/java/org/bitcoinj/quorums/FinalCommitment.java
@@ -24,6 +24,7 @@
import org.bitcoinj.crypto.BLSSignature;
import org.bitcoinj.evolution.Masternode;
import org.bitcoinj.evolution.SpecialTxPayload;
+import org.bitcoinj.manager.DashSystem;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -310,14 +311,15 @@ public boolean verify(StoredBlock block, List members, boolean check
return false;
}
- Context.get().signingManager.logSignature("QUORUM", quorumPublicKey.getPublicKey(), commitmentHash, quorumSignature.getSignature());
-
- if(Context.get().masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES)) {
- if (!quorumSignature.getSignature().verifyInsecure(quorumPublicKey.getPublicKey(), commitmentHash, isLegacy())) {
- log.error("invalid quorum signature");
- return false;
- }
- }
+ // TODO: remove signing manager requirements
+// signingManager.logSignature("QUORUM", quorumPublicKey.getPublicKey(), commitmentHash, quorumSignature.getSignature());
+//
+// if(masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES)) {
+// if (!quorumSignature.getSignature().verifyInsecure(quorumPublicKey.getPublicKey(), commitmentHash, isLegacy())) {
+// log.error("invalid quorum signature");
+// return false;
+// }
+// }
}
verified = true;
return true;
diff --git a/core/src/main/java/org/bitcoinj/quorums/InstantSendManager.java b/core/src/main/java/org/bitcoinj/quorums/InstantSendManager.java
index b68bda0866..01a39e0f1c 100644
--- a/core/src/main/java/org/bitcoinj/quorums/InstantSendManager.java
+++ b/core/src/main/java/org/bitcoinj/quorums/InstantSendManager.java
@@ -6,8 +6,10 @@
import org.bitcoinj.core.*;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.core.listeners.OnTransactionBroadcastListener;
+import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.core.listeners.TransactionReceivedInBlockListener;
import org.bitcoinj.crypto.BLSBatchVerifier;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.quorums.listeners.RecoveredSignatureListener;
import org.bitcoinj.quorums.listeners.ChainLockListener;
import org.bitcoinj.store.BlockStore;
@@ -16,6 +18,8 @@
import org.bitcoinj.utils.ContextPropagatingThreadFactory;
import org.bitcoinj.utils.Pair;
import org.bitcoinj.utils.Threading;
+import org.bitcoinj.wallet.Wallet;
+import org.bitcoinj.wallet.listeners.WalletCoinsSentEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -25,6 +29,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
@@ -32,6 +37,8 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
+import static org.bitcoinj.utils.Threading.SAME_THREAD;
+
public class InstantSendManager implements RecoveredSignatureListener {
Context context;
@@ -39,13 +46,19 @@ public class InstantSendManager implements RecoveredSignatureListener {
private static final Logger log = LoggerFactory.getLogger(InstantSendManager.class);
ReentrantLock lock = Threading.lock("InstantSendManager");
- InstantSendDatabase db;
+ protected InstantSendDatabase db;
+ protected ChainLocksHandler chainLocksHandler;
+ protected PeerGroup peerGroup;
+ protected MasternodeSync masternodeSync;
+ protected SporkManager sporkManager;
+ protected SimplifiedMasternodeListManager masternodeListManager;
@Deprecated
Thread workThread;
@Deprecated
private boolean runWithoutThread = true;
private ScheduledExecutorService scheduledExecutorService;
AbstractBlockChain blockChain;
+ private ArrayList wallets = new ArrayList<>();
//Keep track of when the ISLOCK arrived
HashMap invalidInstantSendLocks;
@@ -53,13 +66,25 @@ public class InstantSendManager implements RecoveredSignatureListener {
// Incoming and not verified yet
HashMap> pendingInstantSendLocks;
- public InstantSendManager(Context context, InstantSendDatabase db) {
+ public InstantSendManager(Context context, InstantSendDatabase db, SigningManager signingManager) {
+ this.context = context;
+ this.db = db;
+ this.quorumSigningManager = signingManager;
+ pendingInstantSendLocks = new HashMap<>();
+ invalidInstantSendLocks = new HashMap<>();
+ scheduledExecutorService = createScheduledExecutorService();
+ }
+
+ public InstantSendManager(Context context, InstantSendDatabase db, AbstractBlockChain blockChain,
+ @Nullable PeerGroup peerGroup, @Nullable ChainLocksHandler chainLocksHandler, SigningManager signingManager,
+ MasternodeSync masternodeSync, SporkManager sporkManager) {
this.context = context;
this.db = db;
- this.quorumSigningManager = context.signingManager;
+ this.quorumSigningManager = signingManager;
pendingInstantSendLocks = new HashMap<>();
invalidInstantSendLocks = new HashMap<>();
scheduledExecutorService = createScheduledExecutorService();
+ setBlockChain(blockChain, peerGroup, chainLocksHandler, masternodeSync, sporkManager, masternodeListManager);
}
private ScheduledExecutorService createScheduledExecutorService() {
@@ -71,19 +96,41 @@ public String toString() {
return String.format("InstantSendManager: pendingInstantSendLocks %d, DB: %s", pendingInstantSendLocks.size(), db);
}
- public InstantSendManager(Context context, InstantSendDatabase db, boolean runWithoutThread) {
- this(context, db);
- this.runWithoutThread = runWithoutThread;
- }
-
- public void setBlockChain(AbstractBlockChain blockChain, @Nullable PeerGroup peerGroup) {
+// public InstantSendManager(Context context, InstantSendDatabase db, boolean runWithoutThread) {
+// this(context, db);
+// this.runWithoutThread = runWithoutThread;
+// }
+
+// public void setBlockChain(AbstractBlockChain blockChain, @Nullable PeerGroup peerGroup) {
+// this.peerGroup = peerGroup;
+// this.blockChain = blockChain;
+// this.blockChain.addTransactionReceivedListener(this.transactionReceivedInBlockListener);
+// this.blockChain.addNewBestBlockListener(this.newBestBlockListener);
+// if (peerGroup != null) {
+// peerGroup.addOnTransactionBroadcastListener(this.transactionBroadcastListener);
+// }
+// if (scheduledExecutorService == null)
+// scheduledExecutorService = createScheduledExecutorService();
+// }
+
+ public void setBlockChain(AbstractBlockChain blockChain, @Nullable PeerGroup peerGroup,
+ @Nullable ChainLocksHandler chainLocksHandler, MasternodeSync masternodeSync,
+ SporkManager sporkManager, SimplifiedMasternodeListManager masternodeListManager) {
+ this.peerGroup = peerGroup;
this.blockChain = blockChain;
+ this.masternodeSync = masternodeSync;
+ this.masternodeListManager = masternodeListManager;
+ this.sporkManager = sporkManager;
this.blockChain.addTransactionReceivedListener(this.transactionReceivedInBlockListener);
this.blockChain.addNewBestBlockListener(this.newBestBlockListener);
if (peerGroup != null) {
peerGroup.addOnTransactionBroadcastListener(this.transactionBroadcastListener);
+ peerGroup.addPreMessageReceivedEventListener(SAME_THREAD, preMessageReceivedEventListener);
+ }
+ if (chainLocksHandler != null) {
+ this.chainLocksHandler = chainLocksHandler;
+ chainLocksHandler.addChainLockListener(this.chainLockListener);
}
- context.chainLockHandler.addChainLockListener(this.chainLockListener);
if (scheduledExecutorService == null)
scheduledExecutorService = createScheduledExecutorService();
}
@@ -96,8 +143,10 @@ public void close(PeerGroup peerGroup) {
}
if (peerGroup != null) {
peerGroup.removeOnTransactionBroadcastListener(this.transactionBroadcastListener);
+ peerGroup.removePreMessageReceivedEventListener(preMessageReceivedEventListener);
}
- context.chainLockHandler.removeChainLockListener(this.chainLockListener);
+ chainLocksHandler.removeChainLockListener(this.chainLockListener);
+ wallets.forEach(wallet -> wallet.removeCoinsSentEventListener(coinsSentEventListener));
try {
if (!scheduledExecutorService.awaitTermination(3000, TimeUnit.MILLISECONDS)) {
log.warn("scheduled threads still remain");
@@ -114,7 +163,7 @@ private boolean isInitialized() {
}
public boolean isInstantSendEnabled() {
- return context.sporkManager.isSporkActive(SporkId.SPORK_2_INSTANTSEND_ENABLED);
+ return sporkManager.isSporkActive(SporkId.SPORK_2_INSTANTSEND_ENABLED);
}
public void processInstantSendLock(Peer peer, InstantSendLock isLock) {
@@ -146,7 +195,7 @@ public void processInstantSendLock(Peer peer, InstantSendLock isLock) {
} catch (BlockStoreException x) {
throw new RuntimeException(x);
}
- } else if (context.getParams().isDIP0024Active(context.blockChain.getChainHead())) {
+ } else if (context.getParams().isDIP0024Active(blockChain.getChainHead())) {
// Ignore non-deterministic islocks once rotation is active
return;
}
@@ -208,6 +257,42 @@ private boolean preVerifyInstantSendLock(InstantSendLock islock)
return true;
}
+ public final PreMessageReceivedEventListener preMessageReceivedEventListener = (peer, m) -> {
+ if (m instanceof InventoryMessage) {
+ if (isInstantSendEnabled() && masternodeSync != null && masternodeSync.hasSyncFlag(MasternodeSync.SYNC_FLAGS.SYNC_INSTANTSENDLOCKS)) {
+ InventoryMessage inv = (InventoryMessage) m;
+ List items = inv.getItems();
+ List instantSendLocks = new LinkedList<>();
+ for (InventoryItem item : items) {
+ switch (item.type) {
+ case InstantSendLock:
+ case InstantSendDeterministicLock:
+ instantSendLocks.add(item);
+ break;
+ default:
+ break;
+ }
+ }
+ Iterator it = instantSendLocks.iterator();
+ GetDataMessage getdata = new GetDataMessage(context.getParams());
+ while (it.hasNext()) {
+ InventoryItem item = it.next();
+ if(!alreadyHave(item)) {
+ getdata.addItem(item);
+ }
+ }
+ if (!getdata.getItems().isEmpty()) {
+ // This will cause us to receive a bunch of block or tx messages.
+ peer.sendMessage(getdata);
+ }
+ }
+ } else if (m instanceof InstantSendLock) {
+ processInstantSendLock(peer, (InstantSendLock) m);
+ return null;
+ }
+ return m;
+ };
+
public boolean alreadyHave(InventoryItem inv)
{
if (!isInstantSendEnabled()) {
@@ -374,7 +459,7 @@ boolean checkCanLock(TransactionOutPoint outpoint, boolean printDebug, Sha256Has
int txAge = blockChain.getBestChainHeight() - utxo.getHeight();
if (txAge < nInstantSendConfirmationsRequired) {
- if (context.chainLockHandler.hasChainLock(utxo.getHeight(), block.getHash())) {
+ if (chainLocksHandler.hasChainLock(utxo.getHeight(), block.getHash())) {
if (printDebug) {
log.info("txid={}: outpoint {} too new and not ChainLocked. nTxAge={}, nInstantSendConfirmationsRequired={}",
txHash, outpoint.toStringShort(), txAge, nInstantSendConfirmationsRequired);
@@ -394,7 +479,7 @@ boolean checkCanLock(TransactionOutPoint outpoint, boolean printDebug, Sha256Has
TransactionConfidence confidence = parent.getConfidence();
if(confidence != null && confidence.getDepthInBlocks() < nInstantSendConfirmationsRequired) {
StoredBlock block = blockStore.get(confidence.getAppearedAtChainHeight());
- if (context.chainLockHandler.hasChainLock(confidence.getAppearedAtChainHeight(), block.getHeader().getHash()))
+ if (chainLocksHandler.hasChainLock(confidence.getAppearedAtChainHeight(), block.getHeader().getHash()))
{
if (printDebug) {
log.info("txid={}: outpoint {} too new and not ChainLocked. nTxAge={}, nInstantSendConfirmationsRequired={}",
@@ -513,7 +598,7 @@ HashSet processPendingInstantSendLocks(LLMQParameters.LLMQType llmqT
for (Map.Entry> p : pend.entrySet()) {
Sha256Hash hash = p.getKey();
- if(!context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.INSTANTSENDLOCK)) {
+ if(!masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.INSTANTSENDLOCK)) {
//If we don't verify the instantsendlock as being signed by a quorum...
processInstantSendLock(p.getValue().getFirst(), hash, p.getValue().getSecond());
continue;
@@ -572,7 +657,7 @@ HashSet processPendingInstantSendLocks(LLMQParameters.LLMQType llmqT
if (quorum == null) {
// should not happen, but if one fails to select, all others will also fail to select
log.info("islock: quorum not found to verify signature [tipHeight: {} vs {}]", tipHeight,
- context.masternodeListManager.getQuorumListAtTip(llmqType).getHeight());
+ masternodeListManager.getQuorumListAtTip(llmqType).getHeight());
log.info("islock: signHeight: {}, id: {}", signHeight, id);
log.info("islock: dash-cli quorum selectquorum {} {}", llmqType.getValue(), Sha256Hash.wrap(id.getReversedBytes()));
invalidInstantSendLocks.put(islock, Utils.currentTimeSeconds());
@@ -602,7 +687,7 @@ HashSet processPendingInstantSendLocks(LLMQParameters.LLMQType llmqT
}
Stopwatch timer = Stopwatch.createStarted();
- if(context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES))
+ if(masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES))
batchVerifier.verify();
log.info("InstantSendManager -- verified locks. count={}, alreadyVerified={}, vt={}, nodes={}",
@@ -680,7 +765,7 @@ void processInstantSendLock(long from, Sha256Hash hash, InstantSendLock islock)
if(block != null) {
// Let's see if the TX that was locked by this islock is already mined in a ChainLocked block. If yes,
// we can simply ignore the islock, as the ChainLock implies locking of all TXs in that chain
- if (context.chainLockHandler.hasChainLock(height, block.getHeader().getHash())) {
+ if (chainLocksHandler.hasChainLock(height, block.getHeader().getHash())) {
log.info("txlock={}, islock={}: dropping islock as it already got a ChainLock in block {}, peer={}",
islock.txid, hash, block.getHeader().getHash(), from);
return;
@@ -793,7 +878,7 @@ public void syncTransaction(Transaction tx, StoredBlock block, int posInBlock) {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
- if (context.sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED)) {
+ if (sporkManager.isSporkActive(SporkId.SPORK_19_CHAINLOCKS_ENABLED)) {
// Nothing to do here. We should keep all islocks and let chainlocks handle them.
return;
}
@@ -991,4 +1076,18 @@ public void onTransaction(Peer peer, Transaction t) {
syncTransaction(t, null, -1);
}
};
+
+ WalletCoinsSentEventListener coinsSentEventListener = (wallet, tx, prevBalance, newBalance) -> syncTransaction(tx, null, -1);
+
+ public void addWallet(Wallet wallet) {
+ wallet.addCoinsSentEventListener(coinsSentEventListener);
+ wallets.add(wallet);
+ }
+
+ public void removeWallet(Wallet wallet) {
+ if (wallets.contains(wallet)) {
+ wallet.removeCoinsSentEventListener(coinsSentEventListener);
+ wallets.remove(wallet);
+ }
+ }
}
diff --git a/core/src/main/java/org/bitcoinj/quorums/LLMQBackgroundThread.java b/core/src/main/java/org/bitcoinj/quorums/LLMQBackgroundThread.java
index 8c6410e3f6..67eb2e3b43 100644
--- a/core/src/main/java/org/bitcoinj/quorums/LLMQBackgroundThread.java
+++ b/core/src/main/java/org/bitcoinj/quorums/LLMQBackgroundThread.java
@@ -1,6 +1,7 @@
package org.bitcoinj.quorums;
import org.bitcoinj.core.Context;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.store.BlockStoreException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -21,8 +22,18 @@ public class LLMQBackgroundThread extends Thread {
private static final Logger log = LoggerFactory.getLogger(LLMQBackgroundThread.class);
Context context;
- public LLMQBackgroundThread(Context context) {
+ protected InstantSendManager instantSendManager;
+ protected ChainLocksHandler chainLocksHandler;
+ protected SigningManager signingManager;
+ protected SimplifiedMasternodeListManager masternodeListManager;
+ public LLMQBackgroundThread(Context context, InstantSendManager instantSendManager,
+ ChainLocksHandler chainLocksHandler, SigningManager signingManager,
+ SimplifiedMasternodeListManager masternodeListManager) {
this.context = context;
+ this.instantSendManager = instantSendManager;
+ this.chainLocksHandler = chainLocksHandler;
+ this.signingManager = signingManager;
+ this.masternodeListManager = masternodeListManager;
}
int debugTimer = 0;
@@ -31,23 +42,23 @@ public LLMQBackgroundThread(Context context) {
public void run() {
Context.propagate(context);
log.info("starting LLMQBackgroundThread.run");
- if (context.signingManager == null) {
+ if (signingManager == null) {
// stop this thread if there is no signing manager
return;
}
try {
- context.signingManager.addRecoveredSignatureListener(context.instantSendManager);
- context.signingManager.addRecoveredSignatureListener(context.chainLockHandler);
+ signingManager.addRecoveredSignatureListener(instantSendManager);
+ signingManager.addRecoveredSignatureListener(chainLocksHandler);
while (!isInterrupted()) {
boolean didWork = false;
// only the DIP24 lists need to be synced for this to work
- if (context.masternodeListManager.isSyncedForInstantSend()) {
- didWork = context.instantSendManager.processPendingInstantSendLocks();
+ if (masternodeListManager.isSyncedForInstantSend()) {
+ didWork = instantSendManager.processPendingInstantSendLocks();
- didWork |= context.signingManager.processPendingRecoveredSigs();
+ didWork |= signingManager.processPendingRecoveredSigs();
- context.signingManager.cleanup();
+ signingManager.cleanup();
}
if (!didWork) {
@@ -56,7 +67,7 @@ public void run() {
debugTimer++;
if(debugTimer % 400 == 0) {
- log.info("{}", context.instantSendManager);
+ log.info("{}", instantSendManager);
if(debugTimer == 2000)
debugTimer = 0;
}
@@ -68,8 +79,8 @@ public void run() {
log.info("stopping LLMQBackgroundThread via InterruptedException");
//let the thread stop
} finally {
- context.signingManager.removeRecoveredSignatureListener(context.instantSendManager);
- context.signingManager.removeRecoveredSignatureListener(context.chainLockHandler);
+ signingManager.removeRecoveredSignatureListener(instantSendManager);
+ signingManager.removeRecoveredSignatureListener(chainLocksHandler);
}
}
}
diff --git a/core/src/main/java/org/bitcoinj/quorums/LLMQUtils.java b/core/src/main/java/org/bitcoinj/quorums/LLMQUtils.java
index ddf3386e54..9ca626fe62 100644
--- a/core/src/main/java/org/bitcoinj/quorums/LLMQUtils.java
+++ b/core/src/main/java/org/bitcoinj/quorums/LLMQUtils.java
@@ -10,6 +10,7 @@
import org.bitcoinj.crypto.BLSPublicKey;
import org.bitcoinj.crypto.BLSSignature;
+import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
@@ -92,20 +93,12 @@ static boolean evalSpork(LLMQParameters.LLMQType llmqType, long sporkValue) {
return sporkValue == 1 && llmqType != LLMQ_100_67 && llmqType != LLMQ_400_60 && llmqType != LLMQ_400_85;
}
- boolean isAllMembersConnectedEnabled(LLMQParameters.LLMQType llmqType) {
- return evalSpork(llmqType, Context.get().sporkManager.getSporkValue(SPORK_21_QUORUM_ALL_CONNECTED));
- }
-
- boolean isQuorumPoseEnabled(LLMQParameters.LLMQType llmqType) {
- return evalSpork(llmqType, Context.get().sporkManager.getSporkValue(SPORK_23_QUORUM_POSE));
- }
-
- public static boolean isQuorumRotationEnabled(Context context, NetworkParameters params, LLMQParameters.LLMQType type) {
+ public static boolean isQuorumRotationEnabled(@Nullable AbstractBlockChain headerChain, AbstractBlockChain blockChain, NetworkParameters params, LLMQParameters.LLMQType type) {
if (type != params.getLlmqDIP0024InstantSend()) {
return false;
}
- int bestHeight = max(context.headerChain != null ? context.headerChain.getBestChainHeight() : 0, context.blockChain.getBestChainHeight());
+ int bestHeight = max(headerChain != null ? headerChain.getBestChainHeight() : 0, blockChain.getBestChainHeight());
boolean quorumRotationActive = bestHeight >= params.getDIP0024BlockHeight();
return params.getLlmqDIP0024InstantSend() == type && quorumRotationActive;
}
diff --git a/core/src/main/java/org/bitcoinj/quorums/RecoveredSignature.java b/core/src/main/java/org/bitcoinj/quorums/RecoveredSignature.java
index 9c13c8bb7d..85fafefc4f 100644
--- a/core/src/main/java/org/bitcoinj/quorums/RecoveredSignature.java
+++ b/core/src/main/java/org/bitcoinj/quorums/RecoveredSignature.java
@@ -76,4 +76,24 @@ public Sha256Hash getHash() {
updateHash();
return hash;
}
+
+ public Sha256Hash getId() {
+ return id;
+ }
+
+ public Sha256Hash getMsgHash() {
+ return msgHash;
+ }
+
+ public Sha256Hash getQuorumHash() {
+ return quorumHash;
+ }
+
+ public BLSLazySignature getSignature() {
+ return signature;
+ }
+
+ public int getLlmqType() {
+ return llmqType;
+ }
}
diff --git a/core/src/main/java/org/bitcoinj/quorums/SigningManager.java b/core/src/main/java/org/bitcoinj/quorums/SigningManager.java
index fbac16c07e..776d9bfcc3 100644
--- a/core/src/main/java/org/bitcoinj/quorums/SigningManager.java
+++ b/core/src/main/java/org/bitcoinj/quorums/SigningManager.java
@@ -4,6 +4,7 @@
import org.bitcoinj.crypto.BLSBatchVerifier;
import org.bitcoinj.crypto.BLSPublicKey;
import org.bitcoinj.crypto.BLSSignature;
+import org.bitcoinj.evolution.SimplifiedMasternodeListManager;
import org.bitcoinj.quorums.listeners.RecoveredSignatureListener;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.utils.ListenerRegistration;
@@ -47,25 +48,29 @@ public class SigningManager {
QuorumManager quorumManager;
AbstractBlockChain blockChain;
AbstractBlockChain headerChain;
+ protected MasternodeSync masternodeSync;
+ protected SimplifiedMasternodeListManager masternodeListManager;
long lastCleanupTime;
File signatureLog;
public OutputStream signatureStream;
- public SigningManager(Context context, RecoveredSignaturesDatabase db) {
+ public SigningManager(Context context, RecoveredSignaturesDatabase db, QuorumManager quorumManager, MasternodeSync masternodeSync) {
this.context = context;
this.db = db;
this.lastCleanupTime = 0;
- this.quorumManager = context.quorumManager;
+ this.quorumManager = quorumManager;
+ this.masternodeSync = masternodeSync;
this.recoveredSigsListeners = new CopyOnWriteArrayList>();
this.pendingReconstructedRecoveredSigs = new ArrayList>();
this.pendingRecoveredSigs = new HashMap>();
}
- public void setBlockChain(AbstractBlockChain blockChain, @Nullable AbstractBlockChain headerChain) {
+ public void setBlockChain(AbstractBlockChain blockChain, @Nullable AbstractBlockChain headerChain, SimplifiedMasternodeListManager masternodeListManager) {
this.blockChain = blockChain;
this.headerChain = headerChain;
+ this.masternodeListManager = masternodeListManager;
}
public void close() {
@@ -201,7 +206,7 @@ Quorum selectQuorumForSigning(LLMQParameters.LLMQType llmqType, long signHeight,
}
- if (LLMQUtils.isQuorumRotationEnabled(context, context.getParams(), llmqType)) {
+ if (LLMQUtils.isQuorumRotationEnabled(headerChain, blockChain, context.getParams(), llmqType)) {
ArrayList quorums = quorumManager.scanQuorums(llmqType, startBlock, poolSize);
if (quorums.isEmpty()) {
return null;
@@ -390,7 +395,7 @@ boolean processPendingRecoveredSigs()
//cxxtimer::Timer verifyTimer(true);
long start = Utils.currentTimeMillis();
- if(context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES))
+ if(masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES))
batchVerifier.verify();
long end = Utils.currentTimeMillis();
//verifyTimer.stop();
@@ -493,7 +498,7 @@ boolean verifyRecoveredSig(LLMQParameters.LLMQType llmqType, long signedAtHeight
logSignature("RECSIG", quorum.getCommitment().quorumPublicKey.getPublicKey(), signHash, sig);
- if(context.masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES)) {
+ if(masternodeSync.hasVerifyFlag(MasternodeSync.VERIFY_FLAGS.BLS_SIGNATURES)) {
boolean result = sig.verifyInsecure(quorum.getCommitment().quorumPublicKey.getPublicKey(), signHash);
if (!result) {
log.info("signature not validated with {}, msg: {}, id: {}, signHash: {}", quorum, msgHash, Sha256Hash.wrap(id.getReversedBytes()), signHash);
@@ -502,7 +507,7 @@ boolean verifyRecoveredSig(LLMQParameters.LLMQType llmqType, long signedAtHeight
StoredBlock block = blockChain.getBlockStore().get((int) (signedAtHeight - SIGN_HEIGHT_OFFSET));
if (block == null)
headerChain.getBlockStore().get((int) (signedAtHeight - SIGN_HEIGHT_OFFSET));
- for (Quorum q : context.masternodeListManager.getAllQuorums(llmqType)) {
+ for (Quorum q : masternodeListManager.getAllQuorums(llmqType)) {
log.info("attempting verification of {}: {} with {}", Sha256Hash.wrap(id.getReversedBytes()), sig.verifyInsecure(q.getCommitment().quorumPublicKey.getPublicKey(), signHash), q);
}
} else {
@@ -530,7 +535,7 @@ void cleanup()
}
public void logSignature(String type, BLSPublicKey publicKey, Sha256Hash messageHash, BLSSignature signature) {
- if(context.masternodeSync.hasFeatureFlag(MasternodeSync.FEATURE_FLAGS.LOG_SIGNATURES)) {
+ if(masternodeSync.hasFeatureFlag(MasternodeSync.FEATURE_FLAGS.LOG_SIGNATURES)) {
if(!sigLogInitialized)
initializeSignatureLog();
try {
@@ -552,7 +557,7 @@ public void initializeSignatureLog(String directory) {
}
public void initializeSignatureLog() {
- if(!context.masternodeSync.hasFeatureFlag(MasternodeSync.FEATURE_FLAGS.LOG_SIGNATURES))
+ if(!masternodeSync.hasFeatureFlag(MasternodeSync.FEATURE_FLAGS.LOG_SIGNATURES))
return;
try {
boolean exists = false;
diff --git a/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java b/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java
index ed93ef2393..aa5582600e 100644
--- a/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java
+++ b/core/src/main/java/org/bitcoinj/quorums/SimplifiedQuorumList.java
@@ -20,6 +20,7 @@
import org.bitcoinj.crypto.BLSSignature;
import org.bitcoinj.evolution.*;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.utils.MerkleRoot;
import org.bitcoinj.utils.Pair;
@@ -137,7 +138,7 @@ BLSSignature getSignatureForIndex(Map> quorumsCLS
return answer.map(Map.Entry::getKey).orElse(null);
}
- public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean isLoadingBootstrap, DualBlockChain chain, boolean doDIP24, boolean validateOldQuorums) throws MasternodeListDiffException{
+ public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean isLoadingBootstrap, DualBlockChain chain, MasternodeListManager masternodeListManager, ChainLocksHandler chainLocksHandler, boolean doDIP24, boolean validateOldQuorums) throws MasternodeListDiffException{
lock.lock();
try {
CoinbaseTx cbtx = (CoinbaseTx) diff.getCoinBaseTx().getExtraPayloadObject();
@@ -158,12 +159,12 @@ public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean
BLSSignature signature = diff.getQuorumsCLSigs() != null ?
getSignatureForIndex(diff.getQuorumsCLSigs(), i) : null;
if (signature != null)
- Context.get().chainLockHandler.addCoinbaseChainLock(entry.quorumHash, 8, signature);
+ chainLocksHandler.addCoinbaseChainLock(entry.quorumHash, 8, signature);
// find a better way to do this
if ((doDIP24 && entry.llmqType == params.getLlmqDIP0024InstantSend().value) || (!doDIP24 && entry.llmqType != params.getLlmqDIP0024InstantSend().value)) {
// for now, don't use the return value
- verifyQuorum(isLoadingBootstrap, chain, validateOldQuorums, entry);
+ verifyQuorum(isLoadingBootstrap, chain, masternodeListManager, validateOldQuorums, entry);
}
result.addCommitment(entry);
}
@@ -175,12 +176,12 @@ public SimplifiedQuorumList applyDiff(SimplifiedMasternodeListDiff diff, boolean
}
}
- public void verifyQuorums(boolean isLoadingBootstrap, DualBlockChain chain, boolean validateOldQuorums) throws BlockStoreException, ProtocolException{
+ public void verifyQuorums(boolean isLoadingBootstrap, DualBlockChain chain, MasternodeListManager masternodeListManager, boolean validateOldQuorums) throws BlockStoreException, ProtocolException{
lock.lock();
try {
int verifiedCount = 0;
for (FinalCommitment entry : minableCommitments.values()) {
- if (verifyQuorum(isLoadingBootstrap, chain, validateOldQuorums, entry)) {
+ if (verifyQuorum(isLoadingBootstrap, chain, masternodeListManager, validateOldQuorums, entry)) {
verifiedCount++;
}
}
@@ -190,7 +191,9 @@ public void verifyQuorums(boolean isLoadingBootstrap, DualBlockChain chain, bool
}
}
- private boolean verifyQuorum(boolean isLoadingBootstrap, DualBlockChain chain, boolean validateOldQuorums, FinalCommitment entry) throws BlockStoreException {
+ private boolean verifyQuorum(boolean isLoadingBootstrap, DualBlockChain chain,
+ MasternodeListManager masternodeListManager,
+ boolean validateOldQuorums, FinalCommitment entry) throws BlockStoreException {
StoredBlock block = chain.getBlock(entry.getQuorumHash());
if (block != null) {
LLMQParameters llmqParameters = params.getLlmqs().get(entry.getLlmqType());
@@ -202,7 +205,7 @@ private boolean verifyQuorum(boolean isLoadingBootstrap, DualBlockChain chain, b
if (block.getHeight() % dkgInterval != 0)
throw new ProtocolException("Quorum block height does not match interval for " + entry.quorumHash);
}
- boolean isVerified = checkCommitment(entry, block, Context.get().masternodeListManager, chain, validateOldQuorums);
+ boolean isVerified = checkCommitment(entry, block, masternodeListManager, chain, validateOldQuorums);
isFirstQuorumCheck = false;
return isVerified;
} else {
@@ -402,7 +405,7 @@ public void syncWithMasternodeList(SimplifiedMasternodeList masternodeList) {
blockHash = masternodeList.getBlockHash();
}
- private boolean checkCommitment(FinalCommitment commitment, StoredBlock quorumBlock, SimplifiedMasternodeListManager manager,
+ private boolean checkCommitment(FinalCommitment commitment, StoredBlock quorumBlock, MasternodeListManager manager,
DualBlockChain chain, boolean validateQuorums) throws BlockStoreException
{
if (commitment.getVersion() == 0 || commitment.getVersion() > FinalCommitment.MAX_VERSION) {
diff --git a/core/src/main/java/org/bitcoinj/signers/CoinJoinTransactionSigner.java b/core/src/main/java/org/bitcoinj/signers/CoinJoinTransactionSigner.java
index 2241f47be9..0cb3bf2c85 100644
--- a/core/src/main/java/org/bitcoinj/signers/CoinJoinTransactionSigner.java
+++ b/core/src/main/java/org/bitcoinj/signers/CoinJoinTransactionSigner.java
@@ -18,6 +18,7 @@
package org.bitcoinj.signers;
+import org.bitcoinj.coinjoin.utils.CoinJoinManager;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Transaction;
@@ -48,7 +49,7 @@
*/
public class CoinJoinTransactionSigner implements TransactionSigner {
private static final Logger log = LoggerFactory.getLogger(CoinJoinTransactionSigner.class);
-
+ private CoinJoinManager coinJoinManager;
/**
* Verify flags that are safe to use when testing if an input is already
* signed.
@@ -59,7 +60,8 @@ public class CoinJoinTransactionSigner implements TransactionSigner {
private final List sigs;
private final boolean anyoneCanPay;
- public CoinJoinTransactionSigner(List sigs, boolean anyoneCanPay) {
+ public CoinJoinTransactionSigner(CoinJoinManager coinJoinManager, List sigs, boolean anyoneCanPay) {
+ this.coinJoinManager = coinJoinManager;
this.sigs = sigs;
this.anyoneCanPay = anyoneCanPay;
sigs.clear();
@@ -121,7 +123,7 @@ public boolean signInputs(ProposedTransaction propTx, KeyBag keyBag) {
if (ScriptPattern.isP2PK(scriptPubKey) || ScriptPattern.isP2PKH(scriptPubKey)
|| ScriptPattern.isP2SH(scriptPubKey)) {
if (key.isEncrypted()) {
- key = Context.get().coinJoinManager.requestDecryptKey(key);
+ key = coinJoinManager.requestDecryptKey(key);
}
TransactionSignature signature = tx.calculateSignature(i, key, script, Transaction.SigHash.ALL, anyoneCanPay);
diff --git a/core/src/main/java/org/bitcoinj/wallet/Wallet.java b/core/src/main/java/org/bitcoinj/wallet/Wallet.java
index 83861e414d..a7e7dc05c8 100644
--- a/core/src/main/java/org/bitcoinj/wallet/Wallet.java
+++ b/core/src/main/java/org/bitcoinj/wallet/Wallet.java
@@ -2906,10 +2906,6 @@ public boolean maybeCommitTx(Transaction tx) throws VerificationException {
isConsistentOrThrow();
- //Dash Specific
- if(context.instantSendManager != null && context.instantSendManager.isInstantSendEnabled())
- context.instantSendManager.syncTransaction(tx, null, -1);
-
// let keychain extensions process the transaction
for (KeyChainGroupExtension extension : keyChainExtensions.values()) {
extension.processTransaction(tx, null, BlockChain.NewBlockType.BEST_CHAIN);
@@ -5657,9 +5653,6 @@ public void setTransactionBroadcaster(@Nullable org.bitcoinj.core.TransactionBro
continue;
}
- //Dash Specific
- if (context.instantSendManager != null && context.instantSendManager.isInstantSendEnabled())
- context.instantSendManager.syncTransaction(tx, null, -1);
checkState(confidenceType == ConfidenceType.PENDING || confidenceType == ConfidenceType.IN_CONFLICT,
"Expected PENDING or IN_CONFLICT, was %s.", confidenceType);
diff --git a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinServer.java b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinServer.java
index 6ea0828452..601c41aedf 100644
--- a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinServer.java
+++ b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinServer.java
@@ -40,6 +40,7 @@
import org.bitcoinj.evolution.Masternode;
import org.bitcoinj.evolution.SimplifiedMasternodeList;
import org.bitcoinj.evolution.SimplifiedMasternodeListEntry;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.slf4j.Logger;
@@ -83,9 +84,11 @@ public class CoinJoinServer extends CoinJoinBaseSession {
static final Logger log = LoggerFactory.getLogger(CoinJoinServer.class);
static final Random random = new Random();
+ private final DashSystem system;
private final CoinJoinBaseManager baseManager = new CoinJoinBaseManager();
- public CoinJoinServer(Context context) {
+ public CoinJoinServer(Context context, DashSystem system) {
super(context);
+ this.system = system;
operatorSecretKey = BLSSecretKey.fromSeed(Sha256Hash.ZERO_HASH.getBytes());
entry = new SimplifiedMasternodeListEntry(
context.getParams(),
@@ -158,7 +161,7 @@ public void processAccept(Peer from, CoinJoinAccept dsa)
log.info("coinjoin server:DSACCEPT -- denom {} ({}) txCollateral {}", dsa.getDenomination(), CoinJoin.denominationToString(dsa.getDenomination()), dsa.getTxCollateral()); /* Continued */
- SimplifiedMasternodeList mnList = context.masternodeListManager.getListAtChainTip();
+ SimplifiedMasternodeList mnList = system.masternodeListManager.getListAtChainTip();
Masternode dmn = mnList.getMN(proTxHash);
if (dmn == null) {
pushStatus(from, STATUS_REJECTED, ERR_MN_LIST);
@@ -178,9 +181,9 @@ public void processAccept(Peer from, CoinJoinAccept dsa)
lock.unlock();
}
- long nLastDsq = context.masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
- long nDsqThreshold = context.masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), mnList.getValidMNsCount());
- if (nLastDsq != 0 && nDsqThreshold > context.masternodeMetaDataManager.getDsqCount()) {
+ long nLastDsq = system.masternodeMetaDataManager.getMetaInfo(dmn.getProTxHash()).getLastDsq();
+ long nDsqThreshold = system.masternodeMetaDataManager.getDsqThreshold(dmn.getProTxHash(), mnList.getValidMNsCount());
+ if (nLastDsq != 0 && nDsqThreshold > system.masternodeMetaDataManager.getDsqCount()) {
log.info("coinjoin server:DSACCEPT -- last dsq too recent, must wait: peer addr={}", from.getAddress().getSocketAddress());
pushStatus(from, STATUS_REJECTED, ERR_RECENT);
return;
@@ -751,7 +754,7 @@ protected void relayFinalTransaction(Transaction finalTx) {
}
protected void relay(Message message) {
- for (Peer peer : context.peerGroup.getConnectedPeers()) {
+ for (Peer peer : system.peerGroup.getConnectedPeers()) {
peer.sendMessage(message);
}
}
diff --git a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSessionTest.java b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSessionTest.java
index 1a418b6d5a..f3f06a0f16 100644
--- a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSessionTest.java
+++ b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSessionTest.java
@@ -116,7 +116,7 @@ public void setUp() throws Exception {
coinbaseTo = Address.fromKey(UNITTEST, wallet.currentReceiveKey());
operatorSecretKey = BLSSecretKey.fromSeed(Sha256Hash.ZERO_HASH.getBytes());
- coinJoinServer = new CoinJoinServer(wallet.getContext());
+ coinJoinServer = new CoinJoinServer(context, system);
entry = new SimplifiedMasternodeListEntry(
UNITTEST,
@@ -152,9 +152,9 @@ public void setUp() throws Exception {
Collections.emptyList(),
SimplifiedMasternodeListDiff.CURRENT_VERSION
);
- wallet.getContext().masternodeListManager.processMasternodeListDiff(null, diff, true);
+ system.masternodeListManager.processMasternodeListDiff(null, diff, true);
- wallet.getContext().coinJoinManager.setMasternodeGroup(masternodeGroup);
+ system.coinJoinManager.setMasternodeGroup(masternodeGroup);
MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet);
wallet.setTransactionBroadcaster(broadcaster);
@@ -165,7 +165,7 @@ public void setUp() throws Exception {
globalTimeout = Timeout.seconds(30);
mixingWallet = (WalletEx) wallet;
- wallet.getContext().coinJoinManager.start();
+ system.coinJoinManager.start();
}
protected Wallet createWallet(KeyChainGroup keyChainGroup) {
@@ -175,7 +175,7 @@ protected Wallet createWallet(KeyChainGroup keyChainGroup) {
@Override
@After
public void tearDown() {
- wallet.getContext().coinJoinManager.stop();
+ system.coinJoinManager.stop();
super.tearDown();
}
@@ -196,15 +196,24 @@ public void sessionTest() throws Exception {
InboundMessageQueuer p2 = connectPeer(2);
assertEquals(2, peerGroup.numConnectedPeers());
- CoinJoinManager coinJoinManager = wallet.getContext().coinJoinManager;
-
- coinJoinManager.coinJoinClientManagers.put(wallet.getDescription(), new CoinJoinClientManager(mixingWallet));
+ CoinJoinManager coinJoinManager = system.coinJoinManager;
+
+ coinJoinManager.coinJoinClientManagers.put(
+ wallet.getDescription(),
+ new CoinJoinClientManager(
+ mixingWallet,
+ system.masternodeSync,
+ system.coinJoinManager,
+ system.masternodeListManager,
+ system.masternodeMetaDataManager
+ )
+ );
HashMap keyMap = new HashMap<>();
// mix coins
CoinJoinClientManager clientManager = coinJoinManager.coinJoinClientManagers.get(wallet.getDescription());
- clientManager.setBlockChain(wallet.getContext().blockChain);
+ clientManager.setBlockChain(system.blockChain);
addBlock();
clientManager.updatedSuccessBlock();
@@ -229,7 +238,7 @@ public void sessionTest() throws Exception {
// mix 1 session (1 round)
do {
Thread.sleep(1000);
- wallet.getContext().coinJoinManager.doMaintenance();
+ system.coinJoinManager.doMaintenance();
addBlock();
// this section of nextMessage() and if/else blocks will simulate a mixing masternode
@@ -378,13 +387,22 @@ public void sessionTestTwo() throws Exception {
assertEquals(GetSporksMessage.class, outbound(spvClient).getClass());
assertEquals(GetSporksMessage.class, outbound(someNode).getClass());
- CoinJoinManager coinJoinManager = wallet.getContext().coinJoinManager;
-
- coinJoinManager.coinJoinClientManagers.put(wallet.getDescription(), new CoinJoinClientManager(mixingWallet));
+ CoinJoinManager coinJoinManager = system.coinJoinManager;
+
+ coinJoinManager.coinJoinClientManagers.put(
+ wallet.getDescription(),
+ new CoinJoinClientManager(
+ mixingWallet,
+ system.masternodeSync,
+ system.coinJoinManager,
+ system.masternodeListManager,
+ system.masternodeMetaDataManager
+ )
+ );
// mix coins
CoinJoinClientManager clientManager = coinJoinManager.coinJoinClientManagers.get(wallet.getDescription());
- clientManager.setBlockChain(wallet.getContext().blockChain);
+ clientManager.setBlockChain(system.blockChain);
// check balance
assertEquals(Coin.FIFTY_COINS, wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE));
@@ -407,7 +425,7 @@ public void sessionTestTwo() throws Exception {
// step 0: client will connect to the masternode, if it hasn't yet
do {
Thread.sleep(1000);
- wallet.getContext().coinJoinManager.doMaintenance();
+ system.coinJoinManager.doMaintenance();
addBlock();
} while (lastMasternode == null);
assertEquals(Coin.FIFTY_COINS, wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE));
@@ -497,7 +515,7 @@ public void sessionTestTwo() throws Exception {
InventoryMessage inv = (InventoryMessage) invMessage;
assertEquals(1, inv.getItems().size());
// step 10: client requests the dstx
- GetDataMessage getDataMessage = new GetDataMessage(wallet.getContext().getParams());
+ GetDataMessage getDataMessage = new GetDataMessage(context.getParams());
getDataMessage.addItem(inv.getItems().get(0));
// step 10: masternode processes request for getdata
@@ -624,12 +642,21 @@ public void sessionAttemptWithEmptyWalletTest() throws Exception {
assertEquals(GetSporksMessage.class, outbound(spvClient).getClass());
assertEquals(GetSporksMessage.class, outbound(someNode).getClass());
- CoinJoinManager coinJoinManager = wallet.getContext().coinJoinManager;
-
- coinJoinManager.coinJoinClientManagers.put(wallet.getDescription(), new CoinJoinClientManager(mixingWallet));
+ CoinJoinManager coinJoinManager = system.coinJoinManager;
+
+ coinJoinManager.coinJoinClientManagers.put(
+ wallet.getDescription(),
+ new CoinJoinClientManager(
+ mixingWallet,
+ system.masternodeSync,
+ system.coinJoinManager,
+ system.masternodeListManager,
+ system.masternodeMetaDataManager
+ )
+ );
CoinJoinClientManager clientManager = coinJoinManager.coinJoinClientManagers.get(wallet.getDescription());
clientManager.setStopOnNothingToDo(true);
- clientManager.setBlockChain(wallet.getContext().blockChain);
+ clientManager.setBlockChain(system.blockChain);
// check balance
assertEquals(Coin.ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE));
@@ -654,7 +681,7 @@ public void sessionAttemptWithEmptyWalletTest() throws Exception {
System.out.println("Mixing " + (result ? "started successfully" : ("start failed: " + clientManager.getStatuses() + ", will retry")));
addBlock();
- wallet.getContext().coinJoinManager.doMaintenance();
+ system.coinJoinManager.doMaintenance();
assertEquals(Coin.ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE_SPENDABLE));
diff --git a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSignedInputsTest.java b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSignedInputsTest.java
index e8acc24409..6fed794e79 100644
--- a/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSignedInputsTest.java
+++ b/core/src/test/java/org/bitcoinj/coinjoin/CoinJoinSignedInputsTest.java
@@ -2,6 +2,7 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import org.bitcoinj.core.Context;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.KeyId;
import org.bitcoinj.core.NetworkParameters;
@@ -10,6 +11,7 @@
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
@@ -33,6 +35,8 @@
public class CoinJoinSignedInputsTest {
static NetworkParameters PARAMS = UnitTestParams.get();
+ static Context context = new Context(PARAMS);
+ static DashSystem system = new DashSystem(context);
byte[] dssMessage = HEX.decode("01204578c8a6564fb12d78e304420ed8738514712ce219c4611cef6b0bdb36ed580d0000006b4830450221009dc078c6c523976413f335cde75f12f9d2a8f64251ba8705947e1de788a0b30e02201d26709b9e4f269f7c7e43542b9ea5663d8a107e72232683b6f9880d994fa10d012102d52ccc891ac43e661cd32a93c892cd668d0ef321448b1a1633efbb3b2e61b31cffffffff");
// byte[] dsfMessage = HEX.decode("9d7f0a000200000003204578c8a6564fb12d78e304420ed8738514712ce219c4611cef6b0bdb36ed580d00000000ffffffffa2039615b2db923f71d49b8af451df47aaf16d1b1baac79a5a732cb53117cd850100000000ffffffffafab56a552e4d66d2c1263027e7f1292b19669415119bdb6faa03ba1e86b58c30100000000ffffffff034a420f00000000001976a9142b4e226c80a96466631ff2db097727a8b712b69488ac4a420f00000000001976a9143b19e3f79a7114e51e95f8c5606c55816c48908988ac4a420f00000000001976a9149439af1abe644548530e2f63e80736a8af91e59b88ac00000000");
byte[] dssMessageTwo = HEX.decode("08c547b604a9682cd6d36b3352697df8661afbf0fff39abe318f739ab22374803f030000006b48304502210085e8bd03a92422fc8f656ded2c19ceb70c68707a1699dd54782c4395532022b602207730c221bcf818c0b0445f576b36d2ee0698edc4d3fe872aeaff772122e4251d0121030c467477c7d4aefb377cbe11c48765669676c556d0149c06da25fd0c2ade39ecffffffffc0c771b0ce74bf4fa4845c990f4ec4faff7374fd6344c0b25f41dd30ebbe5e46040000006a47304402204316f56e90d27505ecb938e52391cc9b0b77474b67283983a63463d0823a813a022058bcb6eab28c2f4f936ba85183e750d010808e1bb11201fab5bae6d5a25391ba0121023c2ff18948d68270f5e150456caa8c1fcb0e3ed33e68340b5e087fd6651cbe7dffffffff204578c8a6564fb12d78e304420ed8738514712ce219c4611cef6b0bdb36ed58010000006a47304402200b049725050b28a4a42f80db28bd8e48f266e2a3460cf6a798457420fa54bd0d02204edd66bf280cfda43019f48394439009cb234ee5871c2ec490d4d7ba84e6a461012102dde437be25a79dedc6dbf4cf73ac8e3eefd90112ddae827c9042b43d0e8d9bf6ffffffff86473250bdabf066fd57bad86de9f141849112e395ea777aceeb0e0fb8388d770a0000006b4830450221009048e55404378c68962bdb4c2acb4ea6592a040ac17be5f5cc2a957b087930620220694e165128a6c40c3bc4f77b369949d80606b9bdcf34e2dd8622107b9a87e3ff0121025064ef597ec1520e2e3b7836261457eb79522299314703a7beeea2bbf42b9175ffffffffe6cb88bd8c3418b3665cc2987e778762e58f461fa84737315622923453c61f95090000006a473044022059c43a7d1327d36adce6cfef92e5e2159c83dc9ebc6b28c5ac8c1ec46e6cdcb2022050dea4f95e4a8a6c4a06d71e6c7e5fc9b7249a967f09bd4283c2ed08a1225ed601210257f68289f77638b808706bced459895b349001a5d86641da619886474e9b417cffffffffc05155aa36cd041a8fa5e8a676877adccecae72f02561379275fb29d429fa79a090000006a47304402205b3398b3ea59a6ebe5cad2be234b64ddc852057197aaf7071c5621739e54ed5f02201330850ddd04f318cc5cffb8ce8464dc0d17dcc8e8d37c84db8bdef0b980363f01210297f200b4f0dc3967d77d822189276d60e6baad8075d954be933724dfa7ded74fffffffff697bccd54ca8c47eb9bf18d948c12226e44234ae1a4ea16c732533518e1074aa080000006a47304402203c3023ee03dee54982ef2176c6b26c81be06d8c09fb19e98ef98c257210f3c0e0220193b4f24aa9cc5720186dd02c05c9257a46383eed23586a3348d4b9af2d3f304012103e943423c41299842d5532a7800d0e7f6d4a4e89a68b992f071988e3325ca3e82ffffffffe2c1cea1e1532922532a2ec7bfa1cd33d202b5067e59decaa7025377ca2de4d6070000006b483045022100de784c07605de564af098672900651b901bbbfd05a9daa51b51d50f414073e16022020881559ada92c99777d1ec103dded571cbb8a9cfc0052262fbd3bcf14ac9dfe01210336d148cfc9a3a3603fa27aca926a73e2d47861194871f1473d9cc173c9ee5df0ffffffff");
@@ -145,7 +149,7 @@ public RedeemData findRedeemDataFromScriptHash(byte[] scriptHash) {
}
List sigs = Lists.newArrayList();
- CoinJoinTransactionSigner signer = new CoinJoinTransactionSigner(sigs, false); // anyoneCanPay = false
+ CoinJoinTransactionSigner signer = new CoinJoinTransactionSigner(system.coinJoinManager, sigs, false); // anyoneCanPay = false
TransactionSigner.ProposedTransaction proposedTransaction = new TransactionSigner.ProposedTransaction(finalMutableTransaction);
signer.signInputs(proposedTransaction, keyBag);
diff --git a/core/src/test/java/org/bitcoinj/coinjoin/TestWithMasternodeGroup.java b/core/src/test/java/org/bitcoinj/coinjoin/TestWithMasternodeGroup.java
index d41f321468..8cd3fbdfea 100644
--- a/core/src/test/java/org/bitcoinj/coinjoin/TestWithMasternodeGroup.java
+++ b/core/src/test/java/org/bitcoinj/coinjoin/TestWithMasternodeGroup.java
@@ -31,6 +31,7 @@
import org.bitcoinj.core.VersionMessage;
import org.bitcoinj.core.listeners.PreMessageReceivedEventListener;
import org.bitcoinj.evolution.Masternode;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.net.BlockingClientManager;
import org.bitcoinj.net.ClientConnectionManager;
import org.bitcoinj.net.NioClientManager;
@@ -53,6 +54,7 @@
public class TestWithMasternodeGroup extends TestWithPeerGroup {
protected MasternodeGroup masternodeGroup;
+ protected DashSystem system;
@Before
public void setUp() throws Exception {
super.setUp();
@@ -60,7 +62,8 @@ public void setUp() throws Exception {
@Override
protected void beforeInitPeerGroup() {
- Context.get().initDash(true, true);
+ system = new DashSystem(Context.get());
+ system.initDash(true, true);
}
@After
@@ -71,6 +74,8 @@ public void tearDown() {
Utils.finishMockSleep();
if (masternodeGroup.isRunning())
masternodeGroup.stopAsync();
+ system.remove();
+ system = null;
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -98,7 +103,7 @@ protected void initPeerGroup() {
protected final Semaphore jobBlocks = new Semaphore(0);
private MasternodeGroup createMasternodeGroup(final ClientConnectionManager manager) {
- return new MasternodeGroup(UNITTEST, blockChain, manager) {
+ return new MasternodeGroup(UNITTEST, blockChain, system.masternodeListManager, manager) {
@Override
protected ListeningScheduledExecutorService createPrivateExecutor() {
return MoreExecutors.listeningDecorator(new ScheduledThreadPoolExecutor(1, new ContextPropagatingThreadFactory("MasternodeGroup test thread")) {
@@ -122,7 +127,7 @@ public void run() {
public boolean addPendingMasternode(CoinJoinClientSession session) {
try {
Sha256Hash proTxHash = session.getMixingMasternodeInfo().getProTxHash();
- Masternode mn = context.masternodeListManager.getListAtChainTip().getMN(proTxHash);
+ Masternode mn = system.masternodeListManager.getListAtChainTip().getMN(proTxHash);
pendingSessions.add(session);
masternodeMap.put(proTxHash, session);
addressMap.put(session.getMixingMasternodeInfo().getService(), session);
diff --git a/core/src/test/java/org/bitcoinj/coinjoin/utils/CoinJoinTransactionTypeTest.java b/core/src/test/java/org/bitcoinj/coinjoin/utils/CoinJoinTransactionTypeTest.java
index c1c8d2f31a..e7a485d368 100644
--- a/core/src/test/java/org/bitcoinj/coinjoin/utils/CoinJoinTransactionTypeTest.java
+++ b/core/src/test/java/org/bitcoinj/coinjoin/utils/CoinJoinTransactionTypeTest.java
@@ -57,7 +57,7 @@ public void setUp() throws Exception {
myAddress = Address.fromKey(UNITTEST, myKey);
blockStore = new MemoryBlockStore(UNITTEST);
chain = new BlockChain(UNITTEST, wallet, blockStore);
- Context.get().initDash(false, true);
+ // Context.get().initDash(false, true);
}
@Test
diff --git a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java
index 6b5785696f..8262539565 100644
--- a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java
+++ b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java
@@ -17,6 +17,7 @@
package org.bitcoinj.core;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.params.UnitTestParams;
@@ -96,7 +97,6 @@ public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBl
chain = new BlockChain(UNITTEST, wallet, blockStore);
coinbaseTo = Address.fromKey(UNITTEST, wallet.currentReceiveKey());
- Context.get().initDash(false, true);
}
@Test
diff --git a/core/src/test/java/org/bitcoinj/core/ChainLockBlockChainTest.java b/core/src/test/java/org/bitcoinj/core/ChainLockBlockChainTest.java
index 2b8f6f99af..05d54e64d0 100644
--- a/core/src/test/java/org/bitcoinj/core/ChainLockBlockChainTest.java
+++ b/core/src/test/java/org/bitcoinj/core/ChainLockBlockChainTest.java
@@ -19,6 +19,7 @@
package org.bitcoinj.core;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.quorums.ChainLocksHandler;
@@ -28,6 +29,7 @@
import org.bitcoinj.store.MemoryBlockStore;
import org.bitcoinj.store.SPVBlockStore;
import org.bitcoinj.utils.BriefLogFormatter;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -57,13 +59,20 @@ public abstract class ChainLockBlockChainTest {
protected BlockChain chain;
protected BlockStore store;
+ protected DashSystem system;
@Before
public void setUp() throws Exception {
BriefLogFormatter.init();
Context context = new Context(PARAMS, 100, Coin.ZERO, false);
Context.propagate(context);
- context.initDash(false, true);
+ system = new DashSystem(Context.get());
+ system.initDash(false, true);
+ }
+
+ @After
+ public void tearDown() {
+ system.remove();
}
public abstract BlockStore createStore(NetworkParameters params, int blockCount) throws BlockStoreException;
@@ -96,10 +105,10 @@ public void testGeneratedChain() throws Exception {
Context context = Context.getOrCreate(PARAMS);
- context.setPeerGroupAndBlockChain(null, chain, null);
- context.masternodeSync.syncFlags = EnumSet.noneOf(MasternodeSync.SYNC_FLAGS.class);
+ system.setPeerGroupAndBlockChain(null, chain, null);
+ system.masternodeSync.syncFlags = EnumSet.noneOf(MasternodeSync.SYNC_FLAGS.class);
- ChainLocksHandler chainLocksHandler = context.chainLockHandler;
+ ChainLocksHandler chainLocksHandler = system.chainLockHandler;
for (Rule rule : blockList.list) {
if (rule instanceof FullBlockTestGenerator.BlockAndValidity) {
diff --git a/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java b/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java
index 478fef720c..01d81fb40c 100644
--- a/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java
+++ b/core/src/test/java/org/bitcoinj/core/ChainSplitTest.java
@@ -68,7 +68,6 @@ public void setUp() throws Exception {
coinsTo = Address.fromKey(UNITTEST, key1);
coinsTo2 = Address.fromKey(UNITTEST, key2);
someOtherGuy = Address.fromKey(UNITTEST, new ECKey());
- Context.get().initDash(false, true);
}
@Test
diff --git a/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java b/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java
index 2ca1c6a136..ad53acfc54 100644
--- a/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java
+++ b/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java
@@ -49,7 +49,7 @@ public FilteredBlockAndPartialMerkleTreeTests(ClientType clientType) {
@Before
public void setUp() throws Exception {
context = new Context(UNITTEST);
- context.initDash(false, true);
+ //context.initDash(false, true);
MemoryBlockStore store = new MemoryBlockStore(UNITTEST);
// Cheat and place the previous block (block 100000) at the head of the block store without supporting blocks
diff --git a/core/src/test/java/org/bitcoinj/core/SporkMessageTest.java b/core/src/test/java/org/bitcoinj/core/SporkMessageTest.java
index 4426d554f5..41f8c0bc54 100644
--- a/core/src/test/java/org/bitcoinj/core/SporkMessageTest.java
+++ b/core/src/test/java/org/bitcoinj/core/SporkMessageTest.java
@@ -24,11 +24,6 @@
public class SporkMessageTest {
static NetworkParameters PARAMS = TestNet3Params.get();
- static Context context = new Context(PARAMS);
-
- static {
- context.initDash(true, true);
- }
@Test
public void verifySpork() {
diff --git a/core/src/test/java/org/bitcoinj/evolution/LoadBootstrapFilesTest.java b/core/src/test/java/org/bitcoinj/evolution/LoadBootstrapFilesTest.java
index 73e7a94450..bcfd8b90dc 100644
--- a/core/src/test/java/org/bitcoinj/evolution/LoadBootstrapFilesTest.java
+++ b/core/src/test/java/org/bitcoinj/evolution/LoadBootstrapFilesTest.java
@@ -20,6 +20,7 @@
import org.bitcoinj.core.Context;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.PeerGroup;
+import org.bitcoinj.manager.DashSystem;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.quorums.QuorumRotationInfoTest;
@@ -45,6 +46,7 @@
public class LoadBootstrapFilesTest {
private static Context context;
+ private static DashSystem system;
private static final MainNetParams MAINPARAMS = MainNetParams.get();
private static final TestNet3Params TESTNETPARAMS = TestNet3Params.get();
private static PeerGroup peerGroup;
@@ -100,14 +102,15 @@ public static Collection