Skip to content

Commit

Permalink
refactor: reduce Context dependencies and replace with DashSystem (#264)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
HashEngineering authored Jan 22, 2025
1 parent 866a004 commit 16c31bb
Show file tree
Hide file tree
Showing 71 changed files with 1,640 additions and 979 deletions.
2 changes: 1 addition & 1 deletion .run/WalletTool CJ Create.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="WalletTool CJ Create" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.bitcoinj.tools.WalletTool" />
<module name="dashj-master-three.tools.main" />
<module name="dashj-parent.dashj-tools.main" />
<option name="PROGRAM_PARAMETERS" value="create --wallet=coinjoin.testnet.wallet --net=TEST --force" />
<option name="VM_PARAMETERS" value="-Djava.library.path=contrib/dashj-bls/bls/target/cmake" />
<extension name="coverage">
Expand Down
2 changes: 1 addition & 1 deletion .run/WalletTool CJ Dump.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="WalletTool CJ Dump" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.bitcoinj.tools.WalletTool" />
<module name="dashj-master-three.tools.main" />
<module name="dashj-parent.dashj-tools.main" />
<option name="PROGRAM_PARAMETERS" value="dump --wallet=coinjoin.testnet.wallet --net=TEST --rounds=1" />
<option name="VM_PARAMETERS" value="-Djava.library.path=contrib/dashj-bls/bls/target/cmake" />
<extension name="coverage">
Expand Down
2 changes: 1 addition & 1 deletion .run/WalletTool CJ Sync.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="WalletTool CJ Sync" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.bitcoinj.tools.WalletTool" />
<module name="dashj-master-three.tools.main" />
<module name="dashj-parent.dashj-tools.main" />
<option name="PROGRAM_PARAMETERS" value="sync --wallet=coinjoin.testnet.wallet --net=TEST" />
<option name="VM_PARAMETERS" value="-Djava.library.path=contrib/dashj-bls/bls/target/cmake" />
<extension name="coverage">
Expand Down
13 changes: 7 additions & 6 deletions core/src/main/java/org/bitcoinj/coinjoin/CoinJoin.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<Map.Entry<Sha256Hash, CoinJoinBroadcastTx>> it = mapDSTX.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Sha256Hash, CoinJoinBroadcastTx> entry = it.next();
if (entry.getValue().isExpired(block)) {
if (entry.getValue().isExpired(block, chainLocksHandler)) {
it.remove();
}
}
Expand All @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down
39 changes: 27 additions & 12 deletions core/src/main/java/org/bitcoinj/coinjoin/CoinJoinClientManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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;

Expand All @@ -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 ||
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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<SessionCompleteListener> listener : sessionCompleteListeners) {
newSession.addSessionCompleteListener(listener.executor, listener.listener);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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++;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Sha256Hash, Long> 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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -83,24 +94,24 @@ 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());
}
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<CoinJoinClientManager>() {
coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate<CoinJoinClientManager>() {
@Override
public boolean test(CoinJoinClientManager coinJoinClientManager) {
return coinJoinClientManager.markAlreadyJoinedQueueAsTried(dsq);
Expand All @@ -119,7 +130,7 @@ public boolean test(CoinJoinClientManager coinJoinClientManager) {
}

private boolean isTrySubmitDenominate(Masternode dmn) {
return context.coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate<CoinJoinClientManager>() {
return coinJoinManager.coinJoinClientManagers.values().stream().anyMatch(new Predicate<CoinJoinClientManager>() {
@Override
public boolean test(CoinJoinClientManager coinJoinClientManager) {
return coinJoinClientManager.trySubmitDenominate(dmn.getService());
Expand All @@ -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();
Expand Down
Loading

0 comments on commit 16c31bb

Please sign in to comment.