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

Commit

Permalink
Hotfix: Gyros - take transaction reattachments into account #1699
Browse files Browse the repository at this point in the history
  • Loading branch information
Gal Rogozinski committed Dec 30, 2019
2 parents 90ab990 + 49b6955 commit 306bb83
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
import com.iota.iri.service.snapshot.impl.SnapshotStateDiffImpl;
import com.iota.iri.service.spentaddresses.SpentAddressesService;
import com.iota.iri.storage.Tangle;
import com.iota.iri.utils.dag.DAGHelper;

import java.util.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* <p>
* Creates a service instance that allows us to perform ledger state specific operations.
Expand All @@ -27,6 +31,9 @@
* </p>
*/
public class LedgerServiceImpl implements LedgerService {

private static final Logger log = LoggerFactory.getLogger(LedgerServiceImpl.class);

/**
* Holds the tangle object which acts as a database interface.
*/
Expand Down Expand Up @@ -82,6 +89,7 @@ public void restoreLedgerState() throws LedgerException {

@Override
public boolean applyMilestoneToLedger(MilestoneViewModel milestone) throws LedgerException {
log.debug("applying milestone {}", milestone.index());
if(generateStateDiff(milestone)) {
try {
snapshotService.replayMilestones(snapshotProvider.getLatestSnapshot(), milestone.index());
Expand Down Expand Up @@ -148,65 +156,58 @@ public Map<Hash, Long> generateBalanceDiff(Set<Hash> visitedTransactions, Hash s
throws LedgerException {

Map<Hash, Long> state = new HashMap<>();
Set<Hash> countedTx = new HashSet<>();

Snapshot initialSnapshot = snapshotProvider.getInitialSnapshot();
Map<Hash, Integer> solidEntryPoints = initialSnapshot.getSolidEntryPoints();
solidEntryPoints.keySet().forEach(solidEntryPointHash -> {
visitedTransactions.add(solidEntryPointHash);
countedTx.add(solidEntryPointHash);
});

final Queue<Hash> nonAnalyzedTransactions = new LinkedList<>(Collections.singleton(startTransaction));
Hash transactionPointer;
while ((transactionPointer = nonAnalyzedTransactions.poll()) != null) {
if (visitedTransactions.add(transactionPointer)) {
try {
final TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle,
transactionPointer);
// only take transactions into account that have not been confirmed by the referenced milestone, yet
try {
final TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle,
transactionPointer);
if (transactionViewModel.getCurrentIndex() == 0 && visitedTransactions.add(transactionPointer)) {
if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT) {
return null;
}
if (!milestoneService.isTransactionConfirmed(transactionViewModel, milestoneIndex)) {
if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT) {
return null;
} else {
if (transactionViewModel.getCurrentIndex() == 0) {

final List<TransactionViewModel> bundleTransactions = bundleValidator.validate(
tangle, snapshotProvider.getInitialSnapshot(), transactionViewModel.getHash());

if(bundleTransactions.isEmpty()){
return null;
}
final List<TransactionViewModel> bundleTransactions = bundleValidator.validate(tangle,
snapshotProvider.getInitialSnapshot(), transactionViewModel.getHash());

//ISSUE 1008: generateBalanceDiff should be refactored so we don't have those hidden
// concerns
spentAddressesService
.persistValidatedSpentAddressesAsync(bundleTransactions);

if (BundleValidator.isInconsistent(bundleTransactions)) {
break;
}
if (bundleTransactions.isEmpty()) {
return null;
}

// ISSUE 1008: generateBalanceDiff should be refactored so we don't have those hidden
// concerns
spentAddressesService.persistValidatedSpentAddressesAsync(bundleTransactions);

for (final TransactionViewModel bundleTransactionViewModel : bundleTransactions) {
if (BundleValidator.isInconsistent(bundleTransactions)) {
log.error("Encountered an inconsistent bundle with tail {} and bundle hash {}",
bundleTransactions.get(0).getHash(), bundleTransactions.get(0).getBundleHash());
return null;
}

if (bundleTransactionViewModel.value() != 0 && countedTx.add(bundleTransactionViewModel.getHash())) {
for (final TransactionViewModel bundleTransactionViewModel : bundleTransactions) {
if (bundleTransactionViewModel.value() != 0) {

final Hash address = bundleTransactionViewModel.getAddressHash();
final Long value = state.get(address);
state.put(address, value == null ? bundleTransactionViewModel.value()
: Math.addExact(value, bundleTransactionViewModel.value()));
}
}
final Hash address = bundleTransactionViewModel.getAddressHash();
final Long value = state.get(address);
state.put(address, value == null ? bundleTransactionViewModel.value()
: Math.addExact(value, bundleTransactionViewModel.value()));
}

nonAnalyzedTransactions.offer(transactionViewModel.getTrunkTransactionHash());
nonAnalyzedTransactions.offer(transactionViewModel.getBranchTransactionHash());
}
nonAnalyzedTransactions.addAll(DAGHelper.get(tangle).findTails(transactionViewModel));
}
} catch (Exception e) {
throw new LedgerException("unexpected error while generating the balance diff", e);

}

} catch (Exception e) {
throw new LedgerException("unexpected error while generating the balance diff", e);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/iota/iri/utils/ASCIIProgressBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public static String getProgressBarString(int start, int end, int current) {
int range = end - start;

// compute actual percentage of current value
double percentage = Math.floor(((double) (current - start) / (double) range) * 1000) / 1000;
// absolute value in case we are rolling back milestones
double percentage = Math.abs(Math.floor(((double) (current - start) / (double) range) * 1000) / 1000);

// how many progress blocks to print in the progress bar
int progressBlocks = (int) (10 * percentage);
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/iota/iri/utils/dag/DAGHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,39 @@ public void traverseApprovees(Hash startingTransactionHash,
traverseApprovees(startingTransactionHash, condition, currentTransactionConsumer, new HashSet<>());
}

/**
* Find all the tail hashes that can be traversed as you walk down the approvees from {@code startingTransaction}.
* When we reach a tail we must stop.
*
* @param startingTransaction starting point
* @return set of the transaction hashes of the tails
* @throws TraversalException if anything goes wrong while traversing the graph
*/
public Set<? extends Hash> findTails(TransactionViewModel startingTransaction) throws TraversalException {
Set<Hash> tailTxs = new HashSet<>();
Queue<Hash> transactionsToExamine = new ArrayDeque<>();
transactionsToExamine.offer(startingTransaction.getTrunkTransactionHash());
transactionsToExamine.offer(startingTransaction.getBranchTransactionHash());
try {
Hash currentTransactionHash;
while ((currentTransactionHash = transactionsToExamine.poll()) != null) {
TransactionViewModel currentTransaction = TransactionViewModel.fromHash(tangle, currentTransactionHash);
if (currentTransaction.getType() != TransactionViewModel.PREFILLED_SLOT) {
// if tail
if (currentTransaction.getCurrentIndex() == 0) {
tailTxs.add(currentTransaction.getHash());
} else {
transactionsToExamine.add(currentTransaction.getBranchTransactionHash());
transactionsToExamine.add(currentTransaction.getTrunkTransactionHash());
}
}
}
} catch (Exception e) {
throw new TraversalException(
"error while traversing the approvees of transaction " + startingTransaction.getHash(), e);
}
return tailTxs;
}

//endregion ////////////////////////////////////////////////////////////////////////////////////////////////////////
}

0 comments on commit 306bb83

Please sign in to comment.