diff --git a/src/main/java/com/iota/iri/Iota.java b/src/main/java/com/iota/iri/Iota.java
index d104db0fa4..f054ab66eb 100644
--- a/src/main/java/com/iota/iri/Iota.java
+++ b/src/main/java/com/iota/iri/Iota.java
@@ -10,9 +10,17 @@
import com.iota.iri.network.UDPReceiver;
import com.iota.iri.network.replicator.Replicator;
import com.iota.iri.service.TipsSolidifier;
+import com.iota.iri.service.ledger.impl.LedgerServiceImpl;
+import com.iota.iri.service.milestone.impl.LatestMilestoneTrackerImpl;
+import com.iota.iri.service.milestone.impl.LatestSolidMilestoneTrackerImpl;
+import com.iota.iri.service.milestone.impl.MilestoneServiceImpl;
+import com.iota.iri.service.milestone.impl.MilestoneSolidifierImpl;
+import com.iota.iri.service.milestone.impl.SeenMilestonesRetrieverImpl;
import com.iota.iri.service.snapshot.SnapshotException;
import com.iota.iri.service.snapshot.SnapshotProvider;
+import com.iota.iri.service.snapshot.impl.LocalSnapshotManagerImpl;
import com.iota.iri.service.snapshot.impl.SnapshotProviderImpl;
+import com.iota.iri.service.snapshot.impl.SnapshotServiceImpl;
import com.iota.iri.service.tipselection.EntryPointSelector;
import com.iota.iri.service.tipselection.RatingCalculator;
import com.iota.iri.service.tipselection.TailFinder;
@@ -23,6 +31,8 @@
import com.iota.iri.service.tipselection.impl.TailFinderImpl;
import com.iota.iri.service.tipselection.impl.TipSelectorImpl;
import com.iota.iri.service.tipselection.impl.WalkerAlpha;
+import com.iota.iri.service.transactionpruning.TransactionPruningException;
+import com.iota.iri.service.transactionpruning.async.AsyncTransactionPruner;
import com.iota.iri.storage.Indexable;
import com.iota.iri.storage.Persistable;
import com.iota.iri.storage.PersistenceProvider;
@@ -73,10 +83,27 @@
public class Iota {
private static final Logger log = LoggerFactory.getLogger(Iota.class);
- public final LedgerValidator ledgerValidator;
- public final MilestoneTracker milestoneTracker;
+ public final SnapshotProviderImpl snapshotProvider;
+
+ public final SnapshotServiceImpl snapshotService;
+
+ public final LocalSnapshotManagerImpl localSnapshotManager;
+
+ public final MilestoneServiceImpl milestoneService;
+
+ public final LatestMilestoneTrackerImpl latestMilestoneTracker;
+
+ public final LatestSolidMilestoneTrackerImpl latestSolidMilestoneTracker;
+
+ public final SeenMilestonesRetrieverImpl seenMilestonesRetriever;
+
+ public final LedgerServiceImpl ledgerService = new LedgerServiceImpl();
+
+ public final AsyncTransactionPruner transactionPruner;
+
+ public final MilestoneSolidifierImpl milestoneSolidifier;
+
public final Tangle tangle;
- public final SnapshotProvider snapshotProvider;
public final TransactionValidator transactionValidator;
public final TipsSolidifier tipsSolidifier;
public final TransactionRequester transactionRequester;
@@ -92,27 +119,38 @@ public class Iota {
* Initializes the latest snapshot and then creates all services needed to run an IOTA node.
*
* @param configuration Information about how this node will be configured.
- * @throws IOException If the Snapshot fails to initialize.
- * This can happen if the snapshot signature is invalid or the file cannot be read.
+ * @throws TransactionPruningException If the TransactionPruner could not restore its state.
+ * @throws SnapshotException If the Snapshot fails to initialize.
+ * This can happen if the snapshot signature is invalid or the file cannot be read.
*/
- public Iota(IotaConfig configuration) throws SnapshotException, IOException {
+ public Iota(IotaConfig configuration) throws TransactionPruningException, SnapshotException {
this.configuration = configuration;
- Snapshot initialSnapshot = Snapshot.init(configuration).clone();
+
+ // new refactored instances
+ snapshotProvider = new SnapshotProviderImpl();
+ snapshotService = new SnapshotServiceImpl();
+ localSnapshotManager = new LocalSnapshotManagerImpl();
+ milestoneService = new MilestoneServiceImpl();
+ latestMilestoneTracker = new LatestMilestoneTrackerImpl();
+ latestSolidMilestoneTracker = new LatestSolidMilestoneTrackerImpl();
+ seenMilestonesRetriever = new SeenMilestonesRetrieverImpl();
+ milestoneSolidifier = new MilestoneSolidifierImpl();
+ transactionPruner = new AsyncTransactionPruner();
+
+ // legacy code
tangle = new Tangle();
messageQ = MessageQ.createWith(configuration);
tipsViewModel = new TipsViewModel();
- snapshotProvider = new SnapshotProviderImpl(configuration);
- transactionRequester = new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), messageQ);
- transactionValidator = new TransactionValidator(tangle, snapshotProvider.getInitialSnapshot(), tipsViewModel,
- transactionRequester);
- milestoneTracker = new MilestoneTracker(tangle, snapshotProvider, transactionValidator, messageQ, initialSnapshot, configuration);
- node = new Node(tangle, snapshotProvider.getInitialSnapshot(), transactionValidator, transactionRequester, tipsViewModel, milestoneTracker, messageQ,
- configuration);
+ transactionRequester = new TransactionRequester(tangle, snapshotProvider, messageQ);
+ transactionValidator = new TransactionValidator(tangle, snapshotProvider, tipsViewModel, transactionRequester);
+ node = new Node(tangle, snapshotProvider, transactionValidator, transactionRequester, tipsViewModel,
+ latestMilestoneTracker, messageQ, configuration);
replicator = new Replicator(node, configuration);
udpReceiver = new UDPReceiver(node, configuration);
- ledgerValidator = new LedgerValidator(tangle, snapshotProvider, milestoneTracker, transactionRequester, messageQ);
tipsSolidifier = new TipsSolidifier(tangle, transactionValidator, tipsViewModel);
tipsSelector = createTipSelector(configuration);
+
+ injectDependencies();
}
/**
@@ -136,13 +174,40 @@ public void init() throws Exception {
tangle.clearColumn(com.iota.iri.model.StateDiff.class);
tangle.clearMetadata(com.iota.iri.model.persistables.Transaction.class);
}
- milestoneTracker.init(SpongeFactory.Mode.CURLP27, 1, ledgerValidator);
+
transactionValidator.init(configuration.isTestnet(), configuration.getMwm());
tipsSolidifier.init();
transactionRequester.init(configuration.getpRemoveRequest());
udpReceiver.init();
replicator.init();
node.init();
+
+ latestMilestoneTracker.start();
+ latestSolidMilestoneTracker.start();
+ seenMilestonesRetriever.start();
+ milestoneSolidifier.start();
+
+ if (configuration.getLocalSnapshotsEnabled()) {
+ localSnapshotManager.start(latestMilestoneTracker);
+
+ if (configuration.getLocalSnapshotsPruningEnabled()) {
+ transactionPruner.start();
+ }
+ }
+ }
+
+ private void injectDependencies() throws SnapshotException, TransactionPruningException {
+ snapshotProvider.init(configuration);
+ snapshotService.init(tangle, snapshotProvider, configuration);
+ localSnapshotManager.init(snapshotProvider, snapshotService, transactionPruner, configuration);
+ milestoneService.init(tangle, snapshotProvider, messageQ, configuration);
+ latestMilestoneTracker.init(tangle, snapshotProvider, milestoneService, milestoneSolidifier,
+ messageQ, configuration);
+ latestSolidMilestoneTracker.init(tangle, snapshotProvider, ledgerService, latestMilestoneTracker, messageQ);
+ seenMilestonesRetriever.init(tangle, snapshotProvider, transactionRequester);
+ milestoneSolidifier.init(snapshotProvider, transactionValidator);
+ ledgerService.init(tangle, snapshotProvider, snapshotService, milestoneService);
+ transactionPruner.init(tangle, snapshotProvider, tipsViewModel, configuration).restoreState();
}
private void rescanDb() throws Exception {
@@ -175,7 +240,6 @@ private void rescanDb() throws Exception {
* Exceptions during shutdown are not caught.
*/
public void shutdown() throws Exception {
- milestoneTracker.shutDown();
tipsSolidifier.shutdown();
node.shutdown();
udpReceiver.shutdown();
@@ -183,6 +247,21 @@ public void shutdown() throws Exception {
transactionValidator.shutdown();
tangle.shutdown();
messageQ.shutdown();
+
+ // shutdown in reverse starting order (to not break any dependencies)
+ milestoneSolidifier.shutdown();
+ seenMilestonesRetriever.shutdown();
+ latestSolidMilestoneTracker.shutdown();
+ latestMilestoneTracker.shutdown();
+ snapshotProvider.shutdown();
+
+ if (configuration.getLocalSnapshotsEnabled()) {
+ localSnapshotManager.shutdown();
+
+ if (configuration.getLocalSnapshotsPruningEnabled()) {
+ transactionPruner.shutdown();
+ }
+ }
}
private void initializeTangle() {
@@ -204,11 +283,12 @@ private void initializeTangle() {
}
private TipSelector createTipSelector(TipSelConfig config) {
- EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider, milestoneTracker);
- RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider.getInitialSnapshot());
+ EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider,
+ latestMilestoneTracker);
+ RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider);
TailFinder tailFinder = new TailFinderImpl(tangle);
Walker walker = new WalkerAlpha(tailFinder, tangle, messageQ, new SecureRandom(), config);
- return new TipSelectorImpl(tangle, snapshotProvider, ledgerValidator, entryPointSelector, ratingCalculator,
- walker, milestoneTracker, config);
+ return new TipSelectorImpl(tangle, snapshotProvider, ledgerService, entryPointSelector, ratingCalculator,
+ walker, config);
}
}
diff --git a/src/main/java/com/iota/iri/TransactionValidator.java b/src/main/java/com/iota/iri/TransactionValidator.java
index 9d1143e513..da8f9cb575 100644
--- a/src/main/java/com/iota/iri/TransactionValidator.java
+++ b/src/main/java/com/iota/iri/TransactionValidator.java
@@ -5,10 +5,10 @@
import com.iota.iri.crypto.Curl;
import com.iota.iri.crypto.Sponge;
import com.iota.iri.crypto.SpongeFactory;
-import com.iota.iri.service.snapshot.Snapshot;
import com.iota.iri.model.Hash;
import com.iota.iri.model.TransactionHash;
import com.iota.iri.network.TransactionRequester;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.storage.Tangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -24,7 +24,7 @@ public class TransactionValidator {
public static final int SOLID_SLEEP_TIME = 500;
private final Tangle tangle;
- private final Snapshot initialSnapshot;
+ private final SnapshotProvider snapshotProvider;
private final TipsViewModel tipsViewModel;
private final TransactionRequester transactionRequester;
private int minWeightMagnitude = 81;
@@ -55,13 +55,13 @@ public class TransactionValidator {
* Constructor for Tangle Validator
*
* @param tangle relays tangle data to and from the persistence layer
- * @param initialSnapshot the initial snapshot that defines the genesis for our ledger state
+ * @param snapshotProvider data provider for the snapshots that are relevant for the node
* @param tipsViewModel container that gets updated with the latest tips (transactions with no children)
* @param transactionRequester used to request missing transactions from neighbors
*/
- TransactionValidator(Tangle tangle, Snapshot initialSnapshot, TipsViewModel tipsViewModel, TransactionRequester transactionRequester) {
+ TransactionValidator(Tangle tangle, SnapshotProvider snapshotProvider, TipsViewModel tipsViewModel, TransactionRequester transactionRequester) {
this.tangle = tangle;
- this.initialSnapshot = initialSnapshot;
+ this.snapshotProvider = snapshotProvider;
this.tipsViewModel = tipsViewModel;
this.transactionRequester = transactionRequester;
}
@@ -135,10 +135,10 @@ private boolean hasInvalidTimestamp(TransactionViewModel transactionViewModel) {
}
if (transactionViewModel.getAttachmentTimestamp() == 0) {
- return transactionViewModel.getTimestamp() < initialSnapshot.getTimestamp() && !initialSnapshot.hasSolidEntryPoint(transactionViewModel.getHash())
+ return transactionViewModel.getTimestamp() < snapshotProvider.getInitialSnapshot().getTimestamp() && !snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(transactionViewModel.getHash())
|| transactionViewModel.getTimestamp() > (System.currentTimeMillis() / 1000) + MAX_TIMESTAMP_FUTURE;
}
- return transactionViewModel.getAttachmentTimestamp() < (initialSnapshot.getTimestamp() * 1000L)
+ return transactionViewModel.getAttachmentTimestamp() < (snapshotProvider.getInitialSnapshot().getTimestamp() * 1000L)
|| transactionViewModel.getAttachmentTimestamp() > System.currentTimeMillis() + MAX_TIMESTAMP_FUTURE_MS;
}
@@ -246,7 +246,7 @@ public boolean checkSolidity(Hash hash, boolean milestone, int maxProcessedTrans
if(fromHash(tangle, hash).isSolid()) {
return true;
}
- Set analyzedHashes = new HashSet<>(initialSnapshot.getSolidEntryPoints().keySet());
+ Set analyzedHashes = new HashSet<>(snapshotProvider.getInitialSnapshot().getSolidEntryPoints().keySet());
if(maxProcessedTransactions != Integer.MAX_VALUE) {
maxProcessedTransactions += analyzedHashes.size();
}
@@ -261,7 +261,7 @@ public boolean checkSolidity(Hash hash, boolean milestone, int maxProcessedTrans
final TransactionViewModel transaction = fromHash(tangle, hashPointer);
if(!transaction.isSolid()) {
- if (transaction.getType() == PREFILLED_SLOT && !initialSnapshot.hasSolidEntryPoint(hashPointer)) {
+ if (transaction.getType() == PREFILLED_SLOT && !snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(hashPointer)) {
solid = false;
if (!transactionRequester.isTransactionRequested(hashPointer, milestone)) {
@@ -276,7 +276,7 @@ public boolean checkSolidity(Hash hash, boolean milestone, int maxProcessedTrans
}
}
if (solid) {
- updateSolidTransactions(tangle, initialSnapshot, analyzedHashes);
+ updateSolidTransactions(tangle, snapshotProvider.getInitialSnapshot(), analyzedHashes);
}
analyzedHashes.clear();
return solid;
@@ -339,7 +339,7 @@ void propagateSolidTransactions() {
for(Hash h: approvers) {
TransactionViewModel tx = fromHash(tangle, h);
if(quietQuickSetSolid(tx)) {
- tx.update(tangle, initialSnapshot, "solid|height");
+ tx.update(tangle, snapshotProvider.getInitialSnapshot(), "solid|height");
tipsViewModel.setSolid(h);
addSolidTransaction(h);
}
@@ -384,7 +384,7 @@ public void updateStatus(TransactionViewModel transactionViewModel) throws Excep
tipsViewModel.removeTipHash(transactionViewModel.getBranchTransactionHash());
if(quickSetSolid(transactionViewModel)) {
- transactionViewModel.update(tangle, initialSnapshot, "solid|height");
+ transactionViewModel.update(tangle, snapshotProvider.getInitialSnapshot(), "solid|height");
tipsViewModel.setSolid(transactionViewModel.getHash());
addSolidTransaction(transactionViewModel.getHash());
}
@@ -422,7 +422,7 @@ private boolean quickSetSolid(final TransactionViewModel transactionViewModel) t
}
if(solid) {
transactionViewModel.updateSolid(true);
- transactionViewModel.updateHeights(tangle, initialSnapshot);
+ transactionViewModel.updateHeights(tangle, snapshotProvider.getInitialSnapshot());
return true;
}
}
@@ -440,7 +440,7 @@ private boolean checkApproovee(TransactionViewModel approovee) throws Exception
transactionRequester.requestTransaction(approovee.getHash(), false);
return false;
}
- if(initialSnapshot.hasSolidEntryPoint(approovee.getHash())) {
+ if(snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(approovee.getHash())) {
return true;
}
return approovee.isSolid();
diff --git a/src/main/java/com/iota/iri/network/Node.java b/src/main/java/com/iota/iri/network/Node.java
index 805fc51eb8..6fef059f68 100644
--- a/src/main/java/com/iota/iri/network/Node.java
+++ b/src/main/java/com/iota/iri/network/Node.java
@@ -1,15 +1,15 @@
package com.iota.iri.network;
-import com.iota.iri.MilestoneTracker;
import com.iota.iri.TransactionValidator;
import com.iota.iri.conf.NodeConfig;
import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.crypto.SpongeFactory;
-import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.milestone.LatestMilestoneTracker;
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashFactory;
import com.iota.iri.model.TransactionHash;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.storage.Tangle;
import com.iota.iri.zmq.MessageQ;
import org.apache.commons.lang3.StringUtils;
@@ -56,10 +56,10 @@ public class Node {
private final ExecutorService executor = Executors.newFixedThreadPool(5);
private final NodeConfig configuration;
private final Tangle tangle;
- private final Snapshot initialSnapshot;
+ private final SnapshotProvider snapshotProvider;
private final TipsViewModel tipsViewModel;
private final TransactionValidator transactionValidator;
- private final MilestoneTracker milestoneTracker;
+ private final LatestMilestoneTracker latestMilestoneTracker;
private final TransactionRequester transactionRequester;
private final MessageQ messageQ;
@@ -78,15 +78,15 @@ public class Node {
public static final ConcurrentSkipListSet rejectedAddresses = new ConcurrentSkipListSet();
private DatagramSocket udpSocket;
- public Node(final Tangle tangle, Snapshot initialSnapshot, final TransactionValidator transactionValidator, final TransactionRequester transactionRequester, final TipsViewModel tipsViewModel, final MilestoneTracker milestoneTracker, final MessageQ messageQ, final NodeConfig configuration
+ public Node(final Tangle tangle, SnapshotProvider snapshotProvider, final TransactionValidator transactionValidator, final TransactionRequester transactionRequester, final TipsViewModel tipsViewModel, final LatestMilestoneTracker latestMilestoneTracker, final MessageQ messageQ, final NodeConfig configuration
) {
this.configuration = configuration;
this.tangle = tangle;
- this.initialSnapshot = initialSnapshot;
+ this.snapshotProvider = snapshotProvider ;
this.transactionValidator = transactionValidator;
this.transactionRequester = transactionRequester;
this.tipsViewModel = tipsViewModel;
- this.milestoneTracker = milestoneTracker;
+ this.latestMilestoneTracker = latestMilestoneTracker ;
this.messageQ = messageQ;
this.reqHashSize = configuration.getRequestHashSize();
int packetSize = configuration.getTransactionPacketSize();
@@ -366,7 +366,7 @@ public void processReceivedData(TransactionViewModel receivedTransactionViewMode
//store new transaction
try {
- stored = receivedTransactionViewModel.store(tangle, initialSnapshot);
+ stored = receivedTransactionViewModel.store(tangle, snapshotProvider.getInitialSnapshot());
} catch (Exception e) {
log.error("Error accessing persistence store.", e);
neighbor.incInvalidTransactions();
@@ -378,7 +378,7 @@ public void processReceivedData(TransactionViewModel receivedTransactionViewMode
try {
transactionValidator.updateStatus(receivedTransactionViewModel);
receivedTransactionViewModel.updateSender(neighbor.getAddress().toString());
- receivedTransactionViewModel.update(tangle, initialSnapshot, "arrivalTime|sender");
+ receivedTransactionViewModel.update(tangle, snapshotProvider.getInitialSnapshot(), "arrivalTime|sender");
} catch (Exception e) {
log.error("Error updating transactions.", e);
}
@@ -449,7 +449,7 @@ public void replyToRequest(Hash requestedHash, Neighbor neighbor) {
}
private Hash getRandomTipPointer() throws Exception {
- Hash tip = rnd.nextDouble() < configuration.getpSendMilestone() ? milestoneTracker.latestMilestone : tipsViewModel.getRandomSolidTipHash();
+ Hash tip = rnd.nextDouble() < configuration.getpSendMilestone() ? latestMilestoneTracker.getLatestMilestoneHash() : tipsViewModel.getRandomSolidTipHash();
return tip == null ? Hash.NULL_HASH : tip;
}
@@ -515,7 +515,7 @@ private Runnable spawnTipRequesterThread() {
while (!shuttingDown.get()) {
try {
- final TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle, milestoneTracker.latestMilestone);
+ final TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle, latestMilestoneTracker.getLatestMilestoneHash());
System.arraycopy(transactionViewModel.getBytes(), 0, tipRequestingPacket.getData(), 0, TransactionViewModel.SIZE);
System.arraycopy(transactionViewModel.getHash().bytes(), 0, tipRequestingPacket.getData(), TransactionViewModel.SIZE,
reqHashSize);
diff --git a/src/main/java/com/iota/iri/network/TransactionRequester.java b/src/main/java/com/iota/iri/network/TransactionRequester.java
index 8ab5f4150b..e3d1db8b61 100644
--- a/src/main/java/com/iota/iri/network/TransactionRequester.java
+++ b/src/main/java/com/iota/iri/network/TransactionRequester.java
@@ -2,7 +2,7 @@
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
-import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.zmq.MessageQ;
import com.iota.iri.storage.Tangle;
import org.apache.commons.lang3.ArrayUtils;
@@ -30,11 +30,11 @@ public class TransactionRequester {
private final Object syncObj = new Object();
private final Tangle tangle;
- private final Snapshot initialSnapshot;
+ private final SnapshotProvider snapshotProvider;
- public TransactionRequester(Tangle tangle, Snapshot initialSnapshot, MessageQ messageQ) {
+ public TransactionRequester(Tangle tangle, SnapshotProvider snapshotProvider, MessageQ messageQ) {
this.tangle = tangle;
- this.initialSnapshot = initialSnapshot;
+ this.snapshotProvider = snapshotProvider;
this.messageQ = messageQ;
}
@@ -65,7 +65,7 @@ public boolean clearTransactionRequest(Hash hash) {
}
public void requestTransaction(Hash hash, boolean milestone) throws Exception {
- if (!initialSnapshot.hasSolidEntryPoint(hash) && !TransactionViewModel.exists(tangle, hash)) {
+ if (!snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(hash) && !TransactionViewModel.exists(tangle, hash)) {
synchronized (syncObj) {
if(milestone) {
transactionsToRequest.remove(hash);
diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java
index 50f90ae46f..fd555f1710 100644
--- a/src/main/java/com/iota/iri/service/API.java
+++ b/src/main/java/com/iota/iri/service/API.java
@@ -2,7 +2,6 @@
import com.iota.iri.*;
import com.iota.iri.conf.APIConfig;
-import com.iota.iri.conf.ConsensusConfig;
import com.iota.iri.controllers.AddressViewModel;
import com.iota.iri.controllers.BundleViewModel;
import com.iota.iri.controllers.TagViewModel;
@@ -16,6 +15,7 @@
import com.iota.iri.model.persistables.Transaction;
import com.iota.iri.network.Neighbor;
import com.iota.iri.service.dto.*;
+import com.iota.iri.service.snapshot.Snapshot;
import com.iota.iri.service.tipselection.TipSelector;
import com.iota.iri.service.tipselection.impl.WalkValidatorImpl;
import com.iota.iri.utils.Converter;
@@ -63,14 +63,14 @@
/**
*
- * The API makes it possible to interact with the node by requesting information or actions to be taken.
+ * The API makes it possible to interact with the node by requesting information or actions to be taken.
* You can interact with it by passing a JSON object which at least contains a command.
* Upon successful execution of the command, the API returns your requested information in an {@link AbstractResponse}.
*
*
- * If the request is invalid, an {@link ErrorResponse} is returned.
+ * If the request is invalid, an {@link ErrorResponse} is returned.
* This, for example, happens when the command does not exist or there is no command section at all.
- * If there is an error in the given data during the execution of a command, an {@link ErrorResponse} is also sent.
+ * If there is an error in the given data during the execution of a command, an {@link ErrorResponse} is also sent.
*
*
* If an Exception is thrown during the execution of a command, an {@link ExceptionResponse} is returned.
@@ -81,13 +81,12 @@ public class API {
public static final String REFERENCE_TRANSACTION_NOT_FOUND = "reference transaction not found";
public static final String REFERENCE_TRANSACTION_TOO_OLD = "reference transaction is too old";
-
+
public static final String INVALID_SUBTANGLE = "This operation cannot be executed: "
+ "The subtangle has not been updated yet.";
-
+
private static final Logger log = LoggerFactory.getLogger(API.class);
private final IXI ixi;
- private final int milestoneStartIndex;
private Undertow server;
@@ -122,9 +121,9 @@ public class API {
/**
* Starts loading the IOTA API, parameters do not have to be initialized.
- *
+ *
* @param instance The data source we interact with during any API call.
- * @param ixi If a command is not in the standard API,
+ * @param ixi If a command is not in the standard API,
* we try to process it as a Nashorn JavaScript module through {@link IXI}
*/
public API(Iota instance, IXI ixi) {
@@ -136,7 +135,6 @@ public API(Iota instance, IXI ixi) {
maxGetTrytes = configuration.getMaxGetTrytes();
maxBodyLength = configuration.getMaxBodyLength();
testNet = configuration.isTestnet();
- milestoneStartIndex = ((ConsensusConfig) configuration).getMilestoneStartIndex();
previousEpochsSpentAddresses = new ConcurrentHashMap<>();
@@ -153,12 +151,12 @@ public API(Iota instance, IXI ixi) {
* If reading from the previous epoch fails, a log is printed. The API will continue to initialize.
*
*
- * Get the {@link APIConfig} from the {@link Iota} instance,
+ * Get the {@link APIConfig} from the {@link Iota} instance,
* and read {@link APIConfig#getPort()} and {@link APIConfig#getApiHost()}
*
*
- * Builds a secure {@link Undertow} server with the port and host.
- * If {@link APIConfig#getRemoteAuth()} is defined, remote authentication is blocked for anyone except
+ * Builds a secure {@link Undertow} server with the port and host.
+ * If {@link APIConfig#getRemoteAuth()} is defined, remote authentication is blocked for anyone except
* those defined in {@link APIConfig#getRemoteAuth()} or localhost.
* This is done with {@link BasicAuthenticationMechanism} in a {@link AuthenticationMode#PRO_ACTIVE} mode.
* By default, this authentication is disabled.
@@ -167,8 +165,8 @@ public API(Iota instance, IXI ixi) {
* Starts the server, opening it for HTTP API requests
*
*
- *
- * @throws IOException If we are not on the testnet, and the previousEpochsSpentAddresses files cannot be found.
+ *
+ * @throws IOException If we are not on the testnet, and the previousEpochsSpentAddresses files cannot be found.
* Currently this exception is caught in {@link #readPreviousEpochsSpentAddresses(boolean)}
*/
public void init() throws IOException {
@@ -211,9 +209,9 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
/**
* Read the spend addresses from the previous epoch. Used in {@link #wasAddressSpentFrom(Hash)}.
* If this fails, a log is printed. The API will continue to initialize.
- *
+ *
* @param isTestnet If this node is running on the testnet. If this is true, nothing is loaded.
- * @throws IOException If we are not on the testnet and previousEpochsSpentAddresses files cannot be found.
+ * @throws IOException If we are not on the testnet and previousEpochsSpentAddresses files cannot be found.
* Currently this exception is caught in {@link #readPreviousEpochsSpentAddresses(boolean)}
*/
private void readPreviousEpochsSpentAddresses(boolean isTestnet) throws IOException {
@@ -225,7 +223,7 @@ private void readPreviousEpochsSpentAddresses(boolean isTestnet) throws IOExcept
.configuration
.getPreviousEpochSpentAddressesFiles()
.split(" ");
-
+
for (String previousEpochsSpentAddressesFile : previousEpochsSpentAddressesFiles) {
InputStream in = Snapshot.class.getResourceAsStream(previousEpochsSpentAddressesFile);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
@@ -238,9 +236,9 @@ private void readPreviousEpochsSpentAddresses(boolean isTestnet) throws IOExcept
}
}
}
-
+
/**
- * Sends the API response back as JSON to the requester.
+ * Sends the API response back as JSON to the requester.
* Status code of the HTTP request is also set according to the type of response.
*
* - {@link ErrorResponse}: 400
@@ -248,12 +246,12 @@ private void readPreviousEpochsSpentAddresses(boolean isTestnet) throws IOExcept
* - {@link ExceptionResponse}: 500
* - Default: 200
*
- *
+ *
* @param exchange Contains information about what the client sent to us
- * @param res The response of the API.
- * See {@link #processRequest(HttpServerExchange)}
+ * @param res The response of the API.
+ * See {@link #processRequest(HttpServerExchange)}
* and {@link #process(String, InetSocketAddress)} for the different responses in each case.
- * @param beginningTime The time when we received the request, in milliseconds.
+ * @param beginningTime The time when we received the request, in milliseconds.
* This will be used to set the response duration in {@link AbstractResponse#setDuration(Integer)}
* @throws IOException When connection to client has been lost - Currently being caught.
*/
@@ -263,13 +261,13 @@ private void sendResponse(HttpServerExchange exchange, AbstractResponse res, lon
if (res instanceof ErrorResponse) {
// bad request or invalid parameters
- exchange.setStatusCode(400);
+ exchange.setStatusCode(400);
} else if (res instanceof AccessLimitedResponse) {
// API method not allowed
- exchange.setStatusCode(401);
+ exchange.setStatusCode(401);
} else if (res instanceof ExceptionResponse) {
// internal error
- exchange.setStatusCode(500);
+ exchange.setStatusCode(500);
}
setupResponseHeaders(exchange);
@@ -299,17 +297,17 @@ private void sendResponse(HttpServerExchange exchange, AbstractResponse res, lon
/**
*
- * Processes an API HTTP request.
+ * Processes an API HTTP request.
* No checks have been done until now, except that it is not an OPTIONS request.
* We can be sure that we are in a thread that allows blocking.
*
*
- * The request process duration is recorded.
+ * The request process duration is recorded.
* During this the request gets verified. If it is incorrect, an {@link ErrorResponse} is made.
* Otherwise it is processed in {@link #process(String, InetSocketAddress)}.
* The result is sent back to the requester.
*
- *
+ *
* @param exchange Contains the data the client sent to us
* @throws IOException If the body of this HTTP request cannot be read
*/
@@ -332,7 +330,7 @@ private void processRequest(final HttpServerExchange exchange) throws IOExceptio
}
/**
- * Handles an API request body.
+ * Handles an API request body.
* Its returned {@link AbstractResponse} is created using the following logic
*
* -
@@ -351,19 +349,19 @@ private void processRequest(final HttpServerExchange exchange) throws IOExceptio
* {@link ExceptionResponse} if we encountered an unexpected exception during command processing.
*
* -
- * {@link AbstractResponse} when the command is successfully processed.
+ * {@link AbstractResponse} when the command is successfully processed.
* The response class depends on the command executed.
*
*
- *
+ *
* @param requestString The JSON encoded data of the request.
* This String is attempted to be converted into a {@code Map}.
* @param sourceAddress The address from the sender of this API request.
- * @return The result of this request.
- * @throws UnsupportedEncodingException If the requestString cannot be parsed into a Map.
+ * @return The result of this request.
+ * @throws UnsupportedEncodingException If the requestString cannot be parsed into a Map.
Currently caught and turned into a {@link ExceptionResponse}.
*/
- private AbstractResponse process(final String requestString, InetSocketAddress sourceAddress)
+ private AbstractResponse process(final String requestString, InetSocketAddress sourceAddress)
throws UnsupportedEncodingException {
try {
@@ -379,7 +377,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
return ErrorResponse.create("COMMAND parameter has not been specified in the request.");
}
- // Is this command allowed to be run from this request address?
+ // Is this command allowed to be run from this request address?
// We check the remote limit API configuration.
if (instance.configuration.getRemoteLimitApi().contains(command) &&
!sourceAddress.getAddress().isLoopbackAddress()) {
@@ -527,7 +525,7 @@ private AbstractResponse process(final String requestString, InetSocketAddress s
/**
* Check if a list of addresses was ever spent from, in the current epoch, or in previous epochs.
* If an address has a pending transaction, it is also marked as spend.
- *
+ *
* @param addresses List of addresses to check if they were ever spent from.
**/
private AbstractResponse wereAddressesSpentFromStatement(List addresses) throws Exception {
@@ -547,7 +545,7 @@ private AbstractResponse wereAddressesSpentFromStatement(List addresses)
/**
* Checks if the address was ever spent from, in the current epoch, or in previous epochs.
* If an address has a pending transaction, it is also marked as spent.
- *
+ *
* @param address The address to check if it was ever spent from.
* @return true if it was spent from, otherwise false
* @throws Exception When a model could not be loaded.
@@ -556,7 +554,7 @@ private boolean wasAddressSpentFrom(Hash address) throws Exception {
if (previousEpochsSpentAddresses.containsKey(address)) {
return true;
}
-
+
Set hashes = AddressViewModel.load(instance.tangle, address).getHashes();
for (Hash hash : hashes) {
final TransactionViewModel tx = TransactionViewModel.fromHash(instance.tangle, hash);
@@ -566,7 +564,7 @@ private boolean wasAddressSpentFrom(Hash address) throws Exception {
if (tx.snapshotIndex() != 0) {
return true;
}
-
+
// Transaction is pending
Hash tail = findTail(hash);
if (tail != null && BundleValidator.validate(instance.tangle, instance.snapshotProvider.getInitialSnapshot(), tail).size() != 0) {
@@ -574,7 +572,7 @@ private boolean wasAddressSpentFrom(Hash address) throws Exception {
}
}
}
-
+
// No spending transaction found
return false;
}
@@ -582,7 +580,7 @@ private boolean wasAddressSpentFrom(Hash address) throws Exception {
/**
* Walks back from the hash until a tail transaction has been found or transaction aprovee is not found.
* A tail transaction is the first transaction in a bundle, thus with index = 0
- *
+ *
* @param hash The transaction hash where we start the search from. If this is a tail, its hash is returned.
* @return The transaction hash of the tail
* @throws Exception When a model could not be loaded.
@@ -592,7 +590,7 @@ private Hash findTail(Hash hash) throws Exception {
final Hash bundleHash = tx.getBundleHash();
long index = tx.getCurrentIndex();
boolean foundApprovee = false;
-
+
// As long as the index is bigger than 0 and we are still traversing the same bundle
// If the hash we asked about is already a tail, this loop never starts
while (index-- > 0 && tx.getBundleHash().equals(bundleHash)) {
@@ -609,7 +607,7 @@ private Hash findTail(Hash hash) throws Exception {
break;
}
}
-
+
if (tx.getCurrentIndex() == 0) {
return tx.getHash();
}
@@ -618,7 +616,7 @@ private Hash findTail(Hash hash) throws Exception {
/**
- *
+ *
* Checks the consistency of the transactions.
* Marks state as false on the following checks:
*
@@ -626,9 +624,9 @@ private Hash findTail(Hash hash) throws Exception {
* - Invalid bundle
* - Tails of tails are invalid
*
- *
+ *
* If a transaction does not exist, or it is not a tail, an {@link ErrorResponse} is returned.
- *
+ *
* @param transactionsList Transactions you want to check the consistency for
* @return {@link CheckConsistency}
**/
@@ -661,10 +659,10 @@ private AbstractResponse checkConsistencyStatement(List transactionsList
// Transactions are valid, lets check ledger consistency
if (state) {
- instance.milestoneTracker.latestSnapshot.rwlock.readLock().lock();
+ instance.snapshotProvider.getLatestSnapshot().lockRead();
try {
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(instance.tangle, instance.snapshotProvider, instance.ledgerValidator,
- instance.milestoneTracker, instance.configuration);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(instance.tangle, instance.snapshotProvider, instance.ledgerService,
+ instance.configuration);
for (Hash transaction : transactions) {
if (!walkValidator.isValid(transaction)) {
state = false;
@@ -673,7 +671,7 @@ private AbstractResponse checkConsistencyStatement(List transactionsList
}
}
} finally {
- instance.milestoneTracker.latestSnapshot.rwlock.readLock().unlock();
+ instance.snapshotProvider.getLatestSnapshot().unlockRead();
}
}
@@ -683,13 +681,13 @@ private AbstractResponse checkConsistencyStatement(List transactionsList
/**
* Compares the last received confirmed milestone with the last global snapshot milestone.
* If these are equal, it means the tangle is empty and therefore invalid.
- *
+ *
* @return false if we received at least a solid milestone, otherwise true
*/
public boolean invalidSubtangleStatus() {
- return (instance.milestoneTracker.latestSolidSubtangleMilestoneIndex == milestoneStartIndex);
+ return (instance.snapshotProvider.getLatestSnapshot().getIndex() == instance.snapshotProvider.getInitialSnapshot().getIndex());
}
-
+
/**
* Returns the set of neighbors you are connected with, as well as their activity statistics (or counters).
* The activity counters are reset after restarting IRI.
@@ -699,11 +697,11 @@ public boolean invalidSubtangleStatus() {
private AbstractResponse getNeighborsStatement() {
return GetNeighborsResponse.create(instance.node.getNeighbors());
}
-
+
/**
* Temporarily add a list of neighbors to your node.
* The added neighbors will not be available after restart.
- * Add the neighbors to your config file
+ * Add the neighbors to your config file
* or supply them in the -n command line option if you want to add them permanently.
*
* The URI (Unique Resource Identification) for adding neighbors is:
@@ -779,19 +777,19 @@ private synchronized AbstractResponse getTrytesStatement(List hashes) th
return GetTrytesResponse.create(elements);
}
-
+
private static int counterGetTxToApprove = 0;
-
+
/**
* Can be 0 or more, and is set to 0 every 100 requests.
* Each increase indicates another 2 tips send.
- *
+ *
* @return The current amount of times this node has returned transactions to approve
*/
private static int getCounterGetTxToApprove() {
return counterGetTxToApprove;
}
-
+
/**
* Increases the amount of tips send for transactions to approve by one
*/
@@ -800,19 +798,19 @@ private static void incCounterGetTxToApprove() {
}
private static long ellapsedTime_getTxToApprove = 0L;
-
+
/**
* Can be 0 or more, and is set to 0 every 100 requests.
- *
+ *
* @return The current amount of time spent on sending transactions to approve in milliseconds
*/
private static long getEllapsedTimeGetTxToApprove() {
return ellapsedTime_getTxToApprove;
}
-
+
/**
* Increases the current amount of time spent on sending transactions to approve
- *
+ *
* @param ellapsedTime the time to add, in milliseconds
*/
private static void incEllapsedTimeGetTxToApprove(long ellapsedTime) {
@@ -850,12 +848,12 @@ private synchronized AbstractResponse getTransactionsToApproveStatement(int dept
/**
* Gets tips which can be used by new transactions to approve.
* If debug is enabled, statistics on tip selection will be gathered.
- *
+ *
* @param depth The milestone depth for finding the transactions to approve.
* @param reference An optional transaction hash to be referenced by tips.
* @return The tips which can be approved.
* @throws Exception if the subtangle is out of date or if we fail to retrieve transaction tips.
- * @see TipSelector
+ * @see TipSelector
*/
List getTransactionToApproveTips(int depth, Optional reference) throws Exception {
if (invalidSubtangleStatus()) {
@@ -872,9 +870,9 @@ List getTransactionToApproveTips(int depth, Optional reference) thro
/**
*
- * Handles statistics on tip selection.
+ * Handles statistics on tip selection.
* Increases the tip selection by one use.
- *
+ *
*
* If the {@link #getCounterGetTxToApprove()} is a power of 100, a log is send and counters are reset.
*
@@ -883,9 +881,9 @@ private void gatherStatisticsOnTipSelection() {
API.incCounterGetTxToApprove();
if ((getCounterGetTxToApprove() % 100) == 0) {
String sb = "Last 100 getTxToApprove consumed "
- + API.getEllapsedTimeGetTxToApprove() / 1000000000L
+ + API.getEllapsedTimeGetTxToApprove() / 1000000000L
+ " seconds processing time.";
-
+
log.debug(sb);
counterGetTxToApprove = 0;
ellapsedTime_getTxToApprove = 0L;
@@ -922,7 +920,7 @@ public void storeTransactionsStatement(List trytes) throws Exception {
instance.transactionValidator.getMinWeightMagnitude());
elements.add(transactionViewModel);
}
-
+
for (final TransactionViewModel transactionViewModel : elements) {
//store transactions
if(transactionViewModel.store(instance.tangle, instance.snapshotProvider.getInitialSnapshot())) {
@@ -933,7 +931,7 @@ public void storeTransactionsStatement(List trytes) throws Exception {
}
}
}
-
+
/**
* Interrupts and completely aborts the attachToTangle process.
*
@@ -951,19 +949,20 @@ private AbstractResponse interruptAttachingToTangleStatement(){
**/
private AbstractResponse getNodeInfoStatement(){
String name = instance.configuration.isTestnet() ? IRI.TESTNET_NAME : IRI.MAINNET_NAME;
- return GetNodeInfoResponse.create(name, IRI.VERSION,
+ return GetNodeInfoResponse.create(name, IRI.VERSION,
Runtime.getRuntime().availableProcessors(),
- Runtime.getRuntime().freeMemory(),
- System.getProperty("java.version"),
+ Runtime.getRuntime().freeMemory(),
+ System.getProperty("java.version"),
Runtime.getRuntime().maxMemory(),
- Runtime.getRuntime().totalMemory(),
- instance.milestoneTracker.latestMilestone, instance.milestoneTracker.latestMilestoneIndex,
- instance.milestoneTracker.latestSolidSubtangleMilestone,
- instance.milestoneTracker.latestSolidSubtangleMilestoneIndex,
- instance.milestoneTracker.milestoneStartIndex,
- instance.node.howManyNeighbors(),
+ Runtime.getRuntime().totalMemory(),
+ instance.latestMilestoneTracker.getLatestMilestoneHash(),
+ instance.latestMilestoneTracker.getLatestMilestoneIndex(),
+ instance.snapshotProvider.getLatestSnapshot().getHash(),
+ instance.snapshotProvider.getLatestSnapshot().getIndex(),
+ instance.snapshotProvider.getInitialSnapshot().getIndex(),
+ instance.node.howManyNeighbors(),
instance.node.queuedTransactionsSize(),
- System.currentTimeMillis(),
+ System.currentTimeMillis(),
instance.tipsViewModel.size(),
instance.transactionRequester.numberOfTransactionsToRequest(),
features,
@@ -988,13 +987,13 @@ private AbstractResponse getNodeInfoStatement(){
* @throws Exception When a transaction cannot be loaded from hash
**/
private AbstractResponse getInclusionStatesStatement(
- final List transactions,
+ final List transactions,
final List tips) throws Exception {
-
+
final List trans = transactions.stream()
.map(HashFactory.TRANSACTION::create)
.collect(Collectors.toList());
-
+
final List tps = tips.stream().
map(HashFactory.TRANSACTION::create)
.collect(Collectors.toList());
@@ -1011,20 +1010,20 @@ private AbstractResponse getInclusionStatesStatement(
}
}
}
-
+
// Finds the lowest tips index, or 0
int minTipsIndex = tipsIndex.stream().reduce((a,b) -> a < b ? a : b).orElse(0);
-
- // If the lowest tips index (minTipsIndex) is 0 (or lower),
+
+ // If the lowest tips index (minTipsIndex) is 0 (or lower),
// we can't check transactions against snapshots because there were no tips,
// or tips have not been confirmed by a snapshot yet
if(minTipsIndex > 0) {
// Finds the highest tips index, or 0
int maxTipsIndex = tipsIndex.stream().reduce((a,b) -> a > b ? a : b).orElse(0);
int count = 0;
-
+
// Checks transactions with indexes of tips, and sets inclusionStates byte to 1 or -1 accordingly
- // Sets to -1 if the transaction is only known by hash,
+ // Sets to -1 if the transaction is only known by hash,
// or has no index, or index is above the max tip index (not included).
// Sets to 1 if the transaction index is below the max index of tips (included).
@@ -1044,7 +1043,7 @@ private AbstractResponse getInclusionStatesStatement(
Set analyzedTips = new HashSet<>();
Map sameIndexTransactionCount = new HashMap<>();
Map> sameIndexTips = new HashMap<>();
-
+
// Sorts all tips per snapshot index. Stops if a tip is not in our database, or just as a hash.
for (final Hash tip : tps) {
TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(instance.tangle, tip);
@@ -1055,7 +1054,7 @@ private AbstractResponse getInclusionStatesStatement(
sameIndexTips.putIfAbsent(snapshotIndex, new LinkedList<>());
sameIndexTips.get(snapshotIndex).add(tip);
}
-
+
// Loop over all transactions without a state, and counts the amount per snapshot index
for(int i = 0; i < inclusionStates.length; i++) {
if(inclusionStates[i] == 0) {
@@ -1065,18 +1064,18 @@ private AbstractResponse getInclusionStatesStatement(
sameIndexTransactionCount.put(snapshotIndex, sameIndexTransactionCount.get(snapshotIndex) + 1);
}
}
-
+
// Loop over all snapshot indexes of transactions that were not confirmed.
// If we encounter an invalid tangle, stop this function completely.
for(Integer index : sameIndexTransactionCount.keySet()) {
// Get the tips from the snapshot indexes we are missing
Queue sameIndexTip = sameIndexTips.get(index);
-
+
// We have tips on the same level as transactions, do a manual search.
if (sameIndexTip != null && !exhaustiveSearchWithinIndex(
- sameIndexTip, analyzedTips, trans,
+ sameIndexTip, analyzedTips, trans,
inclusionStates, sameIndexTransactionCount.get(index), index)) {
-
+
return ErrorResponse.create(INVALID_SUBTANGLE);
}
}
@@ -1085,47 +1084,47 @@ private AbstractResponse getInclusionStatesStatement(
// If a state is 0 by now, we know nothing so assume not included
inclusionStatesBoolean[i] = inclusionStates[i] == 1;
}
-
+
{
return GetInclusionStatesResponse.create(inclusionStatesBoolean);
}
}
-
+
/**
* Traverses down the tips until all transactions we wish to validate have been found or transaction data is missing.
- *
+ *
* @param nonAnalyzedTransactions Tips we will analyze.
- * @param analyzedTips The hashes of tips we have analyzed.
+ * @param analyzedTips The hashes of tips we have analyzed.
* Hashes specified here won't be analyzed again.
- * @param transactions All transactions we are validating.
- * @param inclusionStates The state of each transaction.
+ * @param transactions All transactions we are validating.
+ * @param inclusionStates The state of each transaction.
* 1 means confirmed, -1 means unconfirmed, 0 is unknown confirmation.
* Should be of equal length as transactions.
- * @param count The amount of transactions on the same index level as nonAnalyzedTransactions.
+ * @param count The amount of transactions on the same index level as nonAnalyzedTransactions.
* @param index The snapshot index of the tips in nonAnalyzedTransactions.
- * @return true if all transactions are directly or indirectly references by
- * nonAnalyzedTransactions.
+ * @return true if all transactions are directly or indirectly references by
+ * nonAnalyzedTransactions.
* If at some point we are missing transaction data false is returned immediately.
* @throws Exception If a {@link TransactionViewModel} cannot be loaded.
*/
private boolean exhaustiveSearchWithinIndex(
- Queue nonAnalyzedTransactions,
- Set analyzedTips,
- List transactions,
+ Queue nonAnalyzedTransactions,
+ Set analyzedTips,
+ List transactions,
byte[] inclusionStates, int count, int index) throws Exception {
-
+
Hash pointer;
MAIN_LOOP:
// While we have nonAnalyzedTransactions in the Queue
while ((pointer = nonAnalyzedTransactions.poll()) != null) {
// Only analyze tips we haven't analyzed yet
if (analyzedTips.add(pointer)) {
-
+
// Check if the transactions have indeed this index. Otherwise ignore.
// Starts off with the tips in nonAnalyzedTransactions, but transaction trunk & branch gets added.
final TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(instance.tangle, pointer);
if (transactionViewModel.snapshotIndex() == index) {
- // Do we have the complete transaction?
+ // Do we have the complete transaction?
if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT) {
// Incomplete transaction data, stop search.
return false;
@@ -1133,17 +1132,17 @@ private boolean exhaustiveSearchWithinIndex(
// check all transactions we wish to verify confirmation for
for (int i = 0; i < inclusionStates.length; i++) {
if (inclusionStates[i] < 1 && pointer.equals(transactions.get(i))) {
- // A tip, or its branch/trunk points to this transaction.
+ // A tip, or its branch/trunk points to this transaction.
// That means this transaction is confirmed by this tip.
inclusionStates[i] = 1;
-
+
// Only stop search when we have found all transactions we were looking for
if (--count <= 0) {
break MAIN_LOOP;
}
}
}
-
+
// Add trunk and branch to the queue for the transaction confirmation check
nonAnalyzedTransactions.offer(transactionViewModel.getTrunkTransactionHash());
nonAnalyzedTransactions.offer(transactionViewModel.getBranchTransactionHash());
@@ -1160,14 +1159,14 @@ private boolean exhaustiveSearchWithinIndex(
* All input values are lists, for which a list of return values (transaction hashes), in the same order, is returned for all individual elements.
* The input fields can either be bundles, addresses, tags or approvees.
*
- *
+ *
* Using multiple of these input fields returns the intersection of the values.
* Returns an {@link com.iota.iri.service.dto.ErrorResponse} if more than maxFindTxs was found.
*
* @param request The map with input fields
* Must contain at least one of 'bundles', 'addresses', 'tags' or 'approvees'.
* @return {@link com.iota.iri.service.dto.FindTransactionsResponse}.
- * @throws Exception If a model cannot be loaded, no valid input fields were supplied
+ * @throws Exception If a model cannot be loaded, no valid input fields were supplied
* or the total transactions to find exceeds {@link APIConfig#getMaxFindTransactions()}.
**/
private synchronized AbstractResponse findTransactionsStatement(final Map request) throws Exception {
@@ -1264,7 +1263,7 @@ private synchronized AbstractResponse findTransactionsStatement(final Maptag is a {@link Hash#NULL_HASH}.
@@ -1281,23 +1280,23 @@ private String padTag(String tag) throws ValidationException {
/**
* Runs {@link #getParameterAsList(Map, String, int)} and transforms it into a {@link Set}.
- *
+ *
* @param request All request parameters.
* @param paramName The name of the parameter we want to turn into a list of Strings.
* @param size the length each String must have.
* @return the list of valid Tryte Strings.
- * @throws ValidationException If the requested parameter does not exist or
+ * @throws ValidationException If the requested parameter does not exist or
* the string is not exactly trytes of size length or
* the amount of Strings in the list exceeds {@link APIConfig#getMaxRequestsList}
*/
private Set getParameterAsSet(
- Map request,
+ Map request,
String paramName, int size) throws ValidationException {
HashSet result = getParameterAsList(request,paramName,size)
.stream()
.collect(Collectors.toCollection(HashSet::new));
-
+
if (result.contains(Hash.NULL_HASH.toString())) {
throw new ValidationException("Invalid " + paramName + " input");
}
@@ -1308,7 +1307,7 @@ private Set getParameterAsSet(
* Broadcast a list of transactions to all neighbors.
* The trytes to be used for this call should be valid, attached transaction trytes.
* These trytes are returned by attachToTangle, or by doing proof of work somewhere else.
- *
+ *
* @param trytes the list of transaction trytes to broadcast
**/
public void broadcastTransactionsStatement(List trytes) {
@@ -1319,7 +1318,7 @@ public void broadcastTransactionsStatement(List trytes) {
Converter.trits(tryte, txTrits, 0);
final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(
txTrits, instance.transactionValidator.getMinWeightMagnitude());
-
+
elements.add(transactionViewModel);
}
for (final TransactionViewModel transactionViewModel : elements) {
@@ -1332,10 +1331,10 @@ public void broadcastTransactionsStatement(List trytes) {
/**
*
- * Calculates the confirmed balance, as viewed by the specified tips.
- * If you do not specify the referencing tips,
+ * Calculates the confirmed balance, as viewed by the specified tips.
+ * If you do not specify the referencing tips,
* the returned balance is based on the latest confirmed milestone.
- * In addition to the balances, it also returns the referencing tips (or milestone),
+ * In addition to the balances, it also returns the referencing tips (or milestone),
* as well as the index with which the confirmed balance was determined.
* The balances are returned as a list in the same order as the addresses were provided as input.
*
@@ -1343,13 +1342,13 @@ public void broadcastTransactionsStatement(List trytes) {
*
* @param addresses The addresses where we will find the balance for.
* @param tips The optional tips to find the balance through.
- * @param threshold The confirmation threshold between 0 and 100(inclusive).
+ * @param threshold The confirmation threshold between 0 and 100(inclusive).
* Should be set to 100 for getting balance by counting only confirmed transactions.
* @return {@link com.iota.iri.service.dto.GetBalancesResponse}
* @throws Exception When the database has encountered an error
**/
- private AbstractResponse getBalancesStatement(List addresses,
- List tips,
+ private AbstractResponse getBalancesStatement(List addresses,
+ List tips,
int threshold) throws Exception {
if (threshold <= 0 || threshold > 100) {
@@ -1359,24 +1358,24 @@ private AbstractResponse getBalancesStatement(List addresses,
final List addressList = addresses.stream()
.map(address -> (HashFactory.ADDRESS.create(address)))
.collect(Collectors.toCollection(LinkedList::new));
-
+
final List hashes;
final Map balances = new HashMap<>();
- instance.milestoneTracker.latestSnapshot.rwlock.readLock().lock();
- final int index = instance.milestoneTracker.latestSnapshot.index();
-
+ instance.snapshotProvider.getLatestSnapshot().lockRead();
+ final int index = instance.snapshotProvider.getLatestSnapshot().getIndex();
+
if (tips == null || tips.size() == 0) {
- hashes = Collections.singletonList(instance.milestoneTracker.latestSolidSubtangleMilestone);
+ hashes = Collections.singletonList(instance.snapshotProvider.getLatestSnapshot().getHash());
} else {
hashes = tips.stream()
.map(tip -> (HashFactory.TRANSACTION.create(tip)))
.collect(Collectors.toCollection(LinkedList::new));
}
-
+
try {
// Get the balance for each address at the last snapshot
for (final Hash address : addressList) {
- Long value = instance.milestoneTracker.latestSnapshot.getBalance(address);
+ Long value = instance.snapshotProvider.getLatestSnapshot().getBalance(address);
if (value == null) {
value = 0L;
}
@@ -1392,15 +1391,15 @@ private AbstractResponse getBalancesStatement(List addresses,
if (!TransactionViewModel.exists(instance.tangle, tip)) {
return ErrorResponse.create("Tip not found: " + tip.toString());
}
- if (!instance.ledgerValidator.updateDiff(visitedHashes, diff, tip)) {
+ if (!instance.ledgerService.isBalanceDiffConsistent(visitedHashes, diff, tip)) {
return ErrorResponse.create("Tips are not consistent");
}
}
-
+
// Update the found balance according to 'diffs' balance changes
diff.forEach((key, value) -> balances.computeIfPresent(key, (hash, aLong) -> value + aLong));
} finally {
- instance.milestoneTracker.latestSnapshot.rwlock.readLock().unlock();
+ instance.snapshotProvider.getLatestSnapshot().unlockRead();
}
final List elements = addressList.stream()
@@ -1413,18 +1412,18 @@ private AbstractResponse getBalancesStatement(List addresses,
}
private static int counter_PoW = 0;
-
+
/**
* Can be 0 or more, and is set to 0 every 100 requests.
* Each increase indicates another 2 tips sent.
- *
- * @return The current amount of times this node has done proof of work.
+ *
+ * @return The current amount of times this node has done proof of work.
* Doesn't distinguish between remote and local proof of work.
*/
public static int getCounterPoW() {
return counter_PoW;
}
-
+
/**
* Increases the amount of times this node has done proof of work by one.
*/
@@ -1433,20 +1432,20 @@ public static void incCounterPoW() {
}
private static long ellapsedTime_PoW = 0L;
-
+
/**
* Can be 0 or more, and is set to 0 every 100 requests.
- *
+ *
* @return The current amount of time spent on doing proof of work in milliseconds.
- * Doesn't distinguish between remote and local proof of work.
+ * Doesn't distinguish between remote and local proof of work.
*/
public static long getEllapsedTimePoW() {
return ellapsedTime_PoW;
}
-
+
/**
* Increases the current amount of time spent on doing proof of work.
- *
+ *
* @param ellapsedTime the time to add, in milliseconds.
*/
public static void incEllapsedTimePoW(long ellapsedTime) {
@@ -1457,11 +1456,11 @@ public static void incEllapsedTimePoW(long ellapsedTime) {
*
* Prepares the specified transactions (trytes) for attachment to the Tangle by doing Proof of Work.
* You need to supply branchTransaction as well as trunkTransaction.
- * These are the tips which you're going to validate and reference with this transaction.
+ * These are the tips which you're going to validate and reference with this transaction.
* These are obtainable by the getTransactionsToApprove API call.
*
*
- * The returned value is a different set of tryte values which you can input into
+ * The returned value is a different set of tryte values which you can input into
* broadcastTransactions and storeTransactions.
* The last 243 trytes of the return value consist of the following:
*
@@ -1474,12 +1473,12 @@ public static void incEllapsedTimePoW(long ellapsedTime) {
* @param trunkTransaction A reference to an external transaction (tip) used as trunk.
* The transaction with index 0 will have this tip in its trunk.
* All other transactions reference the previous transaction in the bundle (Their index-1).
- *
+ *
* @param branchTransaction A reference to an external transaction (tip) used as branch.
* Each Transaction in the bundle will have this tip as their branch, except the last.
* The last one will have the branch in its trunk.
- * @param minWeightMagnitude The amount of work we should do to confirm this transaction.
- * Each 0-trit on the end of the transaction represents 1 magnitude.
+ * @param minWeightMagnitude The amount of work we should do to confirm this transaction.
+ * Each 0-trit on the end of the transaction represents 1 magnitude.
* A 9-tryte represents 3 magnitudes, since a 9 is represented by 3 0-trits.
* Transactions with a different minWeightMagnitude are compatible.
* @param trytes the list of trytes to prepare for network attachment, by doing proof of work.
@@ -1487,7 +1486,7 @@ public static void incEllapsedTimePoW(long ellapsedTime) {
**/
public synchronized List attachToTangleStatement(Hash trunkTransaction, Hash branchTransaction,
int minWeightMagnitude, List trytes) {
-
+
final List transactionViewModels = new LinkedList<>();
Hash prevTransaction = null;
@@ -1510,10 +1509,10 @@ public synchronized List attachToTangleStatement(Hash trunkTransaction,
//attachment fields: tag and timestamps
//tag - copy the obsolete tag to the attachment tag field only if tag isn't set.
- if(IntStream.range(TransactionViewModel.TAG_TRINARY_OFFSET,
+ if(IntStream.range(TransactionViewModel.TAG_TRINARY_OFFSET,
TransactionViewModel.TAG_TRINARY_OFFSET + TransactionViewModel.TAG_TRINARY_SIZE)
.allMatch(idx -> transactionTrits[idx] == ((byte) 0))) {
-
+
System.arraycopy(transactionTrits, TransactionViewModel.OBSOLETE_TAG_TRINARY_OFFSET,
transactionTrits, TransactionViewModel.TAG_TRINARY_OFFSET,
TransactionViewModel.TAG_TRINARY_SIZE);
@@ -1543,8 +1542,8 @@ public synchronized List attachToTangleStatement(Hash trunkTransaction,
API.incEllapsedTimePoW(System.nanoTime() - startTime);
API.incCounterPoW();
if ( ( API.getCounterPoW() % 100) == 0 ) {
- String sb = "Last 100 PoW consumed "
- + API.getEllapsedTimePoW() / 1000000000L
+ String sb = "Last 100 PoW consumed "
+ + API.getEllapsedTimePoW() / 1000000000L
+ " seconds processing time.";
log.info(sb);
counter_PoW = 0;
@@ -1559,10 +1558,10 @@ public synchronized List attachToTangleStatement(Hash trunkTransaction,
}
return elements;
}
-
+
/**
- * Transforms an object parameter into an int.
- *
+ * Transforms an object parameter into an int.
+ *
* @param request A map of all request parameters
* @param paramName The parameter we want to get as an int.
* @return The integer value of this parameter
@@ -1581,12 +1580,12 @@ private int getParameterAsInt(Map request, String paramName) thr
/**
* Transforms an object parameter into a String.
- *
+ *
* @param request A map of all request parameters
* @param paramName The parameter we want to get as a String.
* @param size The expected length of this String
* @return The String value of this parameter
- * @throws ValidationException If the requested parameter does not exist or
+ * @throws ValidationException If the requested parameter does not exist or
* the string is not exactly trytes of size length
*/
private String getParameterAsStringAndValidate(Map request, String paramName, int size) throws ValidationException {
@@ -1599,7 +1598,7 @@ private String getParameterAsStringAndValidate(Map request, Stri
/**
* Checks if a string is non 0 length, and contains exactly size amount of trytes.
* Trytes are Strings containing only A-Z and the number 9.
- *
+ *
* @param paramName The name of the parameter this String came from.
* @param size The amount of trytes it should contain.
* @param result The String we validate.
@@ -1624,15 +1623,15 @@ private void validateParamExists(Map request, String paramName)
}
/**
- * Translates the parameter into a {@link List}.
- * We then validate if the amount of elements does not exceed the maximum allowed.
+ * Translates the parameter into a {@link List}.
+ * We then validate if the amount of elements does not exceed the maximum allowed.
* Afterwards we verify if each element is valid according to {@link #validateTrytes(String, int, String)}.
- *
+ *
* @param request All request parameters
* @param paramName The name of the parameter we want to turn into a list of Strings
* @param size the length each String must have
* @return the list of valid Tryte Strings.
- * @throws ValidationException If the requested parameter does not exist or
+ * @throws ValidationException If the requested parameter does not exist or
* the string is not exactly trytes of size length or
* the amount of Strings in the list exceeds {@link APIConfig#getMaxRequestsList}
*/
@@ -1657,7 +1656,7 @@ private List getParameterAsList(Map request, String para
/**
* Checks if a string is of a certain length, and contains exactly size amount of trytes.
* Trytes are Strings containing only A-Z and the number 9.
- *
+ *
* @param trytes The String we validate.
* @param length The amount of trytes it should contain.
* @param zeroAllowed If set to '{@value #ZERO_LENGTH_ALLOWED}', an empty string is also valid.
@@ -1677,7 +1676,7 @@ private boolean validTrytes(String trytes, int length, char zeroAllowed) {
/**
* Updates the {@link HttpServerExchange} {@link HeaderMap} with the proper response settings.
- * @param exchange Contains information about what the client has send to us
+ * @param exchange Contains information about what the client has send to us
*/
private static void setupResponseHeaders(HttpServerExchange exchange) {
final HeaderMap headerMap = exchange.getResponseHeaders();
@@ -1687,10 +1686,10 @@ private static void setupResponseHeaders(HttpServerExchange exchange) {
/**
* Sets up the {@link HttpHandler} to have correct security settings.
- * Remote authentication is blocked for anyone except
+ * Remote authentication is blocked for anyone except
* those defined in {@link APIConfig#getRemoteAuth()} or localhost.
* This is done with {@link BasicAuthenticationMechanism} in a {@link AuthenticationMode#PRO_ACTIVE} mode.
- *
+ *
* @param toWrap the path handler used in creating the server.
* @return The updated handler
*/
@@ -1707,9 +1706,9 @@ private HttpHandler addSecurity(HttpHandler toWrap) {
HttpHandler handler = toWrap;
handler = new AuthenticationCallHandler(handler);
handler = new AuthenticationConstraintHandler(handler);
- final List mechanisms =
+ final List mechanisms =
Collections.singletonList(new BasicAuthenticationMechanism("Iota Realm"));
-
+
handler = new AuthenticationMechanismsHandler(handler, mechanisms);
handler = new SecurityInitialHandler(AuthenticationMode.PRO_ACTIVE, identityManager, handler);
return handler;
@@ -1742,7 +1741,7 @@ private synchronized AbstractResponse storeMessageStatement(String address, Stri
final byte[] timestampTrits = new byte[TransactionViewModel.TIMESTAMP_TRINARY_SIZE];
Converter.copyTrits(System.currentTimeMillis(), timestampTrits, 0, timestampTrits.length);
final String timestampTrytes = StringUtils.rightPad(
- Converter.trytes(timestampTrits),
+ Converter.trytes(timestampTrits),
timestampTrits.length / 3, '9');
final byte[] lastIndexTrits = new byte[TransactionViewModel.LAST_INDEX_TRINARY_SIZE];
@@ -1801,4 +1800,4 @@ private synchronized AbstractResponse storeMessageStatement(String address, Stri
broadcastTransactionsStatement(powResult);
return AbstractResponse.createEmptyResponse();
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/iota/iri/service/ledger/impl/LedgerServiceImpl.java b/src/main/java/com/iota/iri/service/ledger/impl/LedgerServiceImpl.java
index 8b42447ef2..b3899ff5b2 100644
--- a/src/main/java/com/iota/iri/service/ledger/impl/LedgerServiceImpl.java
+++ b/src/main/java/com/iota/iri/service/ledger/impl/LedgerServiceImpl.java
@@ -17,8 +17,7 @@
import java.util.*;
/**
- * Represents the service that contains all the relevant business logic for modifying and calculating the ledger
- * state.
+ * Creates a service instance that allows us to perform ledger state specific operations.
*
* This class is stateless and does not hold any domain specific models.
*/
@@ -26,40 +25,50 @@ public class LedgerServiceImpl implements LedgerService {
/**
* Holds the tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* Holds the snapshot provider which gives us access to the relevant snapshots.
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Holds a reference to the service instance containing the business logic of the snapshot package.
*/
- private final SnapshotService snapshotService;
+ private SnapshotService snapshotService;
/**
* Holds a reference to the service instance containing the business logic of the milestone package.
*/
- private final MilestoneService milestoneService;
+ private MilestoneService milestoneService;
/**
- * Creates a service instance that allows us to perform ledger state specific operations.
+ * Initializes the instance and registers its dependencies.
*
- * It simply stores the passed in dependencies in the internal properties.
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code LedgerService ledgerService = new LedgerServiceImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider snapshot provider which gives us access to the relevant snapshots
- * @param snapshotService service instance of the snapshot package that allows us to rollback ledger states
+ * @param snapshotService service instance of the snapshot package that gives us access to packages' business logic
* @param milestoneService contains the important business logic when dealing with milestones
+ * @return the initialized instance itself to allow chaining
*/
- public LedgerServiceImpl(Tangle tangle, SnapshotProvider snapshotProvider, SnapshotService snapshotService,
+ public LedgerServiceImpl init(Tangle tangle, SnapshotProvider snapshotProvider, SnapshotService snapshotService,
MilestoneService milestoneService) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
this.snapshotService = snapshotService;
this.milestoneService = milestoneService;
+
+ return this;
}
@Override
diff --git a/src/main/java/com/iota/iri/service/milestone/impl/LatestMilestoneTrackerImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/LatestMilestoneTrackerImpl.java
index 605e81ed10..1eef78c02f 100644
--- a/src/main/java/com/iota/iri/service/milestone/impl/LatestMilestoneTrackerImpl.java
+++ b/src/main/java/com/iota/iri/service/milestone/impl/LatestMilestoneTrackerImpl.java
@@ -31,11 +31,12 @@
import static com.iota.iri.service.milestone.MilestoneValidity.VALID;
/**
- * This class implements the basic contract of the {@link LatestMilestoneTracker} that keeps track of the latest
- * milestone by incorporating a background worker that periodically checks if new milestones have arrived.
+ * Creates a tracker that automatically detects new milestones by incorporating a background worker that periodically
+ * checks all transactions that are originating from the coordinator address and that exposes the found latest milestone
+ * via getters.
*
- * Knowing about the latest milestone and being able to compare it to the latest solid milestone allows us to determine
- * if our node is "in sync".
+ * It can be used to determine the sync-status of the node by comparing these values against the latest solid
+ * milestone.
*/
public class LatestMilestoneTrackerImpl implements LatestMilestoneTracker {
/**
@@ -56,39 +57,39 @@ public class LatestMilestoneTrackerImpl implements LatestMilestoneTracker {
/**
* Holds the Tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* The snapshot provider which gives us access to the relevant snapshots that the node uses (for faster
* bootstrapping).
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Service class containing the business logic of the milestone package.
*/
- private final MilestoneService milestoneService;
+ private MilestoneService milestoneService;
/**
* Holds a reference to the manager that takes care of solidifying milestones.
*/
- private final MilestoneSolidifier milestoneSolidifier;
+ private MilestoneSolidifier milestoneSolidifier;
/**
* Holds a reference to the ZeroMQ interface that allows us to emit messages for external recipients.
*/
- private final MessageQ messageQ;
+ private MessageQ messageQ;
/**
- * Holds a reference to the manager of the background worker.
+ * Holds the coordinator address which is used to filter possible milestone candidates.
*/
- private final SilentScheduledExecutorService executorService = new DedicatedScheduledExecutorService(
- "Latest Milestone Tracker", log.delegate());
+ private Hash coordinatorAddress;
/**
- * Holds the coordinator address which is used to filter possible milestone candidates.
+ * Holds a reference to the manager of the background worker.
*/
- private final Hash coordinatorAddress;
+ private final SilentScheduledExecutorService executorService = new DedicatedScheduledExecutorService(
+ "Latest Milestone Tracker", log.delegate());
/**
* Holds the milestone index of the latest milestone that we have seen / processed.
@@ -123,13 +124,17 @@ public class LatestMilestoneTrackerImpl implements LatestMilestoneTracker {
private boolean initialized = false;
/**
- * Creates a tracker that automatically detects new milestones by incorporating a background worker that
- * periodically checks all transactions that are originating from the coordinator address and that exposes the found
- * latest milestone via getters.
+ * This method initializes the instance and registers its dependencies.
*
- * It can be used to determine the sync-status of the node by comparing these values against the latest solid
- * milestone. It simply stores the passed in parameters in their corresponding properties and bootstraps the
- * tracker with values for the latest milestone that can be found quickly.
+ * It simply stores the passed in values in their corresponding private properties and bootstraps the latest
+ * milestone with values for the latest milestone that can be found quickly.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code LatestMilestoneTracker latestMilestoneTracker = new LatestMilestoneTrackerImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider manager for the snapshots that allows us to retrieve the relevant snapshots of this node
@@ -137,8 +142,9 @@ public class LatestMilestoneTrackerImpl implements LatestMilestoneTracker {
* @param milestoneSolidifier manager that takes care of solidifying milestones
* @param messageQ ZeroMQ interface that allows us to emit messages for external recipients
* @param config configuration object which allows us to determine the important config parameters of the node
+ * @return the initialized instance itself to allow chaining
*/
- public LatestMilestoneTrackerImpl(Tangle tangle, SnapshotProvider snapshotProvider,
+ public LatestMilestoneTrackerImpl init(Tangle tangle, SnapshotProvider snapshotProvider,
MilestoneService milestoneService, MilestoneSolidifier milestoneSolidifier, MessageQ messageQ,
IotaConfig config) {
@@ -151,6 +157,8 @@ public LatestMilestoneTrackerImpl(Tangle tangle, SnapshotProvider snapshotProvid
coordinatorAddress = HashFactory.ADDRESS.create(config.getCoordinator());
bootstrapLatestMilestoneValue();
+
+ return this;
}
/**
diff --git a/src/main/java/com/iota/iri/service/milestone/impl/LatestSolidMilestoneTrackerImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/LatestSolidMilestoneTrackerImpl.java
index 651602da2b..346dcf71bc 100644
--- a/src/main/java/com/iota/iri/service/milestone/impl/LatestSolidMilestoneTrackerImpl.java
+++ b/src/main/java/com/iota/iri/service/milestone/impl/LatestSolidMilestoneTrackerImpl.java
@@ -37,28 +37,28 @@ public class LatestSolidMilestoneTrackerImpl implements LatestSolidMilestoneTrac
/**
* Holds the Tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* The snapshot provider which gives us access to the relevant snapshots that the node uses (for the ledger
* state).
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Holds a reference to the manager that keeps track of the latest milestone.
*/
- private final LatestMilestoneTracker latestMilestoneTracker;
+ private LatestMilestoneTracker latestMilestoneTracker;
/**
* Holds a reference to the service that contains the logic for applying milestones to the ledger state.
*/
- private final LedgerService ledgerService;
+ private LedgerService ledgerService;
/**
* Holds a reference to the ZeroMQ interface that allows us to emit messages for external recipients.
*/
- private final MessageQ messageQ;
+ private MessageQ messageQ;
/**
* Holds a reference to the manager of the background worker.
@@ -67,19 +67,25 @@ public class LatestSolidMilestoneTrackerImpl implements LatestSolidMilestoneTrac
"Latest Solid Milestone Tracker", log.delegate());
/**
- * Creates a manager that keeps track of the latest solid milestones and that triggers the application of these
- * milestones and their corresponding balance changes to the latest {@link Snapshot} by incorporating a background
- * worker that periodically checks for new solid milestones.
+ * This method initializes the instance and registers its dependencies.
*
- * We simply store the passed in dependencies in their corresponding properties.
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code latestSolidMilestoneTracker = new LatestSolidMilestoneTrackerImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider manager for the snapshots that allows us to retrieve the relevant snapshots of this node
- * @param latestMilestoneTracker the manager that keeps track of the late st milestone
* @param ledgerService the manager for
+ * @param latestMilestoneTracker the manager that keeps track of the latest milestone
* @param messageQ ZeroMQ interface that allows us to emit messages for external recipients
+ * @return the initialized instance itself to allow chaining
*/
- public LatestSolidMilestoneTrackerImpl(Tangle tangle, SnapshotProvider snapshotProvider,
+ public LatestSolidMilestoneTrackerImpl init(Tangle tangle, SnapshotProvider snapshotProvider,
LedgerService ledgerService, LatestMilestoneTracker latestMilestoneTracker, MessageQ messageQ) {
this.tangle = tangle;
@@ -87,6 +93,8 @@ public LatestSolidMilestoneTrackerImpl(Tangle tangle, SnapshotProvider snapshotP
this.ledgerService = ledgerService;
this.latestMilestoneTracker = latestMilestoneTracker;
this.messageQ = messageQ;
+
+ return this;
}
@Override
diff --git a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneServiceImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneServiceImpl.java
index e08dc30bd7..9f236ac1b1 100644
--- a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneServiceImpl.java
+++ b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneServiceImpl.java
@@ -29,7 +29,7 @@
import static com.iota.iri.service.milestone.MilestoneValidity.VALID;
/**
- * Represents the service that contains all the relevant business logic for interacting with milestones.
+ * Creates a service instance that allows us to perform milestone specific operations.
*
* This class is stateless and does not hold any domain specific models.
*/
@@ -37,40 +37,50 @@ public class MilestoneServiceImpl implements MilestoneService {
/**
* Holds the tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* Holds the snapshot provider which gives us access to the relevant snapshots.
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Holds the ZeroMQ interface that allows us to emit messages for external recipients.
*/
- private final MessageQ messageQ;
+ private MessageQ messageQ;
/**
* Holds the config with important milestone specific settings.
*/
- private final ConsensusConfig config;
+ private ConsensusConfig config;
/**
- * Creates a service instance that allows us to interact with the milestones.
+ * This method initializes the instance and registers its dependencies.
*
- * It simply stores the passed in dependencies in the internal properties.
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code milestoneService = new MilestoneServiceImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider snapshot provider which gives us access to the relevant snapshots
* @param messageQ ZeroMQ interface that allows us to emit messages for external recipients
* @param config config with important milestone specific settings
+ * @return the initialized instance itself to allow chaining
*/
- public MilestoneServiceImpl(Tangle tangle, SnapshotProvider snapshotProvider, MessageQ messageQ,
+ public MilestoneServiceImpl init(Tangle tangle, SnapshotProvider snapshotProvider, MessageQ messageQ,
ConsensusConfig config) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
this.messageQ = messageQ;
this.config = config;
+
+ return this;
}
//region {PUBLIC METHODS] //////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java
index fef5b28fc8..377ae6b0d9 100644
--- a/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java
+++ b/src/main/java/com/iota/iri/service/milestone/impl/MilestoneSolidifierImpl.java
@@ -3,7 +3,7 @@
import com.iota.iri.TransactionValidator;
import com.iota.iri.model.Hash;
import com.iota.iri.service.milestone.MilestoneSolidifier;
-import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.utils.log.interval.IntervalLogger;
import com.iota.iri.utils.thread.DedicatedScheduledExecutorService;
import com.iota.iri.utils.thread.SilentScheduledExecutorService;
@@ -48,14 +48,14 @@ public class MilestoneSolidifierImpl implements MilestoneSolidifier {
private static final IntervalLogger log = new IntervalLogger(MilestoneSolidifier.class);
/**
- * Holds a reference to the initial Snapshot which allows us to check if milestones are still relevant.
+ * Holds the snapshot provider which gives us access to the relevant snapshots.
*/
- private final Snapshot initialSnapshot;
+ private SnapshotProvider snapshotProvider;
/**
* Holds a reference to the TransactionValidator which allows us to issue solidity checks.
*/
- private final TransactionValidator transactionValidator;
+ private TransactionValidator transactionValidator;
/**
* Holds a reference to the manager of the background worker.
@@ -91,16 +91,26 @@ public class MilestoneSolidifierImpl implements MilestoneSolidifier {
private Map.Entry youngestMilestoneInQueue = null;
/**
- * Constructor of the class.
+ * This method initializes the instance and registers its dependencies.
*
- * It simply stores the passed in parameters to be able to access them later on.
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code milestoneSolidifier = new MilestoneSolidifierImpl().init(...);}
*
- * @param initialSnapshot initial Snapshot instance that is used by the node
+ * @param snapshotProvider snapshot provider which gives us access to the relevant snapshots
* @param transactionValidator TransactionValidator instance that is used by the node
+ * @return the initialized instance itself to allow chaining
*/
- public MilestoneSolidifierImpl(Snapshot initialSnapshot, TransactionValidator transactionValidator) {
- this.initialSnapshot = initialSnapshot;
+ public MilestoneSolidifierImpl init(SnapshotProvider snapshotProvider, TransactionValidator transactionValidator) {
+ this.snapshotProvider = snapshotProvider;
this.transactionValidator = transactionValidator;
+
+ return this;
}
/**
@@ -113,7 +123,7 @@ public MilestoneSolidifierImpl(Snapshot initialSnapshot, TransactionValidator tr
@Override
public void add(Hash milestoneHash, int milestoneIndex) {
if (!unsolidMilestonesPool.containsKey(milestoneHash) && !newlyAddedMilestones.containsKey(milestoneHash) &&
- milestoneIndex > initialSnapshot.getIndex()) {
+ milestoneIndex > snapshotProvider.getInitialSnapshot().getIndex()) {
newlyAddedMilestones.put(milestoneHash, milestoneIndex);
}
@@ -212,7 +222,7 @@ private void processSolidificationQueue() {
Map.Entry currentEntry = iterator.next();
- if (currentEntry.getValue() <= initialSnapshot.getIndex() || isSolid(currentEntry)) {
+ if (currentEntry.getValue() <= snapshotProvider.getInitialSnapshot().getIndex() || isSolid(currentEntry)) {
unsolidMilestonesPool.remove(currentEntry.getKey());
iterator.remove();
diff --git a/src/main/java/com/iota/iri/service/milestone/impl/SeenMilestonesRetrieverImpl.java b/src/main/java/com/iota/iri/service/milestone/impl/SeenMilestonesRetrieverImpl.java
index 676bf7dc50..b48b26e5ac 100644
--- a/src/main/java/com/iota/iri/service/milestone/impl/SeenMilestonesRetrieverImpl.java
+++ b/src/main/java/com/iota/iri/service/milestone/impl/SeenMilestonesRetrieverImpl.java
@@ -15,11 +15,13 @@
import java.util.concurrent.TimeUnit;
/**
- * This class implements the basic contract of the {@link SeenMilestonesRetriever} by providing a manager that requests
- * milestones that are "in range" for "immediate solidification".
+ * Creates a manager that proactively requests the missing "seen milestones" (defined in the local snapshot file).
*
- * This means the manager does not request all missing milestones at once, but focuses on the milestones that are
- * directly following our latest solid milestone which will allow us to sync
+ * It simply stores the passed in dependencies in their corresponding properties and then makes a copy of the {@code
+ * seenMilestones} of the initial snapshot which will consequently be requested.
+ *
+ * Once the manager finishes to request all "seen milestones" it will automatically {@link #shutdown()} (when being
+ * {@link #start()}ed before).
*/
public class SeenMilestonesRetrieverImpl implements SeenMilestonesRetriever {
/**
@@ -41,18 +43,18 @@ public class SeenMilestonesRetrieverImpl implements SeenMilestonesRetriever {
/**
* Tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* The snapshot provider which gives us access to the relevant snapshots to calculate our range.
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Holds a reference to the {@link TransactionRequester} that allows us to issue requests for the missing
* milestones.
*/
- private final TransactionRequester transactionRequester;
+ private TransactionRequester transactionRequester;
/**
* Holds a reference to the manager of the background worker.
@@ -63,28 +65,36 @@ public class SeenMilestonesRetrieverImpl implements SeenMilestonesRetriever {
/**
* The list of seen milestones that need to be requested.
*/
- private final Map seenMilestones;
+ private Map seenMilestones;
/**
- * Creates a manager that proactively requests the missing "seen milestones" (defined in the local snapshot
- * file).
+ * This method initializes the instance and registers its dependencies.
*
- * It simply stores the passed in dependencies in their corresponding properties and then makes a copy of the
- * {@code seenMilestones} of the initial snapshot which will consequently be requested.
+ * It simply stores the passed in values in their corresponding private properties and creates a working copy of the
+ * seen milestones (which will get processed by the background worker).
*
- * Once the manager finishes to request all "seen milestones" it will automatically {@link #shutdown()} (when being
- * {@link #start()}ed before).
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code seenMilestonesRetriever = new SeenMilestonesRetrieverImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider snapshot provider which gives us access to the relevant snapshots to calculate our range
* @param transactionRequester allows us to issue requests for the missing milestones
+ * @return the initialized instance itself to allow chaining
*/
- public SeenMilestonesRetrieverImpl(Tangle tangle, SnapshotProvider snapshotProvider, TransactionRequester transactionRequester) {
+ public SeenMilestonesRetrieverImpl init(Tangle tangle, SnapshotProvider snapshotProvider,
+ TransactionRequester transactionRequester) {
+
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
this.transactionRequester = transactionRequester;
seenMilestones = new ConcurrentHashMap<>(snapshotProvider.getInitialSnapshot().getSeenMilestones());
+
+ return this;
}
/**
diff --git a/src/main/java/com/iota/iri/service/snapshot/impl/LocalSnapshotManagerImpl.java b/src/main/java/com/iota/iri/service/snapshot/impl/LocalSnapshotManagerImpl.java
index 36e423038b..b90ec2981a 100644
--- a/src/main/java/com/iota/iri/service/snapshot/impl/LocalSnapshotManagerImpl.java
+++ b/src/main/java/com/iota/iri/service/snapshot/impl/LocalSnapshotManagerImpl.java
@@ -7,7 +7,6 @@
import com.iota.iri.service.snapshot.SnapshotException;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.transactionpruning.TransactionPruner;
-import com.iota.iri.storage.Tangle;
import com.iota.iri.utils.thread.ThreadIdentifier;
import com.iota.iri.utils.thread.ThreadUtils;
@@ -15,7 +14,11 @@
import org.slf4j.LoggerFactory;
/**
- * Implements the basic contract of the {@link LocalSnapshotManager}.
+ * Creates a manager for the local snapshots, that takes care of automatically creating local snapshots when the defined
+ * intervals have passed.
+ *
+ * It incorporates a background worker that periodically checks if a new snapshot is due (see {@link
+ * #start(LatestMilestoneTracker)} and {@link #shutdown()}).
*/
public class LocalSnapshotManagerImpl implements LocalSnapshotManager {
/**
@@ -32,27 +35,22 @@ public class LocalSnapshotManagerImpl implements LocalSnapshotManager {
/**
* Data provider for the relevant {@link com.iota.iri.service.snapshot.Snapshot} instances.
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Service that contains the logic for generating local {@link com.iota.iri.service.snapshot.Snapshot}s.
*/
- private final SnapshotService snapshotService;
+ private SnapshotService snapshotService;
/**
* Manager for the pruning jobs that allows us to clean up old transactions.
*/
- private final TransactionPruner transactionPruner;
-
- /**
- * Tangle object which acts as a database interface.
- */
- private final Tangle tangle;
+ private TransactionPruner transactionPruner;
/**
* Configuration with important snapshot related parameters.
*/
- private final SnapshotConfig config;
+ private SnapshotConfig config;
/**
* Holds a reference to the {@link ThreadIdentifier} for the monitor thread.
@@ -63,24 +61,32 @@ public class LocalSnapshotManagerImpl implements LocalSnapshotManager {
private ThreadIdentifier monitorThreadIdentifier = new ThreadIdentifier("Local Snapshots Monitor");
/**
- * Creates the {@link LocalSnapshotManager} that takes care of automatically creating local snapshots when the
- * defined intervals have passed.
+ * This method initializes the instance and registers its dependencies.
+ *
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code localSnapshotManager = new LocalSnapshotManagerImpl().init(...);}
*
- * It simply stores the passed in parameters in their private properties.
- *
- * @param snapshotProvider data provider for the relevant {@link com.iota.iri.service.snapshot.Snapshot} instances
+ * @param snapshotProvider data provider for the snapshots that are relevant for the node
+ * @param snapshotService service instance of the snapshot package that gives us access to packages' business logic
* @param transactionPruner manager for the pruning jobs that allows us to clean up old transactions
- * @param tangle object which acts as a database interface
- * @param config configuration with important snapshot related parameters
+ * @param config important snapshot related configuration parameters
+ * @return the initialized instance itself to allow chaining
*/
- public LocalSnapshotManagerImpl(SnapshotProvider snapshotProvider, SnapshotService snapshotService,
- TransactionPruner transactionPruner, Tangle tangle, SnapshotConfig config) {
+ public LocalSnapshotManagerImpl init(SnapshotProvider snapshotProvider, SnapshotService snapshotService,
+ TransactionPruner transactionPruner, SnapshotConfig config) {
this.snapshotProvider = snapshotProvider;
this.snapshotService = snapshotService;
this.transactionPruner = transactionPruner;
- this.tangle = tangle;
this.config = config;
+
+ return this;
}
/**
diff --git a/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotProviderImpl.java b/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotProviderImpl.java
index d150763e8d..d2e5113993 100644
--- a/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotProviderImpl.java
+++ b/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotProviderImpl.java
@@ -20,7 +20,18 @@
import java.util.stream.Stream;
/**
- * Implements the basic contract of the {@link SnapshotProvider} interface.
+ * Creates a data provider for the two {@link Snapshot} instances that are relevant for the node.
+ *
+ * It provides access to the two relevant {@link Snapshot} instances:
+ *
+ * -
+ * the {@link #initialSnapshot} (the starting point of the ledger based on the last global or local Snapshot)
+ *
+ * -
+ * the {@link #latestSnapshot} (the state of the ledger after applying all changes up till the latest confirmed
+ * milestone)
+ *
+ *
*/
public class SnapshotProviderImpl implements SnapshotProvider {
/**
@@ -56,7 +67,7 @@ public class SnapshotProviderImpl implements SnapshotProvider {
/**
* Holds Snapshot related configuration parameters.
*/
- private final SnapshotConfig config;
+ private SnapshotConfig config;
/**
* Internal property for the value returned by {@link SnapshotProvider#getInitialSnapshot()}.
@@ -69,21 +80,28 @@ public class SnapshotProviderImpl implements SnapshotProvider {
private Snapshot latestSnapshot;
/**
- * Creates a data provider for the two {@link Snapshot} instances that are relevant for the node.
- *
- * It provides access to the two relevant {@link Snapshot} instances:
- *
- * - the initial {@link Snapshot} (the starting point of the ledger based on the last global or local Snapshot)
- * - the latest {@link Snapshot} (the state of the ledger after applying all changes up till the latest
- * confirmed milestone)
+ * This method initializes the instance and registers its dependencies.
+ *
+ * It simply stores the passed in values in their corresponding private properties and loads the snapshots.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code snapshotProvider = new SnapshotProviderImpl().init(...);}
*
* @param config Snapshot related configuration parameters
* @throws SnapshotException if anything goes wrong while trying to read the snapshots
+ * @return the initialized instance itself to allow chaining
+ *
*/
- public SnapshotProviderImpl(SnapshotConfig config) throws SnapshotException {
+ public SnapshotProviderImpl init(SnapshotConfig config) throws SnapshotException {
this.config = config;
loadSnapshots();
+
+ return this;
}
/**
diff --git a/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotServiceImpl.java b/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotServiceImpl.java
index 5a9ec7e5aa..c548da4417 100644
--- a/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotServiceImpl.java
+++ b/src/main/java/com/iota/iri/service/snapshot/impl/SnapshotServiceImpl.java
@@ -32,7 +32,9 @@
import java.util.stream.Collectors;
/**
- * Implements the basic contract of the {@link SnapshotService}.
+ * Creates a service instance that allows us to access the business logic for {@link Snapshot}s.
+ *
+ * The service instance is stateless and can be shared by multiple other consumers.
*/
public class SnapshotServiceImpl implements SnapshotService {
/**
@@ -57,31 +59,41 @@ public class SnapshotServiceImpl implements SnapshotService {
/**
* Holds the tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
* Holds the snapshot provider which gives us access to the relevant snapshots.
*/
- private final SnapshotProvider snapshotProvider;
+ private SnapshotProvider snapshotProvider;
/**
* Holds the config with important snapshot specific settings.
*/
- private final SnapshotConfig config;
+ private SnapshotConfig config;
/**
- * Creates a service instance that allows us to interact with the snapshots.
+ * This method initializes the instance and registers its dependencies.
*
- * It simply stores the passed in dependencies in the internal properties.
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code snapshotService = new SnapshotServiceImpl().init(...);}
*
* @param tangle Tangle object which acts as a database interface
- * @param snapshotProvider data provider for the {@link Snapshot}s that are relevant for the node
+ * @param snapshotProvider data provider for the snapshots that are relevant for the node
* @param config important snapshot related configuration parameters
+ * @return the initialized instance itself to allow chaining
*/
- public SnapshotServiceImpl(Tangle tangle, SnapshotProvider snapshotProvider, SnapshotConfig config) {
+ public SnapshotServiceImpl init(Tangle tangle, SnapshotProvider snapshotProvider, SnapshotConfig config) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
this.config = config;
+
+ return this;
}
/**
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculator.java b/src/main/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculator.java
index 185ae75a28..263827f4ed 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculator.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculator.java
@@ -5,7 +5,7 @@
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashId;
import com.iota.iri.model.HashPrefix;
-import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.tipselection.RatingCalculator;
import com.iota.iri.utils.collections.impl.TransformingBoundedHashSet;
import com.iota.iri.storage.Tangle;
@@ -31,11 +31,11 @@ public class CumulativeWeightCalculator implements RatingCalculator{
public static final int MAX_FUTURE_SET_SIZE = 5000;
public final Tangle tangle;
- private final Snapshot initialSnapshot;
+ private final SnapshotProvider snapshotProvider;
- public CumulativeWeightCalculator(Tangle tangle, Snapshot initialSnapshot) {
+ public CumulativeWeightCalculator(Tangle tangle, SnapshotProvider snapshotProvider) {
this.tangle = tangle;
- this.initialSnapshot = initialSnapshot;
+ this.snapshotProvider = snapshotProvider;
}
@Override
@@ -89,7 +89,7 @@ private Collection getTxDirectApproversHashes(Hash txHash, Map(appHashes.size());
for (Hash appHash : appHashes) {
//if not genesis (the tx that confirms itself)
- if (!initialSnapshot.hasSolidEntryPoint(appHash)) {
+ if (!snapshotProvider.getInitialSnapshot().hasSolidEntryPoint(appHash)) {
txApprovers.add(appHash);
}
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
index 6ad1ec78fc..67e81ab04f 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImpl.java
@@ -1,8 +1,8 @@
package com.iota.iri.service.tipselection.impl;
-import com.iota.iri.MilestoneTracker;
import com.iota.iri.controllers.MilestoneViewModel;
import com.iota.iri.model.Hash;
+import com.iota.iri.service.milestone.LatestMilestoneTracker;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.tipselection.EntryPointSelector;
import com.iota.iri.storage.Tangle;
@@ -16,24 +16,26 @@ public class EntryPointSelectorImpl implements EntryPointSelector {
private final Tangle tangle;
private final SnapshotProvider snapshotProvider;
- private final MilestoneTracker milestoneTracker;
+ private final LatestMilestoneTracker latestMilestoneTracker;
+
+ public EntryPointSelectorImpl(Tangle tangle, SnapshotProvider snapshotProvider,
+ LatestMilestoneTracker latestMilestoneTracker) {
- public EntryPointSelectorImpl(Tangle tangle, SnapshotProvider snapshotProvider, MilestoneTracker milestoneTracker) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
- this.milestoneTracker = milestoneTracker;
+ this.latestMilestoneTracker = latestMilestoneTracker;
}
@Override
public Hash getEntryPoint(int depth) throws Exception {
- int milestoneIndex = Math.max(milestoneTracker.latestSolidSubtangleMilestoneIndex - depth - 1,
+ int milestoneIndex = Math.max(snapshotProvider.getLatestSnapshot().getIndex() - depth - 1,
snapshotProvider.getInitialSnapshot().getIndex());
MilestoneViewModel milestoneViewModel = MilestoneViewModel.findClosestNextMilestone(tangle, milestoneIndex,
- milestoneTracker.latestMilestoneIndex);
+ latestMilestoneTracker.getLatestMilestoneIndex());
if (milestoneViewModel != null && milestoneViewModel.getHash() != null) {
return milestoneViewModel.getHash();
}
- return milestoneTracker.latestSolidSubtangleMilestone;
+ return snapshotProvider.getLatestSnapshot().getHash();
}
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
index 83add177b6..8c3f844472 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java
@@ -5,6 +5,7 @@
import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashId;
+import com.iota.iri.service.ledger.LedgerService;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.tipselection.*;
import com.iota.iri.storage.Tangle;
@@ -29,19 +30,17 @@ public class TipSelectorImpl implements TipSelector {
private final RatingCalculator ratingCalculator;
private final Walker walker;
- private final LedgerValidator ledgerValidator;
+ private final LedgerService ledgerService;
private final Tangle tangle;
private final SnapshotProvider snapshotProvider;
- private final MilestoneTracker milestoneTracker;
private final TipSelConfig config;
public TipSelectorImpl(Tangle tangle,
SnapshotProvider snapshotProvider,
- LedgerValidator ledgerValidator,
+ LedgerService ledgerService,
EntryPointSelector entryPointSelector,
RatingCalculator ratingCalculator,
Walker walkerAlpha,
- MilestoneTracker milestoneTracker,
TipSelConfig config) {
this.entryPointSelector = entryPointSelector;
@@ -50,10 +49,9 @@ public TipSelectorImpl(Tangle tangle,
this.walker = walkerAlpha;
//used by walkValidator
- this.ledgerValidator = ledgerValidator;
+ this.ledgerService = ledgerService;
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
- this.milestoneTracker = milestoneTracker;
this.config = config;
}
@@ -76,7 +74,7 @@ public TipSelectorImpl(Tangle tangle,
@Override
public List getTransactionsToApprove(int depth, Optional reference) throws Exception {
try {
- milestoneTracker.latestSnapshot.rwlock.readLock().lock();
+ snapshotProvider.getLatestSnapshot().lockRead();
//preparation
Hash entryPoint = entryPointSelector.getEntryPoint(depth);
@@ -84,7 +82,7 @@ public List getTransactionsToApprove(int depth, Optional reference)
//random walk
List tips = new LinkedList<>();
- WalkValidator walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator, milestoneTracker, config);
+ WalkValidator walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService, config);
Hash tip = walker.walk(entryPoint, rating, walkValidator);
tips.add(tip);
@@ -98,13 +96,13 @@ public List getTransactionsToApprove(int depth, Optional reference)
tips.add(tip);
//validate
- if (!ledgerValidator.checkConsistency(tips)) {
+ if (!ledgerService.tipsConsistent(tips)) {
throw new IllegalStateException(TIPS_NOT_CONSISTENT);
}
return tips;
} finally {
- milestoneTracker.latestSnapshot.rwlock.readLock().unlock();
+ snapshotProvider.getLatestSnapshot().unlockRead();
}
}
diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
index 3611a1de19..e598639c49 100644
--- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
+++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java
@@ -5,6 +5,7 @@
import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
+import com.iota.iri.service.ledger.LedgerService;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.tipselection.WalkValidator;
import com.iota.iri.storage.Tangle;
@@ -30,8 +31,7 @@ public class WalkValidatorImpl implements WalkValidator {
private final Tangle tangle;
private final Logger log = LoggerFactory.getLogger(WalkValidator.class);
private final SnapshotProvider snapshotProvider;
- private final LedgerValidator ledgerValidator;
- private final MilestoneTracker milestoneTracker;
+ private final LedgerService ledgerService;
private final TipSelConfig config;
@@ -39,11 +39,10 @@ public class WalkValidatorImpl implements WalkValidator {
private Map myDiff;
private Set myApprovedHashes;
- public WalkValidatorImpl(Tangle tangle, SnapshotProvider snapshotProvider, LedgerValidator ledgerValidator, MilestoneTracker milestoneTracker, TipSelConfig config) {
+ public WalkValidatorImpl(Tangle tangle, SnapshotProvider snapshotProvider, LedgerService ledgerService, TipSelConfig config) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
- this.ledgerValidator = ledgerValidator;
- this.milestoneTracker = milestoneTracker;
+ this.ledgerService = ledgerService;
this.config = config;
maxDepthOkMemoization = new HashSet<>();
@@ -65,10 +64,10 @@ public boolean isValid(Hash transactionHash) throws Exception {
log.debug("Validation failed: {} is not solid", transactionHash);
return false;
} else if (belowMaxDepth(transactionViewModel.getHash(),
- milestoneTracker.latestSolidSubtangleMilestoneIndex - config.getMaxDepth())) {
+ snapshotProvider.getLatestSnapshot().getIndex() - config.getMaxDepth())) {
log.debug("Validation failed: {} is below max depth", transactionHash);
return false;
- } else if (!ledgerValidator.updateDiff(myApprovedHashes, myDiff, transactionViewModel.getHash())) {
+ } else if (!ledgerService.isBalanceDiffConsistent(myApprovedHashes, myDiff, transactionViewModel.getHash())) {
log.debug("Validation failed: {} is not consistent", transactionHash);
return false;
}
diff --git a/src/main/java/com/iota/iri/service/transactionpruning/async/AsyncTransactionPruner.java b/src/main/java/com/iota/iri/service/transactionpruning/async/AsyncTransactionPruner.java
index b156533f4c..812b3d0425 100644
--- a/src/main/java/com/iota/iri/service/transactionpruning/async/AsyncTransactionPruner.java
+++ b/src/main/java/com/iota/iri/service/transactionpruning/async/AsyncTransactionPruner.java
@@ -3,6 +3,7 @@
import com.iota.iri.conf.SnapshotConfig;
import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.service.snapshot.Snapshot;
+import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.transactionpruning.TransactionPruner;
import com.iota.iri.service.transactionpruning.TransactionPrunerJob;
import com.iota.iri.service.transactionpruning.TransactionPruningException;
@@ -21,11 +22,12 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * This class implements the contract of the {@link TransactionPruner} while executing the jobs asynchronously in the
- * background.
- *
- * To start the background processing of pruning tasks one has to make use of the additional {@link #start()} and
- * {@link #shutdown()} methods.
+ * Creates a {@link TransactionPruner} that is able to process it's jobs asynchronously in the background and persists
+ * its state in a file on the hard disk of the node.
+ *
+ * The asynchronous processing of the jobs is done through {@link Thread}s that are started and stopped by invoking the
+ * corresponding {@link #start()} and {@link #shutdown()} methods. Since some of the builtin jobs require a special
+ * logic for the way they are executed, we register the builtin job types here.
*/
public class AsyncTransactionPruner implements TransactionPruner {
/**
@@ -51,22 +53,22 @@ public class AsyncTransactionPruner implements TransactionPruner {
/**
* Tangle object which acts as a database interface.
*/
- private final Tangle tangle;
+ private Tangle tangle;
/**
- * Manager for the tips (required for removing pruned transactions from this manager).
+ * Data provider for the snapshots that are relevant for the node.
*/
- private final TipsViewModel tipsViewModel;
+ private SnapshotProvider snapshotProvider;
/**
- * Last local or global snapshot that acts as a starting point for the state of ledger.
+ * Manager for the tips (required for removing pruned transactions from this manager).
*/
- private final Snapshot snapshot;
+ private TipsViewModel tipsViewModel;
/**
* Configuration with important snapshot related parameters.
*/
- private final SnapshotConfig config;
+ private SnapshotConfig config;
/**
* Holds a reference to the {@link ThreadIdentifier} for the cleanup thread.
@@ -101,24 +103,29 @@ public class AsyncTransactionPruner implements TransactionPruner {
private boolean persistRequested = false;
/**
- * Creates a {@link TransactionPruner} that is able to process it's jobs asynchronously in the background and
- * persists its state in a file on the hard disk of the node.
- *
- * The asynchronous processing of the jobs is done through {@link Thread}s that are started and stopped by invoking
- * the corresponding {@link #start()} and {@link #shutdown()} methods. Since some of the builtin jobs require a
- * special logic for the way they are executed, we register the builtin job types here.
+ * This method initializes the instance and registers its dependencies.
+ *
+ * It simply stores the passed in values in their corresponding private properties.
+ *
+ * Note: Instead of handing over the dependencies in the constructor, we register them lazy. This allows us to have
+ * circular dependencies because the instantiation is separated from the dependency injection. To reduce the
+ * amount of code that is necessary to correctly instantiate this class, we return the instance itself which
+ * allows us to still instantiate, initialize and assign in one line - see Example:
+ *
+ * {@code asyncTransactionPruner = new AsyncTransactionPruner().init(...);}
*
* @param tangle Tangle object which acts as a database interface
+ * @param snapshotProvider data provider for the snapshots that are relevant for the node
* @param tipsViewModel manager for the tips (required for removing pruned transactions from this manager)
- * @param snapshot last local or global snapshot that acts as a starting point for the state of ledger
* @param config Configuration with important snapshot related configuration parameters
+ * @return the initialized instance itself to allow chaining
*/
- public AsyncTransactionPruner(Tangle tangle, TipsViewModel tipsViewModel, Snapshot snapshot,
+ public AsyncTransactionPruner init(Tangle tangle, SnapshotProvider snapshotProvider, TipsViewModel tipsViewModel,
SnapshotConfig config) {
this.tangle = tangle;
+ this.snapshotProvider = snapshotProvider;
this.tipsViewModel = tipsViewModel;
- this.snapshot = snapshot;
this.config = config;
addJobQueue(UnconfirmedSubtanglePrunerJob.class, new SimpleJobQueue(this));
@@ -126,6 +133,8 @@ public AsyncTransactionPruner(Tangle tangle, TipsViewModel tipsViewModel, Snapsh
registerParser(MilestonePrunerJob.class, MilestonePrunerJob::parse);
registerParser(UnconfirmedSubtanglePrunerJob.class, UnconfirmedSubtanglePrunerJob::parse);
+
+ return this;
}
/**
@@ -138,7 +147,7 @@ public void addJob(TransactionPrunerJob job) throws TransactionPruningException
job.setTransactionPruner(this);
job.setTangle(tangle);
job.setTipsViewModel(tipsViewModel);
- job.setSnapshot(snapshot);
+ job.setSnapshot(snapshotProvider.getInitialSnapshot());
// this call is "unchecked" to a "raw" JobQueue and it is intended since the matching JobQueue is defined by the
// registered job types
diff --git a/src/main/java/com/iota/iri/utils/thread/DedicatedScheduledExecutorService.java b/src/main/java/com/iota/iri/utils/thread/DedicatedScheduledExecutorService.java
index 33d5cef5c2..d0dd4923ab 100644
--- a/src/main/java/com/iota/iri/utils/thread/DedicatedScheduledExecutorService.java
+++ b/src/main/java/com/iota/iri/utils/thread/DedicatedScheduledExecutorService.java
@@ -235,12 +235,9 @@ public void onStartTask(TaskDetails taskDetails) {
super.onStartTask(taskDetails);
if (debug || (threadName != null && taskDetails.getExecutionCount().get() == 0)) {
- String oldThreadName = Thread.currentThread().getName();
Thread.currentThread().setName(taskDetails.getThreadName());
printStartedMessage(taskDetails);
-
- Thread.currentThread().setName(oldThreadName);
}
if (threadName != null) {
diff --git a/src/test/java/com/iota/iri/BundleValidatorTest.java b/src/test/java/com/iota/iri/BundleValidatorTest.java
index 2d5d506224..b6f2387f0e 100644
--- a/src/test/java/com/iota/iri/BundleValidatorTest.java
+++ b/src/test/java/com/iota/iri/BundleValidatorTest.java
@@ -30,7 +30,7 @@ public static void setUp() throws Exception {
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder.getRoot().getAbsolutePath(),1000));
tangle.init();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
}
@AfterClass
diff --git a/src/test/java/com/iota/iri/MilestoneTrackerTest.java b/src/test/java/com/iota/iri/MilestoneTrackerTest.java
index 571bdfe4a3..43902be78e 100644
--- a/src/test/java/com/iota/iri/MilestoneTrackerTest.java
+++ b/src/test/java/com/iota/iri/MilestoneTrackerTest.java
@@ -43,7 +43,7 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void beforeClass() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
@@ -63,7 +63,7 @@ private static void initializeMilestoneTracker(String coordinator, int keys, int
configuration.parseConfigFromArgs(args);
MessageQ messageQ = Mockito.mock(MessageQ.class);
- TransactionValidator transactionValidator = new TransactionValidator(tangle, snapshotProvider.getInitialSnapshot(), new TipsViewModel(), new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), messageQ));
+ TransactionValidator transactionValidator = new TransactionValidator(tangle, snapshotProvider, new TipsViewModel(), new TransactionRequester(tangle, snapshotProvider, messageQ));
milestoneTracker = new MilestoneTracker(tangle, snapshotProvider, transactionValidator, messageQ, Snapshot.init(configuration).clone(), configuration);
}
diff --git a/src/test/java/com/iota/iri/TransactionValidatorTest.java b/src/test/java/com/iota/iri/TransactionValidatorTest.java
index 56064d4cc4..e64162ffbc 100644
--- a/src/test/java/com/iota/iri/TransactionValidatorTest.java
+++ b/src/test/java/com/iota/iri/TransactionValidatorTest.java
@@ -36,15 +36,15 @@ public static void setUp() throws Exception {
dbFolder.create();
logFolder.create();
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
tangle.addPersistenceProvider(
new RocksDBPersistenceProvider(
dbFolder.getRoot().getAbsolutePath(), logFolder.getRoot().getAbsolutePath(),1000));
tangle.init();
TipsViewModel tipsViewModel = new TipsViewModel();
MessageQ messageQ = Mockito.mock(MessageQ.class);
- TransactionRequester txRequester = new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), messageQ);
- txValidator = new TransactionValidator(tangle, snapshotProvider.getInitialSnapshot(), tipsViewModel, txRequester);
+ TransactionRequester txRequester = new TransactionRequester(tangle, snapshotProvider, messageQ);
+ txValidator = new TransactionValidator(tangle, snapshotProvider, tipsViewModel, txRequester);
txValidator.setMwm(false, MAINNET_MWM);
}
diff --git a/src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/DbState.java b/src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/DbState.java
index 5047f69c73..a604c98b02 100644
--- a/src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/DbState.java
+++ b/src/test/java/com/iota/iri/benchmarks/dbbenchmark/states/DbState.java
@@ -45,7 +45,7 @@ public void setup() throws Exception {
BaseIotaConfig.Defaults.DB_CACHE_SIZE);
dbProvider.init();
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
tangle.addPersistenceProvider(dbProvider);
String trytes = "";
System.out.println("numTxsToTest = [" + numTxsToTest + "]");
diff --git a/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java b/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
index 72080ecf68..354796f087 100644
--- a/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
+++ b/src/test/java/com/iota/iri/controllers/MilestoneViewModelTest.java
@@ -1,10 +1,8 @@
package com.iota.iri.controllers;
import com.iota.iri.conf.MainnetConfig;
-import com.iota.iri.conf.SnapshotConfig;
import com.iota.iri.model.Hash;
import com.iota.iri.model.HashFactory;
-import com.iota.iri.model.TransactionHash;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
import org.junit.*;
@@ -175,8 +173,7 @@ public void nextGreaterThan() throws Exception {
int next = first + 1;
new MilestoneViewModel(next, HashFactory.TRANSACTION.create("GBCDEBGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUV99999")).store(tangle);
new MilestoneViewModel(first, HashFactory.TRANSACTION.create("GBCDEFGHIJKLMNODQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUVWXYZ9ABCDEFGHIJKLMNOPQRSTUV99999")).store(tangle);
- assertEquals(next, MilestoneViewModel.findClosestNextMilestone(
- tangle, first, next).index().intValue());
+ assertEquals("the found milestone should be following the previous one", next, MilestoneViewModel.findClosestNextMilestone(tangle, first, next).index().intValue());
}
@Test
diff --git a/src/test/java/com/iota/iri/controllers/TransactionRequesterTest.java b/src/test/java/com/iota/iri/controllers/TransactionRequesterTest.java
index 5c5e5d37b9..23f1e5320c 100644
--- a/src/test/java/com/iota/iri/controllers/TransactionRequesterTest.java
+++ b/src/test/java/com/iota/iri/controllers/TransactionRequesterTest.java
@@ -23,7 +23,7 @@ public class TransactionRequesterTest {
@Before
public void setUp() throws Exception {
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
}
@After
@@ -78,7 +78,7 @@ public void instance() throws Exception {
@Test
public void nonMilestoneCapacityLimited() throws Exception {
- TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), mq);
+ TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider, mq);
int capacity = TransactionRequester.MAX_TX_REQ_QUEUE_SIZE;
//fill tips list
for (int i = 0; i < capacity * 2 ; i++) {
@@ -91,7 +91,7 @@ public void nonMilestoneCapacityLimited() throws Exception {
@Test
public void milestoneCapacityNotLimited() throws Exception {
- TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), mq);
+ TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider, mq);
int capacity = TransactionRequester.MAX_TX_REQ_QUEUE_SIZE;
//fill tips list
for (int i = 0; i < capacity * 2 ; i++) {
@@ -104,7 +104,7 @@ public void milestoneCapacityNotLimited() throws Exception {
@Test
public void mixedCapacityLimited() throws Exception {
- TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider.getInitialSnapshot(), mq);
+ TransactionRequester txReq = new TransactionRequester(tangle, snapshotProvider, mq);
int capacity = TransactionRequester.MAX_TX_REQ_QUEUE_SIZE;
//fill tips list
for (int i = 0; i < capacity * 4 ; i++) {
diff --git a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
index d214a585bf..b3ae7f91c6 100644
--- a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
+++ b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java
@@ -45,7 +45,7 @@ public static void setUp() throws Exception {
logFolder.getRoot().getAbsolutePath(),1000);
tangle.addPersistenceProvider(rocksDBPersistenceProvider);
tangle.init();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
}
@AfterClass
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculatorTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculatorTest.java
index 98cd63ef2f..94bc7171c1 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculatorTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/CumulativeWeightCalculatorTest.java
@@ -45,13 +45,13 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void setUp() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
.getRoot().getAbsolutePath(), 1000));
tangle.init();
- cumulativeWeightCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider.getInitialSnapshot());
+ cumulativeWeightCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider);
}
@Test
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java
index 28274663d5..70eb49a7d6 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java
@@ -7,6 +7,7 @@
import com.iota.iri.model.Hash;
import com.iota.iri.model.IntegerIndex;
import com.iota.iri.model.TransactionHash;
+import com.iota.iri.service.milestone.LatestMilestoneTracker;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.snapshot.impl.SnapshotProviderImpl;
import com.iota.iri.service.tipselection.EntryPointSelector;
@@ -26,14 +27,14 @@
public class EntryPointSelectorImplTest {
@Mock
- private MilestoneTracker milestoneTracker;
+ private LatestMilestoneTracker latestMilestoneTracker;
@Mock
private Tangle tangle;
private static SnapshotProvider snapshotProvider;
@BeforeClass
public static void setUp() throws Exception {
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
MilestoneViewModel.clear();
}
@@ -43,7 +44,7 @@ public void testEntryPointBWithTangleData() throws Exception {
mockTangleBehavior(milestoneHash);
mockMilestoneTrackerBehavior(snapshotProvider.getInitialSnapshot().getIndex() + 1, Hash.NULL_HASH);
- EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider, milestoneTracker);
+ EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider, latestMilestoneTracker);
Hash entryPoint = entryPointSelector.getEntryPoint(10);
Assert.assertEquals("The entry point should be the milestone in the Tangle", milestoneHash, entryPoint);
@@ -53,7 +54,7 @@ public void testEntryPointBWithTangleData() throws Exception {
public void testEntryPointAWithoutTangleData() throws Exception {
mockMilestoneTrackerBehavior(0, Hash.NULL_HASH);
- EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider, milestoneTracker);
+ EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider, latestMilestoneTracker);
Hash entryPoint = entryPointSelector.getEntryPoint(10);
Assert.assertEquals("The entry point should be the last tracked solid milestone", Hash.NULL_HASH, entryPoint);
@@ -61,18 +62,15 @@ public void testEntryPointAWithoutTangleData() throws Exception {
private void mockMilestoneTrackerBehavior(int latestSolidSubtangleMilestoneIndex, Hash latestSolidSubtangleMilestone) {
- milestoneTracker.latestSolidSubtangleMilestoneIndex = latestSolidSubtangleMilestoneIndex;
- milestoneTracker.latestMilestoneIndex = latestSolidSubtangleMilestoneIndex;
- milestoneTracker.latestSolidSubtangleMilestone = latestSolidSubtangleMilestone;
- milestoneTracker.latestMilestone = latestSolidSubtangleMilestone;
+ snapshotProvider.getLatestSnapshot().setIndex(latestSolidSubtangleMilestoneIndex);
+ snapshotProvider.getLatestSnapshot().setHash(latestSolidSubtangleMilestone);
+ Mockito.when(latestMilestoneTracker.getLatestMilestoneIndex()).thenReturn(latestSolidSubtangleMilestoneIndex);
}
private void mockTangleBehavior(Hash milestoneModelHash) throws Exception {
com.iota.iri.model.persistables.Milestone milestoneModel = new com.iota.iri.model.persistables.Milestone();
milestoneModel.index = new IntegerIndex(snapshotProvider.getInitialSnapshot().getIndex() + 1);
milestoneModel.hash = milestoneModelHash;
- Mockito.when(milestoneTracker.getMilestoneStartIndex()).thenReturn(0);
- milestoneTracker.latestMilestoneIndex = 1;
Mockito.when(tangle.load(com.iota.iri.model.persistables.Milestone.class, milestoneModel.index))
.thenReturn(milestoneModel);
}
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/RatingOneTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/RatingOneTest.java
index cc99a27ec4..2c12f945be 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/RatingOneTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/RatingOneTest.java
@@ -36,7 +36,7 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void setUp() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/TailFinderImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/TailFinderImplTest.java
index 06581f76b4..281e8fe710 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/TailFinderImplTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/TailFinderImplTest.java
@@ -40,7 +40,7 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void setUp() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java
index fbf5a81316..082a76e3a6 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java
@@ -1,14 +1,12 @@
package com.iota.iri.service.tipselection.impl;
-import com.iota.iri.LedgerValidator;
-import com.iota.iri.MilestoneTracker;
import com.iota.iri.TransactionTestUtils;
-import com.iota.iri.TransactionValidator;
import com.iota.iri.conf.MainnetConfig;
import com.iota.iri.conf.TipSelConfig;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.controllers.TransactionViewModelTest;
import com.iota.iri.model.Hash;
+import com.iota.iri.service.ledger.LedgerService;
import com.iota.iri.service.snapshot.SnapshotProvider;
import com.iota.iri.service.snapshot.impl.SnapshotProviderImpl;
import com.iota.iri.storage.Tangle;
@@ -35,11 +33,7 @@ public class WalkValidatorImplTest {
private static SnapshotProvider snapshotProvider;
private TipSelConfig config = new MainnetConfig();
@Mock
- private LedgerValidator ledgerValidator;
- @Mock
- private TransactionValidator transactionValidator;
- @Mock
- private MilestoneTracker milestoneTrackerTracker;
+ private static LedgerService ledgerService;
@AfterClass
public static void tearDown() throws Exception {
@@ -52,7 +46,7 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void setUp() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
@@ -67,11 +61,11 @@ public void shouldPassValidation() throws Exception {
tx.updateSolid(true);
tx.store(tangle, snapshotProvider.getInitialSnapshot());
Hash hash = tx.getHash();
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = depth;
+ snapshotProvider.getLatestSnapshot().setIndex(depth);
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator, milestoneTrackerTracker, config);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService, config);
Assert.assertTrue("Validation failed", walkValidator.isValid(hash));
}
@@ -82,12 +76,12 @@ public void failOnTxType() throws Exception {
tx.store(tangle, snapshotProvider.getInitialSnapshot());
Hash hash = tx.getTrunkTransactionHash();
tx.updateSolid(true);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = depth;
+ snapshotProvider.getLatestSnapshot().setIndex(depth);
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeded but should have failed since tx is missing", walkValidator.isValid(hash));
}
@@ -97,12 +91,12 @@ public void failOnTxIndex() throws Exception {
tx.store(tangle, snapshotProvider.getInitialSnapshot());
Hash hash = tx.getHash();
tx.updateSolid(true);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE;
+ snapshotProvider.getLatestSnapshot().setIndex(Integer.MAX_VALUE);
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeded but should have failed since we are not on a tail", walkValidator.isValid(hash));
}
@@ -112,12 +106,12 @@ public void failOnSolid() throws Exception {
tx.store(tangle, snapshotProvider.getInitialSnapshot());
Hash hash = tx.getHash();
tx.updateSolid(false);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE;
+ snapshotProvider.getLatestSnapshot().setIndex(Integer.MAX_VALUE);
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeded but should have failed since tx is not solid",
walkValidator.isValid(hash));
}
@@ -129,11 +123,11 @@ public void failOnBelowMaxDepthDueToOldMilestone() throws Exception {
tx.setSnapshot(tangle, snapshotProvider.getInitialSnapshot(), 2);
Hash hash = tx.getHash();
tx.updateSolid(true);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(Integer.MAX_VALUE);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeeded but should have failed tx is below max depth",
walkValidator.isValid(hash));
}
@@ -152,11 +146,11 @@ public void belowMaxDepthWithFreshMilestone() throws Exception {
hash = tx.getHash();
tx.store(tangle, snapshotProvider.getInitialSnapshot());
}
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 100;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(100);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertTrue("Validation failed but should have succeeded since tx is above max depth",
walkValidator.isValid(hash));
}
@@ -177,11 +171,11 @@ public void failBelowMaxDepthWithFreshMilestoneDueToLongChain() throws Exception
tx.updateSolid(true);
tx.store(tangle, snapshotProvider.getInitialSnapshot());
}
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 100;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(100);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeeded but should have failed since tx is below max depth",
walkValidator.isValid(hash));
}
@@ -199,11 +193,11 @@ public void belowMaxDepthOnGenesis() throws Exception {
hash = tx.getHash();
tx.store(tangle, snapshotProvider.getInitialSnapshot());
}
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash()))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), tx.getHash()))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 15;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(15);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertTrue("Validation failed but should have succeeded. We didn't exceed the maximal amount of" +
"transactions that may be analyzed.",
walkValidator.isValid(tx.getHash()));
@@ -223,11 +217,11 @@ public void failBelowMaxDepthOnGenesisDueToLongChain() throws Exception {
tx.store(tangle, snapshotProvider.getInitialSnapshot());
hash = tx.getHash();
}
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash()))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), tx.getHash()))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 17;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(17);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeeded but should have failed. We exceeded the maximal amount of" +
"transactions that may be analyzed.",
walkValidator.isValid(tx.getHash()));
@@ -239,12 +233,12 @@ public void failOnInconsistency() throws Exception {
tx.store(tangle, snapshotProvider.getInitialSnapshot());
Hash hash = tx.getHash();
tx.updateSolid(true);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), hash))
.thenReturn(false);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE;
+ snapshotProvider.getLatestSnapshot().setIndex(Integer.MAX_VALUE);
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation succeded but should have failed due to inconsistent ledger state",
walkValidator.isValid(hash));
}
@@ -281,14 +275,14 @@ public void dontMarkWrongTxsAsBelowMaxDepth() throws Exception {
tx4.updateSolid(true);
tx4.store(tangle, snapshotProvider.getInitialSnapshot());
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx4.getHash()))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), tx4.getHash()))
.thenReturn(true);
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx2.getHash()))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), tx2.getHash()))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 100;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(100);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation of tx4 succeeded but should have failed since tx is below max depth",
walkValidator.isValid(tx4.getHash()));
Assert.assertTrue("Validation of tx2 failed but should have succeeded since tx is above max depth",
@@ -327,12 +321,12 @@ public void allowConfirmedTxToPassBelowMaxDepthAfterMilestoneConfirmation() thro
tx4.updateSolid(true);
tx4.store(tangle, snapshotProvider.getInitialSnapshot());
- Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx4.getHash()))
+ Mockito.when(ledgerService.isBalanceDiffConsistent(new HashSet<>(), new HashMap<>(), tx4.getHash()))
.thenReturn(true);
- milestoneTrackerTracker.latestSolidSubtangleMilestoneIndex = 100;
- WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerValidator,
- milestoneTrackerTracker, config);
+ snapshotProvider.getLatestSnapshot().setIndex(100);
+ WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, snapshotProvider, ledgerService,
+ config);
Assert.assertFalse("Validation of tx4 succeeded but should have failed since tx is below max depth",
walkValidator.isValid(tx4.getHash()));
diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkerAlphaTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkerAlphaTest.java
index 6d42ee3ea4..3eea85d2ff 100644
--- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkerAlphaTest.java
+++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkerAlphaTest.java
@@ -46,7 +46,7 @@ public static void tearDown() throws Exception {
@BeforeClass
public static void setUp() throws Exception {
tangle = new Tangle();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
dbFolder.create();
logFolder.create();
tangle.addPersistenceProvider(new RocksDBPersistenceProvider(dbFolder.getRoot().getAbsolutePath(), logFolder
diff --git a/src/test/java/com/iota/iri/storage/TangleTest.java b/src/test/java/com/iota/iri/storage/TangleTest.java
index 1b7d89d38e..26ff768a6e 100644
--- a/src/test/java/com/iota/iri/storage/TangleTest.java
+++ b/src/test/java/com/iota/iri/storage/TangleTest.java
@@ -35,7 +35,7 @@ public void setUp() throws Exception {
logFolder.getRoot().getAbsolutePath(),1000);
tangle.addPersistenceProvider(rocksDBPersistenceProvider);
tangle.init();
- snapshotProvider = new SnapshotProviderImpl(new MainnetConfig());
+ snapshotProvider = new SnapshotProviderImpl().init(new MainnetConfig());
}
@After