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

sort milestone candidates before analyzing #1660

Merged
merged 5 commits into from
Jan 16, 2020

Conversation

achabill
Copy link
Contributor

Description

Sort milestone candidates before analyzing to increase the likely hood of a new milestone being seen early.

Part of #1655

Type of change

  • Enhancement (a non-breaking change which adds functionality)

Checklist:

  • My code follows the style guidelines for this project
  • I have performed a self-review of my own code
  • I have commented on my code, particularly in hard-to-understand areas
  • New and existing unit tests pass locally with my changes

public static List<TransactionViewModel> loadAsSortedList(Tangle tangle, Indexable hash) throws Exception {
Address hashes = (Address)tangle.load(Address.class, hash);
return hashes.set.stream()
.map(item -> fromHash(tangle,item))
Copy link
Contributor

Choose a reason for hiding this comment

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

When you map with a fromHash call as you've done here, a tvm will always be created, which invalidates the tvm != null call below when sorting. What happens in this case is that the stream will throw an exception once the sorting hits a transaction that doesn't exist in the db (as is the case when a milestone has been removed from pruning). To fix this issue locally I replaced the mapping with:

.map(
    item -> {
        try {
            if(tangle.exists(Transaction.class, item)) {
            return fromHash(tangle, item);
        } else {
            return null;
        }
    }catch(Exception e){
        return null;
    } 
})

This will make sure that if the transaction does not exist, a tvm will not be created for it. Of course this means that you will either need to not include these transactions in the collection before you analyse it in the LatestMilestoneTrackerImpl or have line 314 include a null check before trying to add to the queue's.
i.e
if (tvm != null && seenMilestoneCandidates.add(tvm)) {

Copy link
Contributor

Choose a reason for hiding this comment

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

@achabill if you apply a change like this the code should pass. As is however it throws an exception the first time it encounters a pruned milestone. Which is the case in the regression test.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok.

@GalRogozinski
Copy link
Contributor

I may be forced to look into #1447 now...
If we implement it, then this PR will become obsolete

@GalRogozinski GalRogozinski added the Deffered Will be addressed and merged in later versions. label Dec 17, 2019
@GalRogozinski GalRogozinski added C-Consensus and removed Deffered Will be addressed and merged in later versions. T-Discussion labels Jan 9, 2020
Comment on lines 46 to 47
* Constructor for an {@link Address} set controller from an existing {@link Address} set.
* The resulting hash list is sorted
Copy link
Contributor

Choose a reason for hiding this comment

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

This doc is unclear to me. This is not a java constructor...

Maybe write:
"Loads all transaction that mutate a certain address. It sorts them by the attachment timestamp"

* The resulting hash list is sorted
*
* @param tangle The tangle reference for the database to find the {@link Address} set in
* @param hash The hash identifier for the {@link Address} set that needs to be found
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param hash The hash identifier for the {@link Address} set that needs to be found
* @param hash The address we are loading the transactions for

*
* @param tangle The tangle reference for the database to find the {@link Address} set in
* @param hash The hash identifier for the {@link Address} set that needs to be found
* @return The {@link AddressViewModel} controller generated
Copy link
Contributor

Choose a reason for hiding this comment

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

We are returning a list of transactions (actually transaction controllers unfortunately)

* @return The {@link AddressViewModel} controller generated
* @throws Exception Thrown if the database cannot load an {@link Address} set from the reference {@link Hash}
*/
public static List<TransactionViewModel> loadAsSortedList(Tangle tangle, Indexable hash) throws Exception {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just note (no need to change):
Usually it is best to use an interface like Indexable in method parameters.

In this case it would probably best to use something more specific like AddressHash because you are not going to be using other subtypes of Indexable in this method.
However at the moment casting will be neccessary to change this...

So this is just a point to think of before we start refactoring...

if (tangle.exists(Transaction.class, item)) {
return TransactionViewModel.fromHash(tangle, item);
}
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

why return null? Why not do a .filter(item -> (tangle.exists(Transaction.class, item)) so you won't have nulls in your list

}
return null;
} catch (Exception e) {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

why are you swallowing exceptions? this shouldn't be happening

} catch (Exception e) {
return null;
}
}).sorted(Comparator.comparing(tvm -> tvm != null ? tvm.getTransaction().attachmentTimestamp : 0))
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess sorting by attachmentTimestamp is fine

maybe add a comment that this was an arbitrary choice (you also have timestamp which is part of the bundle essence)

@DyrellC
Copy link
Contributor

DyrellC commented Jan 13, 2020

@acha-bill still waiting on you to respond to Gal's review before I can review myself

Comment on lines 55 to 70
Address hashes = (Address) tangle.load(Address.class, hash);
return hashes.set.stream().filter(hash1 -> {
try {
return TransactionViewModel.exists(tangle, hash1);
} catch (Exception e) {
throw new RuntimeException(e);
}
}).map(item -> {
try {
return TransactionViewModel.fromHash(tangle, item);
} catch (Exception e) {
throw new RuntimeException(e);
}
}).sorted(Comparator.comparing(TransactionViewModel::getAttachmentTimestamp))
.collect(Collectors.toList());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't run it, but the following compiles and looks nicer:

public static List<TransactionViewModel> loadAsSortedList(Tangle tangle, Indexable hash) throws Exception {
        Address hashes = (Address) tangle.load(Address.class, hash);
        return hashes.set.stream()
                .filter(ThrowingPredicate.unchecked(hash1 -> TransactionViewModel.exists(tangle, hash1)))
                .map(ThrowingFunction.unchecked(item -> TransactionViewModel.fromHash(tangle, item)))
                .sorted(Comparator.comparing(TransactionViewModel::getAttachmentTimestamp))
                .collect(Collectors.toList());
    }

Copy link
Contributor

@GalRogozinski GalRogozinski left a comment

Choose a reason for hiding this comment

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

Looks good and test just passed

waiting for @DyrellC to approve before I merge

Copy link
Contributor

@DyrellC DyrellC left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@GalRogozinski
Copy link
Contributor

@karimodm
This should now help with solidifying milestones
note that it is merged

@GalRogozinski GalRogozinski merged commit b658b88 into iotaledger:dev Jan 16, 2020
DyrellC added a commit to DyrellC/iri that referenced this pull request Feb 10, 2020
GalRogozinski pushed a commit that referenced this pull request Feb 11, 2020
kwek20 pushed a commit to kwek20/iri that referenced this pull request Mar 10, 2020
@GalRogozinski GalRogozinski mentioned this pull request May 6, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants