Skip to content
This repository has been archived by the owner on Aug 23, 2020. It is now read-only.

Activate Local Snapshots #1172

Merged
122 changes: 101 additions & 21 deletions src/main/java/com/iota/iri/Iota.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All the Impls should be removed.
This is because: The D in Solid states that the code should depend on abstractions, not concretions.

The Impl is sort of a feature that help you enforce D. Everytime you see it you know D breaks. Besides it is ugly so it incentivizes you to use the interface :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so we can use all the implementation specific methods like "init", "start" and so on without having to typecast them to their explicit type again. I could have the field be generic and then do

((MilestoneSolidifierImpl) milestoneSolidifier).init(...) but that kind of makes it more complicated imho

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm
Once we will do proper DI we will fix it

For now it is fine


public final Tangle tangle;
public final SnapshotProvider snapshotProvider;
public final TransactionValidator transactionValidator;
public final TipsSolidifier tipsSolidifier;
public final TransactionRequester transactionRequester;
Expand All @@ -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();
}

/**
Expand All @@ -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 {
Expand Down Expand Up @@ -175,14 +240,28 @@ private void rescanDb() throws Exception {
* Exceptions during shutdown are not caught.
*/
public void shutdown() throws Exception {
milestoneTracker.shutDown();
tipsSolidifier.shutdown();
node.shutdown();
udpReceiver.shutdown();
replicator.shutdown();
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() {
Expand All @@ -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);
}
}
28 changes: 14 additions & 14 deletions src/main/java/com/iota/iri/TransactionValidator.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -246,7 +246,7 @@ public boolean checkSolidity(Hash hash, boolean milestone, int maxProcessedTrans
if(fromHash(tangle, hash).isSolid()) {
return true;
}
Set<Hash> analyzedHashes = new HashSet<>(initialSnapshot.getSolidEntryPoints().keySet());
Set<Hash> analyzedHashes = new HashSet<>(snapshotProvider.getInitialSnapshot().getSolidEntryPoints().keySet());
if(maxProcessedTransactions != Integer.MAX_VALUE) {
maxProcessedTransactions += analyzedHashes.size();
}
Expand All @@ -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)) {
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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;
}
}
Expand All @@ -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();
Expand Down