Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 919ae1d

Browse files
authored
Merge pull request #271 from dzhelezov/refactoring
Refactoring
2 parents 4e235e4 + 64f296a commit 919ae1d

File tree

12 files changed

+255
-149
lines changed

12 files changed

+255
-149
lines changed

src/main/java/net/helix/pendulum/TransactionValidator.java

Lines changed: 107 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package net.helix.pendulum;
22

3+
import com.google.common.cache.Cache;
34
import net.helix.pendulum.conf.PendulumConfig;
5+
import net.helix.pendulum.controllers.BundleViewModel;
46
import net.helix.pendulum.controllers.RoundViewModel;
57
import net.helix.pendulum.controllers.TransactionViewModel;
68
import net.helix.pendulum.crypto.Sponge;
@@ -10,8 +12,10 @@
1012
import net.helix.pendulum.model.TransactionHash;
1113
import net.helix.pendulum.network.Node;
1214
import net.helix.pendulum.service.cache.TangleCache;
15+
import net.helix.pendulum.service.snapshot.Snapshot;
1316
import net.helix.pendulum.service.snapshot.SnapshotProvider;
1417
import net.helix.pendulum.storage.Tangle;
18+
import net.helix.pendulum.utils.PendulumUtils;
1519
import net.helix.pendulum.utils.collections.impl.BoundedLinkedListImpl;
1620
import net.helix.pendulum.utils.collections.interfaces.BoundedLinkedSet;
1721
import org.slf4j.Logger;
@@ -22,6 +26,7 @@
2226
import java.util.concurrent.ScheduledExecutorService;
2327
import java.util.concurrent.TimeUnit;
2428
import java.util.concurrent.atomic.AtomicBoolean;
29+
import java.util.concurrent.locks.ReentrantLock;
2530
import java.util.function.Function;
2631

2732
import 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

src/main/java/net/helix/pendulum/conf/BasePendulumConfig.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,8 +1036,11 @@ public interface Defaults {
10361036
HashFactory.ADDRESS.create("a5afe01e64ae959f266b382bb5927fd07b49e7e3180239535126844aaae9bf93"),
10371037
HashFactory.ADDRESS.create("e2debe246b5d1a6e05b57b0fc14edb51d136966a91a803b523586ad032f72f3d"),
10381038
HashFactory.ADDRESS.create("1895a039c85b9a5c4e822c8fc51884aedecddfa09daccef642fff697157657b4"),
1039-
HashFactory.ADDRESS.create("1c6b0ee311a7ddccf255c1097995714b285cb06628be1cef2080b0bef7700e12")
1040-
));
1039+
HashFactory.ADDRESS.create("1c6b0ee311a7ddccf255c1097995714b285cb06628be1cef2080b0bef7700e12"),
1040+
HashFactory.ADDRESS.create("fed471fc312fa64a0219d48a4718c5ec62c87ee8a3baa2ff35bf60575ca76c34"),
1041+
HashFactory.ADDRESS.create("efaff88b0eb70cc0a35bfb547a92fd5bebfc239888fda0b329e9b8020600ee0a"),
1042+
HashFactory.ADDRESS.create("79d587618297a6f8ce8b8869ff990b974d8420ad6a4dd9bebcbfed5cb05e2384")
1043+
));
10411044

10421045
long GENESIS_TIME = 1576510288107L;
10431046
int ROUND_DURATION = 45000;

src/main/java/net/helix/pendulum/controllers/RoundViewModel.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import net.helix.pendulum.storage.Persistable;
1414
import net.helix.pendulum.storage.Tangle;
1515
import net.helix.pendulum.utils.Pair;
16+
import net.helix.pendulum.utils.PendulumUtils;
1617
import net.helix.pendulum.utils.Serializer;
1718
import org.slf4j.Logger;
1819
import org.slf4j.LoggerFactory;
@@ -244,7 +245,7 @@ public static int getRoundIndex(TransactionViewModel milestoneTransaction) {
244245
}
245246

246247
// todo this may be very inefficient
247-
public static Set<Hash> getMilestoneTrunk(Tangle tangle, TransactionViewModel transaction, TransactionViewModel milestoneTx) throws Exception{
248+
public static Set<Hash> getMilestoneTrunk(Tangle tangle, TransactionViewModel transaction, TransactionViewModel milestoneTx) throws Exception{
248249
Set<Hash> trunk = new HashSet<>();
249250
// TODO: ugly hack around static methods, all methods should be non-static
250251
TangleCache cache = registry.resolve(TangleCache.class);
@@ -267,6 +268,7 @@ public static Set<Hash> getMilestoneTrunk(Tangle tangle, TransactionViewModel tr
267268
if (prevMilestones.isEmpty()) {
268269
trunk.add(Hash.NULL_HASH);
269270
} else {
271+
log.trace("Prev milestones: {}", PendulumUtils.logHashList(prevMilestones, 4));
270272
trunk.addAll(prevMilestones);
271273
}
272274

@@ -294,6 +296,7 @@ public static Set<Hash> getMilestoneBranch(Tangle tangle, TransactionViewModel t
294296
if (confirmedTips.isEmpty()){
295297
branch.add(Hash.NULL_HASH);
296298
} else {
299+
log.trace("Milestone branch: {}", PendulumUtils.logHashList(confirmedTips, 4));
297300
branch.addAll(confirmedTips);
298301
}
299302
//} else {
@@ -322,6 +325,7 @@ public static Set<Hash> getMilestoneBranch(Tangle tangle, TransactionViewModel t
322325
}
323326
}
324327
}
328+
log.trace("Milestone branch: {}", PendulumUtils.logHashList(branch, 4));
325329
return branch;
326330
}
327331

@@ -407,7 +411,7 @@ public Set<Hash> getReferencedTransactions(Tangle tangle, Set<Hash> tips) throws
407411
while ((hashPointer = nonAnalyzedTransactions.poll()) != null) {
408412
final TransactionViewModel transaction = fromHash(tangle, hashPointer);
409413
// take only transactions into account that aren't confirmed yet or that belong to the round
410-
log.trace("tx {}, tx.roundIndex {}, currentRoundIndex {}", transaction, transaction.getRoundIndex(), index());
414+
//log.trace("tx {}, tx.roundIndex {}, currentRoundIndex {}", transaction, transaction.getRoundIndex(), index());
411415
if (transaction.getRoundIndex() == 0 || transaction.getRoundIndex() == index()) {
412416
// we can add the tx to confirmed transactions, because it is a parent of confirmedTips
413417
transactions.add(hashPointer);
@@ -427,7 +431,8 @@ public Set<Hash> getReferencedTransactions(Tangle tangle, Set<Hash> tips) throws
427431
log.trace("roundIndex already set for tx {}", transaction);
428432
}
429433
}
430-
log.trace("tips: {}, parents: {}", tips, transactions);
434+
log.trace("tips: {}, parents: {}", PendulumUtils.logHashList(tips, 4),
435+
PendulumUtils.logHashList(transactions, 4));
431436
return transactions;
432437
}
433438

src/main/java/net/helix/pendulum/network/Node.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,13 @@ public interface RequestQueue extends Pendulum.Initializable {
10181018

10191019
boolean clearTransactionRequest(Hash hash);
10201020

1021-
void enqueueTransaction(Hash hash, boolean milestone);
1021+
/**
1022+
*
1023+
* @param hash Transaction to request
1024+
* @param milestone If the requested tx is a milstone
1025+
* @return <code>True</code> if the sanity checked passed and the hash has been added to the queue
1026+
*/
1027+
boolean enqueueTransaction(Hash hash, boolean milestone);
10221028

10231029
boolean isTransactionRequested(Hash transactionHash, boolean milestoneRequest);
10241030

0 commit comments

Comments
 (0)