@@ -510,7 +510,7 @@ private void persistLocalSnapshot(SnapshotProvider snapshotProvider, Snapshot ne
510510
511511 /**
512512 * <p>
513- * This method determines if a transaction is orphaned.
513+ * This method determines if a transaction is orphaned when none of its approvers is confirmed by a milestone .
514514 * </p>
515515 * <p>
516516 * Since there is no hard definition for when a transaction can be considered to be orphaned, we define orphaned in
@@ -522,14 +522,14 @@ private void persistLocalSnapshot(SnapshotProvider snapshotProvider, Snapshot ne
522522 * a relatively safe way to determine if a subtangle "above" a transaction got orphaned.
523523 * </p>
524524 *
525- * @param tangle Tangle object which acts as a database interface
526- * @param transaction transaction that shall be checked
527- * @param referenceTransaction transaction that acts as a judge to the other transaction
525+ * @param tangle Tangle object which acts as a database interface
526+ * @param transaction transaction that shall be checked
527+ * @param referenceTransaction transaction that acts as a judge to the other transaction
528528 * @param processedTransactions transactions that were visited already while trying to determine the orphaned status
529529 * @return true if the transaction got orphaned and false otherwise
530530 * @throws SnapshotException if anything goes wrong while determining the orphaned status
531531 */
532- private boolean isOrphaned (Tangle tangle , TransactionViewModel transaction ,
532+ private boolean isProbablyOrphaned (Tangle tangle , TransactionViewModel transaction ,
533533 TransactionViewModel referenceTransaction , Set <Hash > processedTransactions ) throws SnapshotException {
534534
535535 AtomicBoolean nonOrphanedTransactionFound = new AtomicBoolean (false );
@@ -553,29 +553,27 @@ private boolean isOrphaned(Tangle tangle, TransactionViewModel transaction,
553553
554554 /**
555555 * <p>
556- * This method checks if a transaction is a solid entry point for the targetMilestone.
557- * </p>
558- * <p>
559- * A transaction is considered a solid entry point if it has non-orphaned approvers.
556+ * We determine whether future milestones will approve {@param transactionHash}. This should aid in determining
557+ * solid entry points.
560558 * </p>
561559 * <p>
562560 * To check if the transaction has non-orphaned approvers we first check if any of its approvers got confirmed by a
563561 * future milestone, since this is very cheap. If none of them got confirmed by another milestone we do the more
564- * expensive check from {@link #isOrphaned (Tangle, TransactionViewModel, TransactionViewModel, Set)}.
562+ * expensive check from {@link #isProbablyOrphaned (Tangle, TransactionViewModel, TransactionViewModel, Set)}.
565563 * </p>
566564 * <p>
567565 * Since solid entry points have a limited life time and to prevent potential problems due to temporary errors in
568- * the database, we assume that the checked transaction is a solid entry point if any error occurs while determining
569- * its status. This is a storage <=> reliability trade off, since the only bad effect of having too many solid entry
570- * points) is a bigger snapshot file.
566+ * the database, we assume that the checked transaction is not orphaned if any error occurs while determining its
567+ * status, thus adding solid entry points . This is a storage <=> reliability trade off, since the only bad effect of
568+ * having too many solid entry points) is a bigger snapshot file.
571569 * </p>
572570 *
573- * @param tangle Tangle object which acts as a database interface
571+ * @param tangle Tangle object which acts as a database interface
574572 * @param transactionHash hash of the transaction that shall be checked
575573 * @param targetMilestone milestone that is used as an anchor for our checks
576574 * @return true if the transaction is a solid entry point and false otherwise
577575 */
578- private boolean isSolidEntryPoint (Tangle tangle , Hash transactionHash , MilestoneViewModel targetMilestone ) {
576+ private boolean isNotOrphaned (Tangle tangle , Hash transactionHash , MilestoneViewModel targetMilestone ) {
579577 Set <TransactionViewModel > unconfirmedApprovers = new HashSet <>();
580578
581579 try {
@@ -592,7 +590,7 @@ private boolean isSolidEntryPoint(Tangle tangle, Hash transactionHash, Milestone
592590 Set <Hash > processedTransactions = new HashSet <>();
593591 TransactionViewModel milestoneTransaction = TransactionViewModel .fromHash (tangle , targetMilestone .getHash ());
594592 for (TransactionViewModel unconfirmedApprover : unconfirmedApprovers ) {
595- if (!isOrphaned (tangle , unconfirmedApprover , milestoneTransaction , processedTransactions )) {
593+ if (!isProbablyOrphaned (tangle , unconfirmedApprover , milestoneTransaction , processedTransactions )) {
596594 return true ;
597595 }
598596 }
@@ -610,51 +608,66 @@ private boolean isSolidEntryPoint(Tangle tangle, Hash transactionHash, Milestone
610608 * This method analyzes the old solid entry points and determines if they are still not orphaned.
611609 * </p>
612610 * <p>
613- * It simply iterates through the old solid entry points and checks them one by one. If an old solid entry point
614- * is found to still be relevant it is added to the passed in map.
611+ * It simply iterates through the old solid entry points and checks them one by one. If an old solid entry point is
612+ * found to still be relevant it is added to the passed in map.
615613 * </p>
616- *
617- * @param tangle Tangle object which acts as a database interface
614+ *
615+ * @see #processNewSolidEntryPoints to understand the definition for solid entry points
616+ * @param tangle Tangle object which acts as a database interface
618617 * @param snapshotProvider data provider for the {@link Snapshot}s that are relevant for the node
619- * @param targetMilestone milestone that is used to generate the solid entry points
618+ * @param targetMilestone milestone that is used to generate the solid entry points
620619 * @param solidEntryPoints map that is used to collect the solid entry points
621620 */
622621 private void processOldSolidEntryPoints (Tangle tangle , SnapshotProvider snapshotProvider ,
623- MilestoneViewModel targetMilestone , Map <Hash , Integer > solidEntryPoints ) {
622+ MilestoneViewModel targetMilestone , Map <Hash , Integer > solidEntryPoints ) throws SnapshotException {
624623
625624 ProgressLogger progressLogger = new IntervalProgressLogger (
626625 "Taking local snapshot [analyzing old solid entry points]" , log )
627626 .start (snapshotProvider .getInitialSnapshot ().getSolidEntryPoints ().size ());
627+ try {
628+ Snapshot initialSnapshot = snapshotProvider .getInitialSnapshot ();
629+ Map <Hash , Integer > orgSolidEntryPoints = initialSnapshot .getSolidEntryPoints ();
630+ for (Map .Entry <Hash , Integer > solidPoint : orgSolidEntryPoints .entrySet ()) {
631+ Hash hash = solidPoint .getKey ();
632+ int milestoneIndex = solidPoint .getValue ();
633+ if (!Hash .NULL_HASH .equals (hash )
634+ && targetMilestone .index () - milestoneIndex <= SOLID_ENTRY_POINT_LIFETIME
635+ && isNotOrphaned (tangle , hash , targetMilestone )) {
636+ TransactionViewModel tvm = TransactionViewModel .fromHash (tangle , hash );
637+ addTailsToSolidEntryPoints (milestoneIndex , solidEntryPoints , tvm );
638+ solidEntryPoints .put (hash , milestoneIndex );
639+ }
628640
629- Snapshot initialSnapshot = snapshotProvider .getInitialSnapshot ();
630- initialSnapshot .getSolidEntryPoints ().forEach ((hash , milestoneIndex ) -> {
631- if (!Hash .NULL_HASH .equals (hash ) && targetMilestone .index () - milestoneIndex <= SOLID_ENTRY_POINT_LIFETIME
632- && isSolidEntryPoint (tangle , hash , targetMilestone )) {
633-
634- solidEntryPoints .put (hash , milestoneIndex );
641+ progressLogger .progress ();
635642 }
636-
637- progressLogger .progress ();
638- });
639-
640- progressLogger .finish ();
643+ } catch (Exception e ) {
644+ throw new SnapshotException (
645+ "Couldn't process old solid entry point for target milestone " + targetMilestone .index (), e );
646+ } finally {
647+ progressLogger .finish ();
648+ }
641649 }
642650
643651 /**
644652 * <p>
645653 * This method retrieves the new solid entry points of the snapshot reference given by the target milestone.
646654 * </p>
647655 * <p>
656+ * A transaction is considered a solid entry point if it is a bundle tail that can be traversed down from a
657+ * non-orphaned transaction that was approved by a milestone that is above the last local snapshot. Or if it is a
658+ * bundle tail of a non-orphaned transaction that was approved by a milestone that is above the last local snapshot.
659+ *
648660 * It iterates over all unprocessed milestones and analyzes their directly and indirectly approved transactions.
649- * Every transaction is checked for being a solid entry point and added to the passed in map (if it was found to be
650- * one).
661+ * Every transaction is checked for being not orphaned and the appropriate SEP is added to {@param SolidEntryPoints}
651662 * </p>
652- *
653- * @param tangle Tangle object which acts as a database interface
663+ *
664+ *
665+ * @param tangle Tangle object which acts as a database interface
654666 * @param snapshotProvider data provider for the {@link Snapshot}s that are relevant for the node
655- * @param targetMilestone milestone that is used to generate the solid entry points
667+ * @param targetMilestone milestone that is used to generate the solid entry points
656668 * @param solidEntryPoints map that is used to collect the solid entry points
657669 * @throws SnapshotException if anything goes wrong while determining the solid entry points
670+ * @see #isNotOrphaned(Tangle, Hash, MilestoneViewModel)
658671 */
659672 private void processNewSolidEntryPoints (Tangle tangle , SnapshotProvider snapshotProvider ,
660673 MilestoneViewModel targetMilestone , Map <Hash , Integer > solidEntryPoints ) throws SnapshotException {
@@ -675,8 +688,9 @@ private void processNewSolidEntryPoints(Tangle tangle, SnapshotProvider snapshot
675688 currentMilestone .getHash (),
676689 currentTransaction -> currentTransaction .snapshotIndex () >= currentMilestone .index (),
677690 currentTransaction -> {
678- if (isSolidEntryPoint (tangle , currentTransaction .getHash (), targetMilestone )) {
679- solidEntryPoints .put (currentTransaction .getHash (), targetMilestone .index ());
691+ if (isNotOrphaned (tangle , currentTransaction .getHash (), targetMilestone )) {
692+ addTailsToSolidEntryPoints (targetMilestone .index (), solidEntryPoints ,
693+ currentTransaction );
680694 }
681695 }
682696 );
@@ -696,4 +710,15 @@ private void processNewSolidEntryPoints(Tangle tangle, SnapshotProvider snapshot
696710 throw new SnapshotException ("could not generate the solid entry points for " + targetMilestone , e );
697711 }
698712 }
713+
714+ private void addTailsToSolidEntryPoints (int milestoneIndex , Map <Hash , Integer > solidEntryPoints ,
715+ TransactionViewModel currentTransaction ) throws TraversalException {
716+ // if tail
717+ if (currentTransaction .getCurrentIndex () == 0 ) {
718+ solidEntryPoints .put (currentTransaction .getHash (), milestoneIndex );
719+ } else {
720+ Set <? extends Hash > tails = DAGHelper .get (tangle ).findTails (currentTransaction );
721+ tails .forEach (tail -> solidEntryPoints .put (tail , milestoneIndex ));
722+ }
723+ }
699724}
0 commit comments