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

Feature: Improved CW Calculation #1451

Merged
merged 22 commits into from
Jul 31, 2019
Merged
Changes from 5 commits
Commits
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
4 changes: 2 additions & 2 deletions src/main/java/com/iota/iri/Iota.java
Original file line number Diff line number Diff line change
@@ -37,8 +37,8 @@
import com.iota.iri.service.tipselection.TailFinder;
import com.iota.iri.service.tipselection.TipSelector;
import com.iota.iri.service.tipselection.Walker;
import com.iota.iri.service.tipselection.impl.CumulativeWeightCalculator;
import com.iota.iri.service.tipselection.impl.EntryPointSelectorImpl;
import com.iota.iri.service.tipselection.impl.RecursiveWeightCalculator;
import com.iota.iri.service.tipselection.impl.TailFinderImpl;
import com.iota.iri.service.tipselection.impl.TipSelectorImpl;
import com.iota.iri.service.tipselection.impl.WalkerAlpha;
@@ -345,7 +345,7 @@ private PersistenceProvider createRocksDbProvider(String path, String log, int c
private TipSelector createTipSelector(TipSelConfig config) {
EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, snapshotProvider,
latestMilestoneTracker);
RatingCalculator ratingCalculator = new RecursiveWeightCalculator(tangle, snapshotProvider);
RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider);
TailFinder tailFinder = new TailFinderImpl(tangle);
Walker walker = new WalkerAlpha(tailFinder, tangle, new SecureRandom(), config);
return new TipSelectorImpl(tangle, snapshotProvider, ledgerService, entryPointSelector, ratingCalculator,
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ public interface RatingCalculator {
* </p>
*
* @param entryPoint Transaction hash of a selected entry point.
* @return Map of ratings for each transaction that references entryPoint.
* @return Map of ratings for each transaction that references entryPoint.
* @throws Exception If DB fails to retrieve transactions
*/

Original file line number Diff line number Diff line change
@@ -21,22 +21,25 @@
import com.iota.iri.utils.collections.interfaces.UnIterableMap;

/**
* Calculates the weight recursively/on the fly
* Used to create a weighted random walks.
* Implementation of {@link RatingCalculator} that calculates the cumulative weight
* Calculates the weight recursively/on the fly for each transaction referencing {@code entryPoint}. <br>
* Works using DFS search for new hashes and a BFS calculation.
* Uses cached values to prevent double database lookup for approvers
*
* @see <a href="cumulative.md">https://github.com/alongalky/iota-docs/blob/master/cumulative.md</a>
Copy link
Contributor

Choose a reason for hiding this comment

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

Delete this link

*/
public class RecursiveWeightCalculator implements RatingCalculator {
public class CumulativeWeightCalculator implements RatingCalculator {

private final Tangle tangle;
private final SnapshotProvider snapshotProvider;

/**
* Constructor for Recursive Weight Calculator
* Constructor for Cumulative Weight Calculator
*
* @param tangle Tangle object which acts as a database interface
* @param snapshotProvider accesses ledger's snapshots
*/
public RecursiveWeightCalculator(Tangle tangle, SnapshotProvider snapshotProvider) {
public CumulativeWeightCalculator(Tangle tangle, SnapshotProvider snapshotProvider) {
this.tangle = tangle;
this.snapshotProvider = snapshotProvider;
}
@@ -55,40 +58,58 @@ private UnIterableMap<HashId, Integer> calculateRatingDfs(Hash entryPoint) throw
: 1;

// Estimated capacity per depth, assumes 5 minute gap in between milestones, at 3tps
UnIterableMap<HashId, Integer> hashWeight = createTxHashToCumulativeWeightMap( 5 * 60 * 3 * depth);
UnIterableMap<HashId, Integer> hashWeightMap = createTxHashToCumulativeWeightMap( 5 * 60 * 3 * depth);

Map<Hash, Set<Hash>> txToDirectApprovers = new HashMap<>();

Deque<Hash> stack = new ArrayDeque<>();
stack.push(entryPoint);
stack.addAll(getTxDirectApproversHashes(entryPoint, txToDirectApprovers));

while (!stack.isEmpty()) {
Hash txHash = stack.peekLast();
Hash txHash = stack.pollLast();

Set<Hash> approvers = getTxDirectApproversHashes(txHash, txToDirectApprovers);
if (null != approvers && (approvers.size() == 0 || hasAll(hashWeight, approvers, stack))) {
approvers.add(txHash);
hashWeight.put(txHash, getRating(approvers, txToDirectApprovers));
stack.removeLast();

// If its empty, its a tip!
if (approvers.isEmpty()) {
hashWeightMap.put(txHash, 1);

// Else we go deeper
} else {
stack.addAll(approvers);
}
// Add all approvers, given we didnt go there
for (Hash h : approvers) {
if (!hashWeightMap.containsKey(h)) {
stack.add(h);
}
}

// Add the tx to the approvers list to count itself as +1 weight, preventing self-referencing
approvers.add(txHash);

// calculate and add rating. Naturally the first time all approvers need to be looked up. Then its cached.
hashWeightMap.put(txHash, getRating(approvers, txToDirectApprovers));
}
}

return hashWeight;
// If we have a circular reference, its already added, otherwise we save a big calculation
Copy link
Contributor

Choose a reason for hiding this comment

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

circular -> self referencing

if (!hashWeightMap.containsKey(entryPoint)) {
hashWeightMap.put(entryPoint, hashWeightMap.size() + 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

nice

}
return hashWeightMap;
}

/**
* Gets the rating of a set, calculated by checking its approvers
*
* @param startingSet
* @param txToDirectApproversCache
* @return
* @throws Exception
* @param startingSet All approvers of a certain hash, including the hash itself.
* Should always start with at least 1 hash.
* @param txToDirectApproversCache The cache of approvers, used to prevent double db lookups
* @return The weight, or rating, of the starting hash
* @throws Exception If we can't get the approvers
*/
private int getRating(Set<Hash> startingSet, Map<Hash, Set<Hash>> txToDirectApproversCache) throws Exception {
Deque<Hash> stack = new ArrayDeque<>(startingSet);
while (stack.isEmpty()) {
while (!stack.isEmpty()) {
Set<Hash> approvers = getTxDirectApproversHashes(stack.pollLast(), txToDirectApproversCache);
for (Hash hash : approvers) {
if (startingSet.add(hash)) {
@@ -99,22 +120,6 @@ private int getRating(Set<Hash> startingSet, Map<Hash, Set<Hash>> txToDirectAppr

return startingSet.size();
}

/**
*
* @param source
* @param requester
* @param stack
* @return
*/
private boolean hasAll(UnIterableMap<HashId, Integer> source, Set<Hash> requester, Deque<Hash> stack) {
for (Hash h : requester) {
if (!source.containsKey(h) && !stack.contains(h)) {
return false;
}
}
return true;
}

/**
* Finds the approvers of a transaction, and adds it to the txToDirectApprovers map if they weren't there yet.
Original file line number Diff line number Diff line change
@@ -18,7 +18,6 @@
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Ignore;
Copy link
Contributor

Choose a reason for hiding this comment

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

So we're still using transforming map
You want to avoid doing more tests for now?

Fine with that, we can change it later

import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
@@ -65,7 +64,7 @@ public static void setUp() throws Exception {
tangle.addPersistenceProvider( new RocksDBPersistenceProvider(
dbFolder.getRoot().getAbsolutePath(), logFolder.getRoot().getAbsolutePath(),1000, Tangle.COLUMN_FAMILIES, Tangle.METADATA_COLUMN_FAMILY));
tangle.init();
cumulativeWeightCalculator = new RecursiveWeightCalculator(tangle, snapshotProvider);
cumulativeWeightCalculator = new CumulativeWeightCalculator(tangle, snapshotProvider);
}

@Test