11package net .helix .pendulum ;
22
3+ import com .google .common .cache .Cache ;
34import net .helix .pendulum .conf .PendulumConfig ;
5+ import net .helix .pendulum .controllers .BundleViewModel ;
46import net .helix .pendulum .controllers .RoundViewModel ;
57import net .helix .pendulum .controllers .TransactionViewModel ;
68import net .helix .pendulum .crypto .Sponge ;
1012import net .helix .pendulum .model .TransactionHash ;
1113import net .helix .pendulum .network .Node ;
1214import net .helix .pendulum .service .cache .TangleCache ;
15+ import net .helix .pendulum .service .snapshot .Snapshot ;
1316import net .helix .pendulum .service .snapshot .SnapshotProvider ;
1417import net .helix .pendulum .storage .Tangle ;
18+ import net .helix .pendulum .utils .PendulumUtils ;
1519import net .helix .pendulum .utils .collections .impl .BoundedLinkedListImpl ;
1620import net .helix .pendulum .utils .collections .interfaces .BoundedLinkedSet ;
1721import org .slf4j .Logger ;
2226import java .util .concurrent .ScheduledExecutorService ;
2327import java .util .concurrent .TimeUnit ;
2428import java .util .concurrent .atomic .AtomicBoolean ;
29+ import java .util .concurrent .locks .ReentrantLock ;
2530import java .util .function .Function ;
2631
2732import static net .helix .pendulum .controllers .TransactionViewModel .*;
@@ -39,7 +44,7 @@ public class TransactionValidator implements PendulumEventListener {
3944 private static final long MAX_TIMESTAMP_FUTURE = 2L * 60L * 60L ;
4045 private static final long MAX_TIMESTAMP_FUTURE_MS = MAX_TIMESTAMP_FUTURE * 1_000L ;
4146
42-
47+ private ReentrantLock lock = new ReentrantLock ( true );
4348 /////////////////////////////////fields for solidification thread//////////////////////////////////////
4449
4550 private ScheduledExecutorService scheduler = Executors .newSingleThreadScheduledExecutor ();
@@ -61,6 +66,8 @@ public class TransactionValidator implements PendulumEventListener {
6166
6267 private final AtomicBoolean forwardSolidificationDone = new AtomicBoolean (true );
6368
69+ private Cache <Hash , Integer > solidificationCache ;
70+
6471 /**
6572 * Constructor for Tangle Validator
6673 *
@@ -101,15 +108,17 @@ public void init() {
101108 TransactionViewModel parent = tangleCache .getTxVM (parentHash );
102109
103110 if (parent .getType () == PREFILLED_SLOT ) {
104- log .trace ("Missing parent, requesting {}" , parent .getHash ());
105- requestQueue .enqueueTransaction (parent .getHash (), false );
111+ if (requestQueue .enqueueTransaction (parent .getHash (), false )) {
112+ log .trace ("Missing parent, requesting {}" , parent .getHash ());
113+ }
106114 }
107115
108116 if (parent .getType () == FILLED_SLOT && !parent .isSolid ()) {
109- log .trace ("Non-solid but filled parent {}" , parent .getHash ());
110117 if (forwardSolidificationDone .get ()) {
111118 forwardSolidificationDone .set (false );
112- forwardSolidificationQueue .add (parent .getHash ());
119+ if (forwardSolidificationQueue .add (parent .getHash ())) {
120+ log .trace ("Non-solid but filled parent {}" , parent .getHash ());
121+ }
113122 }
114123 }
115124 // not important
@@ -119,19 +128,23 @@ public void init() {
119128 depthCallback = parentHash -> {
120129 TransactionViewModel parent = tangleCache .getTxVM (parentHash );
121130 if (parent .getType () == PREFILLED_SLOT ) {
122- log .trace ("Missing parent, requesting {}" , parent .getHash ());
123- requestQueue .enqueueTransaction (parent .getHash (), false );
131+ if (requestQueue .enqueueTransaction (parent .getHash (), false )) {
132+ log .trace ("Missing parent, requesting {}" , parent .getHash ());
133+ }
124134 }
125135
126136 if (parent .getType () == FILLED_SLOT && !parent .isSolid ()) {
127- log .trace ("Non-solid but filled parent {}" , parent .getHash ());
128- forwardSolidificationQueue .push (parent .getHash ());
137+ if (forwardSolidificationQueue .push (parent .getHash ())) {
138+ log .trace ("Non-solid but filled parent {}" , parent .getHash ());
139+ }
129140 forwardSolidificationDone .set (false );
130141 }
131142 // not important
132143 return null ;
133144 };
134145
146+
147+
135148 EventManager .get ().subscribe (EventType .TX_STORED , this );
136149 }
137150
@@ -294,9 +307,10 @@ public TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagni
294307 */
295308
296309 public boolean checkSolidity (Hash hash ) throws Exception {
297- TransactionViewModel txvm = fromHash (tangle , hash );
298- quickSetSolid (txvm , breadthCallback );
299- return txvm .isSolid ();
310+ if (fromHash (tangle , hash ).isSolid ()) {
311+ return true ;
312+ }
313+ return quickSetSolid (hash , breadthCallback );
300314 }
301315
302316
@@ -318,8 +332,7 @@ public void solidifyForward() {
318332 return ;
319333 }
320334 txCount ++;
321- TransactionViewModel txvm = tangleCache .getTxVM (txHash );
322- quickSetSolid (txvm , depthCallback );
335+ quickSetSolid (txHash , depthCallback );
323336 } catch (Exception e ) {
324337 log .error ("Failed to solidify" , e );
325338 }
@@ -358,14 +371,20 @@ public void solidifyBackwards() {
358371 return ;
359372 }
360373 txCount ++;
374+ if (txHash .leadingZeros () < getMinWeightMagnitude ()) {
375+ log .trace ("Skipping {}." , txHash );
376+ continue ;
377+ }
378+
361379 TransactionViewModel transaction = tangleCache .getTxVM (txHash );
362380 Set <Hash > approvers = transaction .getApprovers (tangle ).getHashes ();
363381 for (Hash h : approvers ) {
382+
364383 TransactionViewModel approver = fromHash (tangle , h );
365384 if (approver .isSolid ()) {
366385 backwardsSolidificationQueue .add (h );
367386 } else {
368- quickSetSolid (approver , breadthCallback );
387+ quickSetSolid (h , hash -> null );
369388 }
370389 }
371390 } catch (Exception e ) {
@@ -382,11 +401,13 @@ protected void addSolidTransaction(Hash hash) throws Exception {
382401 /**
383402 * Tries to solidify the transactions quickly by performing {@link #checkApproovee} on both parents (trunk and
384403 * branch). If the parents are solid, mark the transactions as solid.
385- * @param transactionViewModel transaction to solidify
404+ * @param tvmHash hash of the transaction to solidify
386405 * @return <tt>true</tt> if we made the transaction solid, else <tt>false</tt>.
387406 * @throws Exception
388407 */
389- private boolean quickSetSolid (final TransactionViewModel transactionViewModel , Function <Hash , Void > parentCallback ) throws Exception {
408+ private boolean quickSetSolid (Hash tvmHash , Function <Hash , Void > parentCallback ) throws Exception {
409+ TransactionViewModel transactionViewModel = fromHash (tangle , tvmHash );
410+
390411 if (transactionViewModel .isSolid ()) {
391412 return false ;
392413 }
@@ -398,57 +419,105 @@ private boolean quickSetSolid(final TransactionViewModel transactionViewModel, F
398419 log .trace ("Milestone solidification: {} {}" , milestoneTx .getHash ().toString (),
399420 transactionViewModel .getHash ());
400421 Set <Hash > parents = RoundViewModel .getMilestoneTrunk (tangle , transactionViewModel , milestoneTx );
401- parents .addAll (RoundViewModel .getMilestoneBranch (tangle , transactionViewModel , milestoneTx , config .getValidatorSecurity ()));
422+ if (transactionViewModel .getCurrentIndex () == transactionViewModel .lastIndex ()) {
423+ parents .addAll (RoundViewModel .getMilestoneBranch (tangle , transactionViewModel , milestoneTx , config .getValidatorSecurity ()));
424+ }
425+
426+ log .trace ("Milestone tx, adding referenced parents: {}" , PendulumUtils .logHashList (parents , 6 ));
427+
402428 for (Hash parent : parents ){
403- TransactionViewModel parentTxvm = fromHash (tangle , parent );
404- // milestones are solidified separately
405- if (!checkApproovee (parentTxvm , parentCallback )) {
429+ log .trace ("Parent ml: {}" , parent );
430+ if (!checkApproovee (parent , parentCallback )) {
406431 solid = false ;
407432 }
408-
409433 }
410434 } else {
411- TransactionViewModel [] parents = new TransactionViewModel []{
412- transactionViewModel .getTrunkTransaction ( tangle ),
413- transactionViewModel .getBranchTransaction ( tangle )
435+ Hash [] parents = new Hash []{
436+ transactionViewModel .getTrunkTransactionHash ( ),
437+ transactionViewModel .getBranchTransactionHash ( )
414438 };
415439
416- for (TransactionViewModel parentTxvm : parents ) {
417- if (!checkApproovee (parentTxvm , parentCallback )) {
440+ //if (checkParentsTxs(transactionViewModel, parents)) {
441+ // log.warn("The tx and the bundle has been deleted");
442+ // return false;
443+ //}
444+
445+ for (Hash parent : parents ) {
446+ log .trace ("Parent tx: {}" , parent );
447+ if (!checkApproovee (parent , parentCallback )) {
418448 solid = false ;
419449 }
420-
421450 }
422451 }
423452
424453 if (solid ) {
425- log .trace ("Quickly solidified: {}" , transactionViewModel .getHash ());
426- // ugly...
454+ lock .lock ();
455+ try {
456+ log .trace ("Quickly solidified: {}" , transactionViewModel .getHash ());
457+ // ugly...
458+ transactionViewModel .updateSolid (true );
459+ transactionViewModel .update (tangle , snapshotProvider .getInitialSnapshot (), "solid|height" );
460+ } finally {
461+ lock .unlock ();
462+ }
463+
464+ EventManager .get ().fire (EventType .TX_SOLIDIFIED , EventUtils .fromTxHash (transactionViewModel .getHash ()));
427465 backwardsSolidificationQueue .add (transactionViewModel .getHash ());
428- transactionViewModel .updateSolid (true );
429466 // we don't use heights atm
430467 //tvm.updateHeights(tangle, snapshotProvider.getInitialSnapshot());
431- transactionViewModel .update (tangle , snapshotProvider .getInitialSnapshot (), "solid|height" );
432- EventManager .get ().fire (EventType .TX_SOLIDIFIED , EventUtils .fromTxHash (transactionViewModel .getHash ()));
433468 return true ;
434469 }
435470
436471 return false ;
437472 }
438473
474+
475+ private boolean checkParentsTxs (TransactionViewModel transactionViewModel , Hash [] parents ) {
476+
477+ for (Hash parentHash : parents ) {
478+ if (parentHash .leadingZeros () < getMinWeightMagnitude ()) {
479+
480+ log .trace ("Invalid parent: {}\n tx: {}\n Deleting" , parentHash , transactionViewModel );
481+ try {
482+ lock .lock ();
483+ for (Hash bundleTx : BundleViewModel .load (tangle , transactionViewModel .getBundleHash ()).getHashes ()) {
484+ log .trace ("Deleting: {}" , bundleTx );
485+ fromHash (tangle , bundleTx ).delete (tangle );
486+ }
487+ transactionViewModel .delete (tangle );
488+ fromHash (tangle , parentHash ).delete (tangle );
489+ return false ;
490+ } catch (Exception e ) {
491+ log .error ("Fatal: " , e );
492+ } finally {
493+ lock .unlock ();
494+ }
495+ }
496+ }
497+ return true ;
498+ }
499+
439500 /**
440501 * If the the {@code approvee} is missing, request it from a neighbor.
441- * @param approovee transaction we check.
502+ * @param hApprovee transaction hash we check.
442503 * @return true if {@code approvee} is solid.
443504 * @throws Exception if we encounter an error while requesting a transaction
444505 */
445- private boolean checkApproovee (TransactionViewModel approovee , Function <Hash , Void > approveeCallback ) throws Exception {
446- if (snapshotProvider .getInitialSnapshot ().hasSolidEntryPoint (approovee .getHash ())) {
506+ private boolean checkApproovee (Hash hApprovee , Function <Hash , Void > approveeCallback ) throws Exception {
507+ TransactionViewModel approovee = fromHash (tangle , hApprovee );
508+ Snapshot s = snapshotProvider .getInitialSnapshot ();
509+ if (s == null ) {
510+ log .warn ("Initial snapshot is NULL" );
511+ } else if (s .hasSolidEntryPoint (approovee .getHash ())) {
447512 return true ;
448513 }
449514
450- approveeCallback .apply (approovee .getHash ());
451-
515+ if (approovee .getHash ().leadingZeros () >= minWeightMagnitude ) {
516+ approveeCallback .apply (approovee .getHash ());
517+ } else {
518+ log .trace ("Invalid mvm: {} {}" , approovee , hApprovee );
519+ return true ;
520+ }
452521 return approovee .getType () == FILLED_SLOT && approovee .isSolid ();
453522 }
454523
0 commit comments