Skip to content
This repository was archived by the owner on Aug 23, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/main/java/com/iota/iri/Iota.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.iota.iri.service.transactionpruning.DepthPruningCondition;
import com.iota.iri.service.transactionpruning.SizePruningCondition;
import com.iota.iri.service.transactionpruning.TransactionPruner;
import com.iota.iri.service.validation.TransactionSolidifier;
import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.storage.*;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
Expand Down Expand Up @@ -96,6 +97,8 @@ public class Iota {

public final MilestoneSolidifier milestoneSolidifier;

public final TransactionSolidifier transactionSolidifier;

public final BundleValidator bundleValidator;

public final Tangle tangle;
Expand Down Expand Up @@ -127,7 +130,7 @@ public Iota(IotaConfig configuration, SpentAddressesProvider spentAddressesProvi
TransactionRequester transactionRequester, NeighborRouter neighborRouter,
TransactionProcessingPipeline transactionProcessingPipeline, TipsRequester tipsRequester,
TipsViewModel tipsViewModel, TipSelector tipsSelector, LocalSnapshotsPersistenceProvider localSnapshotsDb,
CacheManager cacheManager) {
CacheManager cacheManager, TransactionSolidifier transactionSolidifier) {
this.configuration = configuration;

this.ledgerService = ledgerService;
Expand All @@ -145,9 +148,9 @@ public Iota(IotaConfig configuration, SpentAddressesProvider spentAddressesProvi
this.neighborRouter = neighborRouter;
this.txPipeline = transactionProcessingPipeline;
this.tipsRequester = tipsRequester;
this.transactionSolidifier = transactionSolidifier;
this.localSnapshotsDb = localSnapshotsDb;


// legacy classes
this.bundleValidator = bundleValidator;
this.tangle = tangle;
Expand Down Expand Up @@ -200,8 +203,6 @@ public void init() throws Exception {
tangle.clearMetadata(com.iota.iri.model.persistables.Transaction.class);
}

transactionValidator.init();

txPipeline.start();
neighborRouter.start();
tipsRequester.start();
Expand All @@ -210,6 +211,7 @@ public void init() throws Exception {
latestSolidMilestoneTracker.start();
seenMilestonesRetriever.start();
milestoneSolidifier.start();
transactionSolidifier.start();

if (localSnapshotManager != null) {
localSnapshotManager.addSnapshotCondition(new SnapshotDepthCondition(configuration, snapshotProvider));
Expand Down Expand Up @@ -256,6 +258,7 @@ private void rescanDb() throws Exception {
public void shutdown() throws Exception {
// shutdown in reverse starting order (to not break any dependencies)
milestoneSolidifier.shutdown();
transactionSolidifier.shutdown();
seenMilestonesRetriever.shutdown();
latestSolidMilestoneTracker.shutdown();
latestMilestoneTracker.shutdown();
Expand All @@ -270,7 +273,6 @@ public void shutdown() throws Exception {
tipsRequester.shutdown();
txPipeline.shutdown();
neighborRouter.shutdown();
transactionValidator.shutdown();
localSnapshotsDb.shutdown();
tangle.shutdown();

Expand Down
24 changes: 16 additions & 8 deletions src/main/java/com/iota/iri/MainInjectionConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
import com.iota.iri.service.tipselection.impl.*;
import com.iota.iri.service.transactionpruning.TransactionPruner;
import com.iota.iri.service.transactionpruning.async.AsyncTransactionPruner;
import com.iota.iri.service.validation.TransactionSolidifier;
import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.service.validation.impl.TransactionSolidifierImpl;
import com.iota.iri.storage.LocalSnapshotsPersistenceProvider;
import com.iota.iri.storage.Tangle;
import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider;
Expand Down Expand Up @@ -115,8 +117,8 @@ SeenMilestonesRetriever provideSeenMilestonesRetriever(Tangle tangle, SnapshotPr

@Singleton
@Provides
MilestoneSolidifier provideMilestoneSolidifier(SnapshotProvider snapshotProvider, TransactionValidator transactionValidator) {
return new MilestoneSolidifierImpl(snapshotProvider, transactionValidator);
MilestoneSolidifier provideMilestoneSolidifier(SnapshotProvider snapshotProvider, TransactionSolidifier transactionSolidifier) {
return new MilestoneSolidifierImpl(snapshotProvider, transactionSolidifier);
}

@Singleton
Expand All @@ -137,8 +139,14 @@ LocalSnapshotManager provideLocalSnapshotManager(SnapshotProvider snapshotProvid

@Singleton
@Provides
TransactionValidator provideTransactionValidator(Tangle tangle, SnapshotProvider snapshotProvider, TipsViewModel tipsViewModel, TransactionRequester transactionRequester) {
return new TransactionValidator(tangle, snapshotProvider, tipsViewModel, transactionRequester, configuration);
TransactionValidator provideTransactionValidator(SnapshotProvider snapshotProvider, TransactionRequester transactionRequester) {
return new TransactionValidator(snapshotProvider, transactionRequester, configuration);
}

@Singleton
@Provides
TransactionSolidifier provideTransactionSolidifier(Tangle tangle, SnapshotProvider snapshotProvider, TransactionRequester transactionRequester, TipsViewModel tipsViewModel){
return new TransactionSolidifierImpl(tangle, snapshotProvider, transactionRequester, tipsViewModel);
}

@Singleton
Expand Down Expand Up @@ -172,12 +180,12 @@ Iota provideIota(SpentAddressesProvider spentAddressesProvider, SpentAddressesSe
TransactionRequester transactionRequester, NeighborRouter neighborRouter,
TransactionProcessingPipeline transactionProcessingPipeline, TipsRequester tipsRequester,
TipsViewModel tipsViewModel, TipSelector tipsSelector, LocalSnapshotsPersistenceProvider localSnapshotsDb,
CacheManager cacheManager) {
CacheManager cacheManager, TransactionSolidifier transactionSolidifier) {
return new Iota(configuration, spentAddressesProvider, spentAddressesService, snapshotProvider, snapshotService,
localSnapshotManager, milestoneService, latestMilestoneTracker, latestSolidMilestoneTracker,
seenMilestonesRetriever, ledgerService, transactionPruner, milestoneSolidifier, bundleValidator, tangle,
transactionValidator, transactionRequester, neighborRouter, transactionProcessingPipeline,
tipsRequester, tipsViewModel, tipsSelector, localSnapshotsDb, cacheManager);
tipsRequester, tipsViewModel, tipsSelector, localSnapshotsDb, cacheManager, transactionSolidifier);
}

@Singleton
Expand All @@ -192,8 +200,8 @@ API provideApi(IXI ixi, TransactionRequester transactionRequester,
SpentAddressesService spentAddressesService, Tangle tangle, BundleValidator bundleValidator,
SnapshotProvider snapshotProvider, LedgerService ledgerService, NeighborRouter neighborRouter, TipSelector tipsSelector,
TipsViewModel tipsViewModel, TransactionValidator transactionValidator,
LatestMilestoneTracker latestMilestoneTracker, TransactionProcessingPipeline txPipeline) {
return new API(configuration, ixi, transactionRequester, spentAddressesService, tangle, bundleValidator, snapshotProvider, ledgerService, neighborRouter, tipsSelector, tipsViewModel, transactionValidator, latestMilestoneTracker, txPipeline);
LatestMilestoneTracker latestMilestoneTracker, TransactionProcessingPipeline txPipeline, TransactionSolidifier transactionSolidifier) {
return new API(configuration, ixi, transactionRequester, spentAddressesService, tangle, bundleValidator, snapshotProvider, ledgerService, neighborRouter, tipsSelector, tipsViewModel, transactionValidator, latestMilestoneTracker, txPipeline, transactionSolidifier);
}

@Singleton
Expand Down
22 changes: 0 additions & 22 deletions src/main/java/com/iota/iri/controllers/TransactionViewModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -779,28 +779,6 @@ public void setMetadata() {
: TransactionViewModel.FILLED_SLOT;
}

/**
* Update solid transactions
* @param tangle Tangle
* @param initialSnapshot Initial snapshot
* @param analyzedHashes analyzed hashes
* @throws Exception Exception
*/
public static void updateSolidTransactions(Tangle tangle, Snapshot initialSnapshot,
final Set<Hash> analyzedHashes) throws Exception {
Object[] hashes = analyzedHashes.toArray();
TransactionViewModel transactionViewModel;
for (int i = hashes.length - 1; i >= 0; i--) {
transactionViewModel = TransactionViewModel.fromHash(tangle, (Hash) hashes[i]);

transactionViewModel.updateHeights(tangle, initialSnapshot);

if (!transactionViewModel.isSolid()) {
transactionViewModel.updateSolid(true);
transactionViewModel.update(tangle, initialSnapshot, "solid|height");
}
}
}

/**
* Updates the {@link Transaction#solid} value of the referenced {@link Transaction} object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.Singleton;
import com.iota.iri.service.validation.TransactionSolidifier;
import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.conf.IotaConfig;
import com.iota.iri.controllers.TipsViewModel;
Expand Down Expand Up @@ -46,9 +47,9 @@ TipsRequester provideTipsRequester(NeighborRouter neighborRouter, Tangle tangle,
TransactionProcessingPipeline provideTransactionProcessingPipeline(NeighborRouter neighborRouter,
TransactionValidator txValidator, Tangle tangle, SnapshotProvider snapshotProvider,
TipsViewModel tipsViewModel, LatestMilestoneTracker latestMilestoneTracker,
TransactionRequester transactionRequester) {
TransactionRequester transactionRequester, TransactionSolidifier transactionSolidifier) {
return new TransactionProcessingPipelineImpl(neighborRouter, configuration, txValidator, tangle,
snapshotProvider, tipsViewModel, latestMilestoneTracker, transactionRequester);
snapshotProvider, tipsViewModel, latestMilestoneTracker, transactionRequester, transactionSolidifier);
}

@Singleton
Expand Down
24 changes: 12 additions & 12 deletions src/main/java/com/iota/iri/network/pipeline/ReceivedStage.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.iota.iri.network.pipeline;

import com.iota.iri.service.validation.TransactionValidator;
import com.iota.iri.service.validation.TransactionSolidifier;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.network.TransactionRequester;
import com.iota.iri.network.neighbor.Neighbor;
Expand All @@ -19,28 +19,28 @@ public class ReceivedStage implements Stage {

private Tangle tangle;
private TransactionRequester transactionRequester;
private TransactionValidator txValidator;
private TransactionSolidifier txSolidifier;
private SnapshotProvider snapshotProvider;

/**
* Creates a new {@link ReceivedStage}.
*
*
* @param tangle The {@link Tangle} database used to store/update the transaction
* @param txValidator The {@link TransactionValidator} used to store/update the transaction
* @param txSolidifier The {@link TransactionSolidifier} used to store/update the transaction
* @param snapshotProvider The {@link SnapshotProvider} used to store/update the transaction
*/
public ReceivedStage(Tangle tangle, TransactionValidator txValidator, SnapshotProvider snapshotProvider,
public ReceivedStage(Tangle tangle, TransactionSolidifier txSolidifier, SnapshotProvider snapshotProvider,
TransactionRequester transactionRequester) {
this.txValidator = txValidator;
this.txSolidifier = txSolidifier;
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
this.transactionRequester = transactionRequester;
}

/**
* Stores the given transaction in the database, updates it status
* ({@link TransactionValidator#updateStatus(TransactionViewModel)}) and updates the sender.
*
* ({@link TransactionSolidifier#updateStatus(TransactionViewModel)}) and updates the sender.
*
* @param ctx the received stage {@link ProcessingContext}
* @return a {@link ProcessingContext} which redirects to the {@link BroadcastStage}
*/
Expand All @@ -65,7 +65,7 @@ public ProcessingContext process(ProcessingContext ctx) {
if (stored) {
tvm.setArrivalTime(System.currentTimeMillis());
try {
txValidator.updateStatus(tvm);
txSolidifier.updateStatus(tvm);

// free up the recently requested transaction set
if(transactionRequester.removeRecentlyRequestedTransaction(tvm.getHash())){
Expand All @@ -91,8 +91,8 @@ public ProcessingContext process(ProcessingContext ctx) {
}

// broadcast the newly saved tx to the other neighbors
ctx.setNextStage(TransactionProcessingPipeline.Stage.BROADCAST);
ctx.setPayload(new BroadcastPayload(originNeighbor, tvm));
ctx.setNextStage(TransactionProcessingPipeline.Stage.SOLIDIFY);
ctx.setPayload(new SolidifyPayload(originNeighbor, tvm));
return ctx;
}
}
}
39 changes: 39 additions & 0 deletions src/main/java/com/iota/iri/network/pipeline/SolidifyPayload.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.iota.iri.network.pipeline;

import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.network.neighbor.Neighbor;

/**
* Defines a payload which gets submitted to the {@link SolidifyStage}.
*/
public class SolidifyPayload extends Payload {
private Neighbor originNeighbor;
private TransactionViewModel tvm;

/**
* Constructor for solidification payload.
*
* @param originNeighbor The originating point of a received transaction
* @param tvm The transaction that needs to be solidified
*/
public SolidifyPayload(Neighbor originNeighbor, TransactionViewModel tvm){
this.originNeighbor = originNeighbor;
this.tvm = tvm;
}

/**
* {@inheritDoc}
*/
@Override
public Neighbor getOriginNeighbor(){
return originNeighbor;
}

/**
* Fetches the transaction from the payload.
* @return The transaction stored in the payload.
*/
public TransactionViewModel getTransaction(){
return tvm;
}
}
94 changes: 94 additions & 0 deletions src/main/java/com/iota/iri/network/pipeline/SolidifyStage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.iota.iri.network.pipeline;

import com.iota.iri.controllers.TipsViewModel;
import com.iota.iri.controllers.TransactionViewModel;
import com.iota.iri.model.Hash;
import com.iota.iri.service.validation.TransactionSolidifier;
import com.iota.iri.storage.Tangle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.iota.iri.controllers.TransactionViewModel.fromHash;

/**
* The {@link SolidifyStage} is used to process newly received transaction for solidity. Once a transaction has been
* passed from the {@link ReceivedStage} it will be placed into this stage to have the {@link TransactionSolidifier}
* check the solidity of the transaction. If the transaction is found to be solid, it will be passed forward to the
* {@link BroadcastStage}. If it is found to be unsolid, it is put through the solidity check so that missing reference
* transactions get requested. If the transaction is unsolid, a random solid tip is broadcast instead to keep the
* requests transmitting to neighbors.
*/
public class SolidifyStage implements Stage {
private static final Logger log = LoggerFactory.getLogger(SolidifyStage.class);

private TransactionSolidifier txSolidifier;
private TipsViewModel tipsViewModel;
private Tangle tangle;

/**
* Constructor for the {@link SolidifyStage}.
*
* @param txSolidifier Transaction validator implementation for determining the validity of a transaction
* @param tipsViewModel Used for broadcasting random solid tips if the subject transaction is unsolid
* @param tangle A reference to the nodes DB
*/
public SolidifyStage(TransactionSolidifier txSolidifier, TipsViewModel tipsViewModel, Tangle tangle){
this.txSolidifier = txSolidifier;
this.tipsViewModel = tipsViewModel;
this.tangle = tangle;
}

/**
* Processes the payload of the {@link ProcessingContext} as a {@link SolidifyPayload}. First the transaction will
* be checked for solidity and validity. If the transaction is already solid or can be set solid quickly by the
* transaction validator, the transaction is passed to the {@link BroadcastStage}. If not, a random solid tip is
Copy link
Contributor

Choose a reason for hiding this comment

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

can be set solid quickly by the transaction validator solidifier

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aaah nice catch thought I caught them all. Thanks 👍

* pulled form the {@link TipsViewModel} to be broadcast instead.
*
* @param ctx The context to process
* @return The output context, in most cases a {@link BroadcastPayload}.
*/
@Override
public ProcessingContext process(ProcessingContext ctx){
try {
SolidifyPayload payload = (SolidifyPayload) ctx.getPayload();
TransactionViewModel tvm = payload.getTransaction();

if (tvm.isSolid() || txSolidifier.quickSetSolid(tvm)) {
// If the transaction is in the solidifier broadcast queue, remove it as it will be broadcast now
txSolidifier.clearFromBroadcastQueue(tvm);
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm... I think this is a good defense :-)

ctx.setNextStage(TransactionProcessingPipeline.Stage.BROADCAST);
ctx.setPayload(new BroadcastPayload(payload.getOriginNeighbor(), payload.getTransaction()));
return ctx;
}

return broadcastTip(ctx, payload);
}catch (Exception e){
log.error("Failed to process transaction for solidification", e);
ctx.setNextStage(TransactionProcessingPipeline.Stage.ABORT);
return ctx;
}

}

private ProcessingContext broadcastTip(ProcessingContext ctx, SolidifyPayload payload) throws Exception{
// First check if there is a transaction available to broadcast from the broadcast queue
TransactionViewModel tip = txSolidifier.getNextTxInBroadcastQueue();

// If there is not a transaction available from the broadcast queue, instead try to send a solid tip
if (tip == null) {
Hash tipHash = tipsViewModel.getRandomSolidTipHash();

if (tipHash == null) {
ctx.setNextStage(TransactionProcessingPipeline.Stage.FINISH);
return ctx;
}

tip = fromHash(tangle, tipHash);
}

ctx.setNextStage(TransactionProcessingPipeline.Stage.BROADCAST);
ctx.setPayload(new BroadcastPayload(payload.getOriginNeighbor(), tip));

return ctx;
}
}
Loading