From aa06b2e14ed9f8510cc361ae73d67313fed757ce Mon Sep 17 00:00:00 2001 From: Alon Elmaliah Date: Sat, 21 Jul 2018 23:00:50 +0300 Subject: [PATCH 01/26] replace all trit representations from int[] to byte[] fix tests accordingly. --- .../java/com/iota/iri/BundleValidator.java | 8 +- src/main/java/com/iota/iri/Milestone.java | 6 +- src/main/java/com/iota/iri/SignedFiles.java | 28 +++--- .../com/iota/iri/TransactionValidator.java | 20 ++-- .../iri/controllers/TransactionViewModel.java | 54 +++++------ src/main/java/com/iota/iri/hash/Curl.java | 16 ++-- src/main/java/com/iota/iri/hash/ISS.java | 34 +++---- .../java/com/iota/iri/hash/ISSInPlace.java | 18 ++-- src/main/java/com/iota/iri/hash/Kerl.java | 14 +-- .../java/com/iota/iri/hash/PearlDiver.java | 10 +- src/main/java/com/iota/iri/hash/Sponge.java | 4 +- src/main/java/com/iota/iri/model/Hash.java | 50 +++++----- .../java/com/iota/iri/model/HashPrefix.java | 2 +- src/main/java/com/iota/iri/service/API.java | 27 +++--- .../iota/iri/storage/FileExportProvider.java | 4 +- .../java/com/iota/iri/utils/Converter.java | 66 +++++++------- .../iota/iri/utils/MapIdentityManager.java | 4 +- .../iota/iri/TransactionValidatorTest.java | 16 ++-- .../controllers/TransactionViewModelTest.java | 91 ++++++++----------- src/test/java/com/iota/iri/hash/CurlTest.java | 12 +-- src/test/java/com/iota/iri/hash/ISSTest.java | 55 +++++------ src/test/java/com/iota/iri/hash/KerlTest.java | 63 +++++++------ .../com/iota/iri/hash/PearlDiverTest.java | 12 +-- .../iri/integration/NodeIntegrationTests.java | 20 ++-- .../java/com/iota/iri/model/HashTest.java | 14 +-- .../impl/EntryPointSelectorImplTest.java | 2 +- .../java/com/iota/iri/storage/TangleTest.java | 50 ++++------ 27 files changed, 340 insertions(+), 360 deletions(-) diff --git a/src/main/java/com/iota/iri/BundleValidator.java b/src/main/java/com/iota/iri/BundleValidator.java index d00a99be30..f9e52ead98 100644 --- a/src/main/java/com/iota/iri/BundleValidator.java +++ b/src/main/java/com/iota/iri/BundleValidator.java @@ -31,10 +31,10 @@ public static List> validate(Tangle tangle, Hash tail final Sponge curlInstance = SpongeFactory.create(SpongeFactory.Mode.KERL); final Sponge addressInstance = SpongeFactory.create(SpongeFactory.Mode.KERL); - final int[] addressTrits = new int[TransactionViewModel.ADDRESS_TRINARY_SIZE]; - final int[] bundleHashTrits = new int[TransactionViewModel.BUNDLE_TRINARY_SIZE]; - final int[] normalizedBundle = new int[Curl.HASH_LENGTH / ISS.TRYTE_WIDTH]; - final int[] digestTrits = new int[Curl.HASH_LENGTH]; + final byte[] addressTrits = new byte[TransactionViewModel.ADDRESS_TRINARY_SIZE]; + final byte[] bundleHashTrits = new byte[TransactionViewModel.BUNDLE_TRINARY_SIZE]; + final byte[] normalizedBundle = new byte[Curl.HASH_LENGTH / ISS.TRYTE_WIDTH]; + final byte[] digestTrits = new byte[Curl.HASH_LENGTH]; MAIN_LOOP: while (true) { diff --git a/src/main/java/com/iota/iri/Milestone.java b/src/main/java/com/iota/iri/Milestone.java index bc5e21c858..7bec19f472 100644 --- a/src/main/java/com/iota/iri/Milestone.java +++ b/src/main/java/com/iota/iri/Milestone.java @@ -204,10 +204,10 @@ private Validity validateMilestone(SpongeFactory.Mode mode, TransactionViewModel && transactionViewModel.getBranchTransactionHash().equals(transactionViewModel2.getTrunkTransactionHash()) && transactionViewModel.getBundleHash().equals(transactionViewModel2.getBundleHash())) { - final int[] trunkTransactionTrits = transactionViewModel.getTrunkTransactionHash().trits(); - final int[] signatureFragmentTrits = Arrays.copyOfRange(transactionViewModel.trits(), TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_OFFSET, TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_OFFSET + TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE); + final byte[] trunkTransactionTrits = transactionViewModel.getTrunkTransactionHash().trits(); + final byte[] signatureFragmentTrits = Arrays.copyOfRange(transactionViewModel.trits(), TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_OFFSET, TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_OFFSET + TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE); - final int[] merkleRoot = ISS.getMerkleRoot(mode, ISS.address(mode, ISS.digest(mode, + final byte[] merkleRoot = ISS.getMerkleRoot(mode, ISS.address(mode, ISS.digest(mode, Arrays.copyOf(ISS.normalizedBundle(trunkTransactionTrits), ISS.NUMBER_OF_FRAGMENT_CHUNKS), signatureFragmentTrits)), diff --git a/src/main/java/com/iota/iri/SignedFiles.java b/src/main/java/com/iota/iri/SignedFiles.java index ad82eb469d..30773349a0 100644 --- a/src/main/java/com/iota/iri/SignedFiles.java +++ b/src/main/java/com/iota/iri/SignedFiles.java @@ -13,16 +13,16 @@ public class SignedFiles { public static boolean isFileSignatureValid(String filename, String signatureFilename, String publicKey, int depth, int index) throws IOException { - int[] signature = digestFile(filename, SpongeFactory.create(SpongeFactory.Mode.KERL)); + byte[] signature = digestFile(filename, SpongeFactory.create(SpongeFactory.Mode.KERL)); return validateSignature(signatureFilename, publicKey, depth, index, signature); } - private static boolean validateSignature(String signatureFilename, String publicKey, int depth, int index, int[] digest) throws IOException { + private static boolean validateSignature(String signatureFilename, String publicKey, int depth, int index, byte[] digest) throws IOException { //validate signature SpongeFactory.Mode mode = SpongeFactory.Mode.CURLP81; - int[] digests = new int[0]; - int[] bundle = ISS.normalizedBundle(digest); - int[] root; + byte[] digests = new byte[0]; + byte[] bundle = ISS.normalizedBundle(digest); + byte[] root; int i; try (InputStream inputStream = SignedFiles.class.getResourceAsStream(signatureFilename); @@ -31,33 +31,33 @@ private static boolean validateSignature(String signatureFilename, String public String line; for (i = 0; i < 3 && (line = reader.readLine()) != null; i++) { - int[] lineTrits = Converter.allocateTritsForTrytes(line.length()); + byte[] lineTrits = Converter.allocateTritsForTrytes(line.length()); Converter.trits(line, lineTrits, 0); - int[] normalizedBundleFragment = Arrays.copyOfRange(bundle, i * ISS.NORMALIZED_FRAGMENT_LENGTH, (i + 1) * ISS.NORMALIZED_FRAGMENT_LENGTH); - int[] issDigest = ISS.digest(mode, normalizedBundleFragment, lineTrits); + byte[] normalizedBundleFragment = Arrays.copyOfRange(bundle, i * ISS.NORMALIZED_FRAGMENT_LENGTH, (i + 1) * ISS.NORMALIZED_FRAGMENT_LENGTH); + byte[] issDigest = ISS.digest(mode, normalizedBundleFragment, lineTrits); digests = ArrayUtils.addAll(digests, issDigest); } if ((line = reader.readLine()) != null) { - int[] lineTrits = Converter.allocateTritsForTrytes(line.length()); + byte[] lineTrits = Converter.allocateTritsForTrytes(line.length()); Converter.trits(line, lineTrits, 0); root = ISS.getMerkleRoot(mode, ISS.address(mode, digests), lineTrits, 0, index, depth); } else { root = ISS.address(mode, digests); } - int[] pubkeyTrits = Converter.allocateTritsForTrytes(publicKey.length()); + byte[] pubkeyTrits = Converter.allocateTritsForTrytes(publicKey.length()); Converter.trits(publicKey, pubkeyTrits, 0); return Arrays.equals(pubkeyTrits, root); // valid } } - private static int[] digestFile(String filename, Sponge curl) throws IOException { + private static byte[] digestFile(String filename, Sponge curl) throws IOException { try (InputStream inputStream = SignedFiles.class.getResourceAsStream(filename); BufferedReader reader = new BufferedReader((inputStream == null) ? new FileReader(filename) : new InputStreamReader(inputStream))) { - int[] buffer = new int[Curl.HASH_LENGTH * 3]; + byte[] buffer = new byte[Curl.HASH_LENGTH * 3]; reader.lines().forEach(line -> { String trytes = Converter.asciiToTrytes(line); // can return a null @@ -66,10 +66,10 @@ private static int[] digestFile(String filename, Sponge curl) throws IOException } Converter.trits(trytes, buffer, 0); curl.absorb(buffer, 0, buffer.length); - Arrays.fill(buffer, 0); + Arrays.fill(buffer, (byte) 0); }); - int[] signature = new int[Curl.HASH_LENGTH]; + byte[] signature = new byte[Curl.HASH_LENGTH]; curl.squeeze(signature, 0, Curl.HASH_LENGTH); return signature; } catch (UncheckedIOException e) { diff --git a/src/main/java/com/iota/iri/TransactionValidator.java b/src/main/java/com/iota/iri/TransactionValidator.java index a287a222b5..b4e7b81480 100644 --- a/src/main/java/com/iota/iri/TransactionValidator.java +++ b/src/main/java/com/iota/iri/TransactionValidator.java @@ -54,7 +54,7 @@ public TransactionValidator(Tangle tangle, TipsViewModel tipsViewModel, Transact public void init(boolean testnet, int mwm) { MIN_WEIGHT_MAGNITUDE = mwm; - + //lowest allowed MWM encoded in 46 bytes. if (!testnet && MIN_WEIGHT_MAGNITUDE<13){ MIN_WEIGHT_MAGNITUDE = 13; @@ -104,14 +104,14 @@ public static void runValidation(TransactionViewModel transactionViewModel, fina } } - public static TransactionViewModel validate(final int[] trits, int minWeightMagnitude) { - TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81))); - runValidation(transactionViewModel, minWeightMagnitude); - return transactionViewModel; - } - public static TransactionViewModel validate(final byte[] bytes, int minWeightMagnitude) { - return validate(bytes, minWeightMagnitude, SpongeFactory.create(SpongeFactory.Mode.CURLP81)); - + public static TransactionViewModel validate(final byte[] trits, int minWeightMagnitude) { + if(trits.length == 8019) { + TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81))); + runValidation(transactionViewModel, minWeightMagnitude); + return transactionViewModel; + } else { + return validate(trits, minWeightMagnitude, SpongeFactory.create(SpongeFactory.Mode.CURLP81)); + } } public static TransactionViewModel validate(final byte[] bytes, int minWeightMagnitude, Sponge curl) { @@ -186,7 +186,7 @@ private Runnable spawnSolidTransactionsPropagation() { for(Hash h: approvers) { TransactionViewModel tx = TransactionViewModel.fromHash(tangle, h); if(quietQuickSetSolid(tx)) { - tx.update(tangle, "solid"); + tx.update(tangle, "solid"); } else { if (transaction.isSolid()) { addSolidTransaction(hash); diff --git a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java index 823de7302d..8b20a5aaae 100644 --- a/src/main/java/com/iota/iri/controllers/TransactionViewModel.java +++ b/src/main/java/com/iota/iri/controllers/TransactionViewModel.java @@ -51,7 +51,7 @@ public class TransactionViewModel { public final static int PREFILLED_SLOT = 1; // means that we know only hash of the tx, the rest is unknown yet: only another tx references that hash public final static int FILLED_SLOT = -1; // knows the hash only coz another tx references that hash - private int[] trits; + private byte[] trits; public int weightMagnitude; public static void fillMetadata(Tangle tangle, TransactionViewModel transactionViewModel) throws Exception { @@ -85,29 +85,29 @@ public TransactionViewModel(final Transaction transaction, final Hash hash) { weightMagnitude = this.hash.trailingZeros(); } - public TransactionViewModel(final int[] trits, Hash hash) { - transaction = new com.iota.iri.model.Transaction(); - this.trits = new int[trits.length]; - System.arraycopy(trits, 0, this.trits, 0, trits.length); - transaction.bytes = Converter.allocateBytesForTrits(trits.length); - Converter.bytes(trits, 0, transaction.bytes, 0, trits.length); - this.hash = hash; + public TransactionViewModel(final byte[] trits, Hash hash) { + if(trits.length == 8019) { + transaction = new com.iota.iri.model.Transaction(); + this.trits = new byte[trits.length]; + System.arraycopy(trits, 0, this.trits, 0, trits.length); + transaction.bytes = Converter.allocateBytesForTrits(trits.length); + Converter.bytes(trits, 0, transaction.bytes, 0, trits.length); + this.hash = hash; - transaction.type = FILLED_SLOT; + transaction.type = FILLED_SLOT; - weightMagnitude = this.hash.trailingZeros(); - transaction.validity = 0; - transaction.arrivalTime = 0; - } - - - public TransactionViewModel(final byte[] bytes, Hash hash) throws RuntimeException { - transaction = new Transaction(); - transaction.bytes = new byte[SIZE]; - System.arraycopy(bytes, 0, transaction.bytes, 0, SIZE); - this.hash = hash; - weightMagnitude = this.hash.trailingZeros(); - transaction.type = FILLED_SLOT; + weightMagnitude = this.hash.trailingZeros(); + transaction.validity = 0; + transaction.arrivalTime = 0; + } + else { + transaction = new Transaction(); + transaction.bytes = new byte[SIZE]; + System.arraycopy(trits, 0, transaction.bytes, 0, SIZE); + this.hash = hash; + weightMagnitude = this.hash.trailingZeros(); + transaction.type = FILLED_SLOT; + } } public static int getNumberOfStoredTransactions(Tangle tangle) throws Exception { @@ -143,16 +143,16 @@ public TransactionViewModel getTrunkTransaction(Tangle tangle) throws Exception return trunk; } - public static int[] trits(byte[] transactionBytes) { - int[] trits; - trits = new int[TRINARY_SIZE]; + public static byte[] trits(byte[] transactionBytes) { + byte[] trits; + trits = new byte[TRINARY_SIZE]; if(transactionBytes != null) { Converter.getTrits(transactionBytes, trits); } return trits; } - public synchronized int[] trits() { + public synchronized byte[] trits() { return (trits == null) ? (trits = trits(transaction.bytes)) : trits; } @@ -329,7 +329,7 @@ public long getCurrentIndex() { return transaction.currentIndex; } - public int[] getSignature() { + public byte[] getSignature() { return Arrays.copyOfRange(trits(), SIGNATURE_MESSAGE_FRAGMENT_TRINARY_OFFSET, SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE); } diff --git a/src/main/java/com/iota/iri/hash/Curl.java b/src/main/java/com/iota/iri/hash/Curl.java index a50e88b155..6cc51188f1 100644 --- a/src/main/java/com/iota/iri/hash/Curl.java +++ b/src/main/java/com/iota/iri/hash/Curl.java @@ -20,7 +20,7 @@ public class Curl implements Sponge { private static final int STATE_LENGTH = 3 * HASH_LENGTH; private static final int HALF_LENGTH = 364; - private static final int[] TRUTH_TABLE = {1, 0, -1, 2, 1, -1, 0, 2, -1, 1, 0}; + private static final byte[] TRUTH_TABLE = {1, 0, -1, 2, 1, -1, 0, 2, -1, 1, 0}; /* private static final IntPair[] TRANSFORM_INDICES = IntStream.range(0, STATE_LENGTH) .mapToObj(i -> new IntPair(i == 0 ? 0 : (((i - 1) % 2) + 1) * HALF_LENGTH - ((i - 1) >> 1), @@ -28,11 +28,11 @@ public class Curl implements Sponge { .toArray(IntPair[]::new); */ - private final int[] state; + private final byte[] state; private final long[] stateLow; private final long[] stateHigh; - private final int[] scratchpad = new int[STATE_LENGTH]; + private final byte[] scratchpad = new byte[STATE_LENGTH]; protected Curl(SpongeFactory.Mode mode) { @@ -45,7 +45,7 @@ protected Curl(SpongeFactory.Mode mode) { } break; default: throw new NoSuchElementException("Only Curl-P-27 and Curl-P-81 are supported."); } - state = new int[STATE_LENGTH]; + state = new byte[STATE_LENGTH]; stateHigh = null; stateLow = null; } @@ -66,7 +66,7 @@ public Curl(boolean pair, SpongeFactory.Mode mode) { state = null; set(); } else { - state = new int[STATE_LENGTH]; + state = new byte[STATE_LENGTH]; stateHigh = null; stateLow = null; } @@ -76,7 +76,7 @@ private void setMode(SpongeFactory.Mode mode) { } - public void absorb(final int[] trits, int offset, int length) { + public void absorb(final byte[] trits, int offset, int length) { do { System.arraycopy(trits, offset, state, 0, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -86,7 +86,7 @@ public void absorb(final int[] trits, int offset, int length) { } - public void squeeze(final int[] trits, int offset, int length) { + public void squeeze(final byte[] trits, int offset, int length) { do { System.arraycopy(state, 0, trits, offset, length < HASH_LENGTH ? length : HASH_LENGTH); @@ -113,7 +113,7 @@ private void transform() { } } public void reset() { - Arrays.fill(state, 0); + Arrays.fill(state, (byte) 0); } public void reset(boolean pair) { if(pair) { diff --git a/src/main/java/com/iota/iri/hash/ISS.java b/src/main/java/com/iota/iri/hash/ISS.java index bd51586fd0..9d8124fec3 100644 --- a/src/main/java/com/iota/iri/hash/ISS.java +++ b/src/main/java/com/iota/iri/hash/ISS.java @@ -18,13 +18,13 @@ public class ISS { private static final int MIN_TRYTE_VALUE = -13, MAX_TRYTE_VALUE = 13; public static final int NORMALIZED_FRAGMENT_LENGTH = Curl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS; - public static int[] subseed(SpongeFactory.Mode mode, final int[] seed, int index) { + public static byte[] subseed(SpongeFactory.Mode mode, final byte[] seed, int index) { if (index < 0) { throw new RuntimeException("Invalid subseed index: " + index); } - final int[] subseedPreimage = Arrays.copyOf(seed, seed.length); + final byte[] subseedPreimage = Arrays.copyOf(seed, seed.length); while (index-- > 0) { @@ -38,7 +38,7 @@ public static int[] subseed(SpongeFactory.Mode mode, final int[] seed, int index } } - final int[] subseed = new int[Curl.HASH_LENGTH]; + final byte[] subseed = new byte[Curl.HASH_LENGTH]; final Sponge hash = SpongeFactory.create(mode); hash.absorb(subseedPreimage, 0, subseedPreimage.length); @@ -46,7 +46,7 @@ public static int[] subseed(SpongeFactory.Mode mode, final int[] seed, int index return subseed; } - public static int[] key(SpongeFactory.Mode mode, final int[] subseed, final int numberOfFragments) { + public static byte[] key(SpongeFactory.Mode mode, final byte[] subseed, final int numberOfFragments) { if (subseed.length != Curl.HASH_LENGTH) { throw new RuntimeException("Invalid subseed length: " + subseed.length); @@ -55,7 +55,7 @@ public static int[] key(SpongeFactory.Mode mode, final int[] subseed, final int throw new RuntimeException("Invalid number of key fragments: " + numberOfFragments); } - final int[] key = new int[FRAGMENT_LENGTH * numberOfFragments]; + final byte[] key = new byte[FRAGMENT_LENGTH * numberOfFragments]; final Sponge hash = SpongeFactory.create(mode); hash.absorb(subseed, 0, subseed.length); @@ -63,18 +63,18 @@ public static int[] key(SpongeFactory.Mode mode, final int[] subseed, final int return key; } - public static int[] digests(SpongeFactory.Mode mode, final int[] key) { + public static byte[] digests(SpongeFactory.Mode mode, final byte[] key) { if (key.length == 0 || key.length % FRAGMENT_LENGTH != 0) { throw new RuntimeException("Invalid key length: " + key.length); } - final int[] digests = new int[key.length / FRAGMENT_LENGTH * Curl.HASH_LENGTH]; + final byte[] digests = new byte[key.length / FRAGMENT_LENGTH * Curl.HASH_LENGTH]; final Sponge hash = SpongeFactory.create(mode); for (int i = 0; i < key.length / FRAGMENT_LENGTH; i++) { - final int[] buffer = Arrays.copyOfRange(key, i * FRAGMENT_LENGTH, (i + 1) * FRAGMENT_LENGTH); + final byte[] buffer = Arrays.copyOfRange(key, i * FRAGMENT_LENGTH, (i + 1) * FRAGMENT_LENGTH); for (int j = 0; j < NUMBER_OF_FRAGMENT_CHUNKS; j++) { for (int k = MAX_TRYTE_VALUE - MIN_TRYTE_VALUE; k-- > 0; ) { @@ -91,13 +91,13 @@ public static int[] digests(SpongeFactory.Mode mode, final int[] key) { return digests; } - public static int[] address(SpongeFactory.Mode mode, final int[] digests) { + public static byte[] address(SpongeFactory.Mode mode, final byte[] digests) { if (digests.length == 0 || digests.length % Curl.HASH_LENGTH != 0) { throw new RuntimeException("Invalid digests length: " + digests.length); } - final int[] address = new int[Curl.HASH_LENGTH]; + final byte[] address = new byte[Curl.HASH_LENGTH]; final Sponge hash = SpongeFactory.create(mode); hash.absorb(digests, 0, digests.length); @@ -106,19 +106,19 @@ public static int[] address(SpongeFactory.Mode mode, final int[] digests) { return address; } - public static int[] normalizedBundle(final int[] bundle) { + public static byte[] normalizedBundle(final byte[] bundle) { if (bundle.length != Curl.HASH_LENGTH) { throw new RuntimeException("Invalid bundleValidator length: " + bundle.length); } - final int[] normalizedBundle = new int[Curl.HASH_LENGTH / TRYTE_WIDTH]; + final byte[] normalizedBundle = new byte[Curl.HASH_LENGTH / TRYTE_WIDTH]; ISSInPlace.normalizedBundle(bundle, normalizedBundle); return normalizedBundle; } - public static int[] signatureFragment(SpongeFactory.Mode mode, final int[] normalizedBundleFragment, final int[] keyFragment) { + public static byte[] signatureFragment(SpongeFactory.Mode mode, final byte[] normalizedBundleFragment, final byte[] keyFragment) { if (normalizedBundleFragment.length != NORMALIZED_FRAGMENT_LENGTH) { throw new RuntimeException("Invalid normalized bundleValidator fragment length: " + normalizedBundleFragment.length); @@ -127,7 +127,7 @@ public static int[] signatureFragment(SpongeFactory.Mode mode, final int[] norma throw new RuntimeException("Invalid key fragment length: " + keyFragment.length); } - final int[] signatureFragment = Arrays.copyOf(keyFragment, keyFragment.length); + final byte[] signatureFragment = Arrays.copyOf(keyFragment, keyFragment.length); final Sponge hash = SpongeFactory.create(mode); for (int j = 0; j < NUMBER_OF_FRAGMENT_CHUNKS; j++) { @@ -142,7 +142,7 @@ public static int[] signatureFragment(SpongeFactory.Mode mode, final int[] norma return signatureFragment; } - public static int[] digest(SpongeFactory.Mode mode, final int[] normalizedBundleFragment, final int[] signatureFragment) { + public static byte[] digest(SpongeFactory.Mode mode, final byte[] normalizedBundleFragment, final byte[] signatureFragment) { if (normalizedBundleFragment.length != Curl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS) { throw new RuntimeException("Invalid normalized bundleValidator fragment length: " + normalizedBundleFragment.length); @@ -151,12 +151,12 @@ public static int[] digest(SpongeFactory.Mode mode, final int[] normalizedBundle throw new RuntimeException("Invalid signature fragment length: " + signatureFragment.length); } - final int[] digest = new int[Curl.HASH_LENGTH]; + final byte[] digest = new byte[Curl.HASH_LENGTH]; ISSInPlace.digest(mode, normalizedBundleFragment, 0, signatureFragment, 0, digest); return digest; } - public static int[] getMerkleRoot(SpongeFactory.Mode mode, int[] hash, int[] trits, int offset, final int indexIn, int size) { + public static byte[] getMerkleRoot(SpongeFactory.Mode mode, byte[] hash, byte[] trits, int offset, final int indexIn, int size) { int index = indexIn; final Sponge curl = SpongeFactory.create(mode); for (int i = 0; i < size; i++) { diff --git a/src/main/java/com/iota/iri/hash/ISSInPlace.java b/src/main/java/com/iota/iri/hash/ISSInPlace.java index 8e7691d197..39a61e9ccb 100644 --- a/src/main/java/com/iota/iri/hash/ISSInPlace.java +++ b/src/main/java/com/iota/iri/hash/ISSInPlace.java @@ -16,7 +16,7 @@ public class ISSInPlace { private static final int MIN_TRIT_VALUE = -1, MAX_TRIT_VALUE = 1; private static final int MIN_TRYTE_VALUE = -13, MAX_TRYTE_VALUE = 13; - public static void subseed(SpongeFactory.Mode mode, int[] subseed, int index) { + public static void subseed(SpongeFactory.Mode mode, byte[] subseed, int index) { if (index < 0) { throw new RuntimeException("Invalid subseed index: " + index); @@ -43,7 +43,7 @@ public static void subseed(SpongeFactory.Mode mode, int[] subseed, int index) { hash.squeeze(subseed, 0, subseed.length); } - public static void key(SpongeFactory.Mode mode, final int[] subseed, int[] key) { + public static void key(SpongeFactory.Mode mode, final byte[] subseed, byte[] key) { if (subseed.length != Kerl.HASH_LENGTH) { throw new RuntimeException("Invalid subseed length: " + subseed.length); @@ -64,7 +64,7 @@ public static void key(SpongeFactory.Mode mode, final int[] subseed, int[] key) hash.squeeze(key, 0, key.length); } - public static void digests(SpongeFactory.Mode mode, final int[] key, int[] digests) { + public static void digests(SpongeFactory.Mode mode, final byte[] key, byte[] digests) { if (key.length == 0 || key.length % FRAGMENT_LENGTH != 0) { throw new RuntimeException("Invalid key length: " + key.length); @@ -78,7 +78,7 @@ public static void digests(SpongeFactory.Mode mode, final int[] key, int[] diges for (int i = 0; i < key.length / FRAGMENT_LENGTH; i++) { - final int[] buffer = Arrays.copyOfRange(key, i * FRAGMENT_LENGTH, (i + 1) * FRAGMENT_LENGTH); + final byte[] buffer = Arrays.copyOfRange(key, i * FRAGMENT_LENGTH, (i + 1) * FRAGMENT_LENGTH); for (int j = 0; j < NUMBER_OF_FRAGMENT_CHUNKS; j++) { for (int k = MAX_TRYTE_VALUE - MIN_TRYTE_VALUE; k-- > 0; ) { @@ -93,7 +93,7 @@ public static void digests(SpongeFactory.Mode mode, final int[] key, int[] diges } } - public static void address(SpongeFactory.Mode mode, final int[] digests, int[] address) { + public static void address(SpongeFactory.Mode mode, final byte[] digests, byte[] address) { if (digests.length == 0 || digests.length % Kerl.HASH_LENGTH != 0) { throw new RuntimeException("Invalid digests length: " + digests.length); @@ -109,7 +109,7 @@ public static void address(SpongeFactory.Mode mode, final int[] digests, int[] a } - public static void digest(SpongeFactory.Mode mode, final int[] normalizedBundleFragment, int nbOff, final int[] signatureFragment, int sfOff, int[] digest) { + public static void digest(SpongeFactory.Mode mode, final byte[] normalizedBundleFragment, int nbOff, final byte[] signatureFragment, int sfOff, byte[] digest) { if (normalizedBundleFragment.length - nbOff < (Curl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS)) { throw new RuntimeException("Invalid normalized bundleValidator fragment length: " + normalizedBundleFragment.length); @@ -122,7 +122,7 @@ public static void digest(SpongeFactory.Mode mode, final int[] normalizedBundleF throw new IllegalArgumentException("Invalid digest array length."); } - final int[] buffer = Arrays.copyOfRange(signatureFragment, sfOff, sfOff + FRAGMENT_LENGTH); + final byte[] buffer = Arrays.copyOfRange(signatureFragment, sfOff, sfOff + FRAGMENT_LENGTH); final Sponge hash = SpongeFactory.create(mode); for (int j = 0; j < NUMBER_OF_FRAGMENT_CHUNKS; j++) { @@ -139,7 +139,7 @@ public static void digest(SpongeFactory.Mode mode, final int[] normalizedBundleF } - public static void normalizedBundle(final int[] bundle, int[] normalizedBundle) { + public static void normalizedBundle(final byte[] bundle, byte[] normalizedBundle) { if (bundle.length != Curl.HASH_LENGTH) { throw new RuntimeException("Invalid bundleValidator length: " + bundle.length); } @@ -148,7 +148,7 @@ public static void normalizedBundle(final int[] bundle, int[] normalizedBundle) int sum = 0; for (int j = i * (Curl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS); j < (i + 1) * (Curl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS); j++) { - normalizedBundle[j] = bundle[j * TRYTE_WIDTH] + bundle[j * TRYTE_WIDTH + 1] * 3 + bundle[j * TRYTE_WIDTH + 2] * 9; + normalizedBundle[j] = (byte) (bundle[j * TRYTE_WIDTH] + bundle[j * TRYTE_WIDTH + 1] * 3 + bundle[j * TRYTE_WIDTH + 2] * 9); sum += normalizedBundle[j]; } if (sum > 0) { diff --git a/src/main/java/com/iota/iri/hash/Kerl.java b/src/main/java/com/iota/iri/hash/Kerl.java index 9ae1bf82f9..594905b280 100644 --- a/src/main/java/com/iota/iri/hash/Kerl.java +++ b/src/main/java/com/iota/iri/hash/Kerl.java @@ -29,7 +29,7 @@ public void reset() { } @Override - public void absorb(final int[] trits, final int offset, final int length) { + public void absorb(final byte[] trits, final int offset, final int length) { if (length % 243 != 0) { throw new RuntimeException("Illegal length: " + length); } @@ -43,7 +43,7 @@ public void absorb(final int[] trits, final int offset, final int length) { } @Override - public void squeeze(final int[] trits, final int offset, final int length) { + public void squeeze(final byte[] trits, final int offset, final int length) { if (length % 243 != 0) { throw new IllegalArgumentException("Illegal length: " + length); } @@ -70,7 +70,7 @@ public void squeeze(final int[] trits, final int offset, final int length) { } } - public static BigInteger bigIntFromTrits(final int[] trits, final int offset, final int size) { + public static BigInteger bigIntFromTrits(final byte[] trits, final int offset, final int size) { for (int i = offset; i < offset + size; i++) { if (trits[i] < -1 || trits[i] > 1) { throw new IllegalArgumentException("not a trit: " + trits[i]); @@ -89,14 +89,14 @@ public static BigInteger bigIntFromTrits(final int[] trits, final int offset, fi return value; } - public static void tritsFromBigInt(final BigInteger value, final int[] destination, final int offset, final int size) { + public static void tritsFromBigInt(final BigInteger value, final byte[] destination, final int offset, final int size) { if (destination.length - offset < size) { throw new IllegalArgumentException("Destination array has invalid size"); } final int signum = value.signum(); if (signum == 0) { - Arrays.fill(destination, offset, size, 0); + Arrays.fill(destination, offset, size, (byte) 0); return; } BigInteger absoluteValue = value.abs(); @@ -104,12 +104,12 @@ public static void tritsFromBigInt(final BigInteger value, final int[] destinati BigInteger[] divRemainder = absoluteValue.divideAndRemainder(RADIX); absoluteValue = divRemainder[0]; - int remainder = divRemainder[1].intValue(); + byte remainder = divRemainder[1].byteValue(); if (remainder > Converter.MAX_TRIT_VALUE) { remainder = Converter.MIN_TRIT_VALUE; absoluteValue = absoluteValue.add(BigInteger.ONE); } - destination[offset + i] = signum < 0 ? -remainder : remainder; + destination[offset + i] = signum < 0 ? (byte) -remainder : remainder; } } diff --git a/src/main/java/com/iota/iri/hash/PearlDiver.java b/src/main/java/com/iota/iri/hash/PearlDiver.java index 6ff37fde86..6f91bce261 100644 --- a/src/main/java/com/iota/iri/hash/PearlDiver.java +++ b/src/main/java/com/iota/iri/hash/PearlDiver.java @@ -30,7 +30,7 @@ public void cancel() { } } - private static void validateParameters(int[] transactionTrits, int minWeightMagnitude) { + private static void validateParameters(byte[] transactionTrits, int minWeightMagnitude) { if (transactionTrits.length != TRANSACTION_LENGTH) { throw new RuntimeException( "Invalid transaction trits length: " + transactionTrits.length); @@ -40,7 +40,7 @@ private static void validateParameters(int[] transactionTrits, int minWeightMagn } } - public synchronized boolean search(final int[] transactionTrits, final int minWeightMagnitude, + public synchronized boolean search(final byte[] transactionTrits, final int minWeightMagnitude, int numberOfThreads) { validateParameters(transactionTrits, minWeightMagnitude); @@ -79,7 +79,7 @@ public synchronized boolean search(final int[] transactionTrits, final int minWe return state == COMPLETED; } - private Runnable getRunnable(final int threadIndex, final int[] transactionTrits, final int minWeightMagnitude, + private Runnable getRunnable(final int threadIndex, final byte[] transactionTrits, final int minWeightMagnitude, final long[] midStateCopyLow, final long[] midStateCopyHigh) { return () -> { for (int i = 0; i < threadIndex; i++) { @@ -119,7 +119,7 @@ private Runnable getRunnable(final int threadIndex, final int[] transactionTrits for (int i = 0; i < CURL_HASH_LENGTH; i++) { transactionTrits[TRANSACTION_LENGTH - CURL_HASH_LENGTH + i] = (midStateCopyLow[i] & outMask) == 0 ? 1 - : (midStateCopyHigh[i] & outMask) == 0 ? -1 : 0; + : (midStateCopyHigh[i] & outMask) == 0 ? (byte) -1 : (byte) 0; } } } @@ -132,7 +132,7 @@ private static void copy(long[] srcLow, long[] srcHigh, long[] destLow, long[] d System.arraycopy(srcHigh, 0, destHigh, 0, CURL_STATE_LENGTH); } - private static void initializeMidCurlStates(int[] transactionTrits, long[] midStateLow, long[] midStateHigh) { + private static void initializeMidCurlStates(byte[] transactionTrits, long[] midStateLow, long[] midStateHigh) { for (int i = CURL_HASH_LENGTH; i < CURL_STATE_LENGTH; i++) { midStateLow[i] = HIGH_BITS; midStateHigh[i] = HIGH_BITS; diff --git a/src/main/java/com/iota/iri/hash/Sponge.java b/src/main/java/com/iota/iri/hash/Sponge.java index 00e85b628b..ba9190aa1f 100644 --- a/src/main/java/com/iota/iri/hash/Sponge.java +++ b/src/main/java/com/iota/iri/hash/Sponge.java @@ -3,7 +3,7 @@ public interface Sponge { int HASH_LENGTH = 243; - void absorb(final int[] trits, int offset, int length); - void squeeze(final int[] trits, int offset, int length); + void absorb(final byte[] trits, int offset, int length); + void squeeze(final byte[] trits, int offset, int length); void reset(); } diff --git a/src/main/java/com/iota/iri/model/Hash.java b/src/main/java/com/iota/iri/model/Hash.java index 4b0559f78a..f8e8bd5ccf 100644 --- a/src/main/java/com/iota/iri/model/Hash.java +++ b/src/main/java/com/iota/iri/model/Hash.java @@ -16,7 +16,7 @@ public final class Hash implements Serializable, Indexable, HashId { public static final int SIZE_IN_TRITS = 243; public static final int SIZE_IN_BYTES = 49; - public static final Hash NULL_HASH = new Hash(new int[Curl.HASH_LENGTH]); + public static final Hash NULL_HASH = new Hash(new byte[Curl.HASH_LENGTH]); private final Object lock = new Object(); private ByteSafe byteSafe; @@ -34,59 +34,57 @@ private ByteSafe(byte[] bytes) { } private final class TritSafe { - private final int[] trits; + private final byte[] trits; - private TritSafe(int[] trits) { + private TritSafe(byte[] trits) { this.trits = Objects.requireNonNull(trits, "TritSafe is attempted to be initialized with a null int array"); } } - public static Hash calculate(SpongeFactory.Mode mode, int[] trits) { + public static Hash calculate(SpongeFactory.Mode mode, byte[] trits) { return calculate(trits, 0, trits.length, SpongeFactory.create(mode)); } public static Hash calculate(byte[] bytes, int tritsLength, final Sponge curl) { - int[] trits = new int[tritsLength]; + byte[] trits = new byte[tritsLength]; Converter.getTrits(bytes, trits); return calculate(trits, 0, tritsLength, curl); } - public static Hash calculate(final int[] tritsToCalculate, int offset, int length, final Sponge curl) { - int[] hashTrits = new int[SIZE_IN_TRITS]; + public static Hash calculate(final byte[] tritsToCalculate, int offset, int length, final Sponge curl) { + byte[] hashTrits = new byte[SIZE_IN_TRITS]; curl.reset(); curl.absorb(tritsToCalculate, offset, length); curl.squeeze(hashTrits, 0, SIZE_IN_TRITS); return new Hash(hashTrits); } - public Hash() { } - public Hash(final byte[] source, final int sourceOffset, final int sourceSize) { - byte[] dest = new byte[SIZE_IN_BYTES]; - System.arraycopy(source, sourceOffset, dest, 0, sourceSize - sourceOffset > source.length ? source.length - sourceOffset : sourceSize); - this.byteSafe = new ByteSafe(dest); + if(sourceSize < SIZE_IN_TRITS) { + byte[] dest = new byte[SIZE_IN_BYTES]; + System.arraycopy(source, sourceOffset, dest, 0, sourceSize - sourceOffset > source.length ? source.length - sourceOffset : sourceSize); + this.byteSafe = new ByteSafe(dest); + } else { + byte[] dest = new byte[SIZE_IN_TRITS]; + System.arraycopy(source, sourceOffset, dest, 0, dest.length); + this.tritSafe = new TritSafe(dest); + } } public Hash(final byte[] bytes) { - this(bytes, 0, SIZE_IN_BYTES); - } - - public Hash(final int[] trits, final int offset) { - int[] dest = new int[SIZE_IN_TRITS]; - System.arraycopy(trits, offset, dest, 0, dest.length); - this.tritSafe = new TritSafe(dest); + this(bytes, 0, bytes.length == 243 ? SIZE_IN_TRITS : SIZE_IN_BYTES); } - public Hash(final int[] trits) { - this(trits, 0); + public Hash(final byte[] trits, final int offset) { + this(trits, offset, SIZE_IN_TRITS); } public Hash(final String trytes) { - this.tritSafe = new TritSafe(new int[SIZE_IN_TRITS]); + this.tritSafe = new TritSafe(new byte[SIZE_IN_TRITS]); Converter.trits(trytes, this.tritSafe.trits, 0); } @@ -104,7 +102,7 @@ private void fullRead(byte[] src) { } public int trailingZeros() { - final int[] trits = trits(); + final byte[] trits = trits(); int index = SIZE_IN_TRITS; int zeros = 0; while (index-- > 0 && trits[index] == 0) { @@ -113,14 +111,14 @@ public int trailingZeros() { return zeros; } - public int[] trits() { + public byte[] trits() { TritSafe safe = tritSafe; if (safe == null) { synchronized (lock) { if (tritSafe == null) { Objects.requireNonNull(byteSafe, "I need my bytes to be initialized in order to construct trits."); byte[] src = bytes(); - int[] dest = new int[Curl.HASH_LENGTH]; + byte[] dest = new byte[Curl.HASH_LENGTH]; Converter.getTrits(src, dest); tritSafe = new TritSafe(dest); } @@ -159,7 +157,7 @@ public byte[] bytes() { synchronized (lock) { if (byteSafe == null) { Objects.requireNonNull(tritSafe, "I need my trits to be initialized in order to construct bytes."); - int[] src = trits(); + byte[] src = trits(); byte[] dest = new byte[SIZE_IN_BYTES]; Converter.bytes(src, 0, dest, 0, src.length); byteSafe = new ByteSafe(dest); diff --git a/src/main/java/com/iota/iri/model/HashPrefix.java b/src/main/java/com/iota/iri/model/HashPrefix.java index 8eeb83c93e..0f2b21d15c 100644 --- a/src/main/java/com/iota/iri/model/HashPrefix.java +++ b/src/main/java/com/iota/iri/model/HashPrefix.java @@ -54,7 +54,7 @@ public String toString() { } private static String trytes(byte[] bytes) { - int[] dest = new int[Curl.HASH_LENGTH]; + byte[] dest = new byte[Curl.HASH_LENGTH]; Converter.getTrits(bytes, dest); return Converter.trytes(dest); } diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java index c796e8c24c..53a2055e65 100644 --- a/src/main/java/com/iota/iri/service/API.java +++ b/src/main/java/com/iota/iri/service/API.java @@ -49,6 +49,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.IntStream; import static io.undertow.Handlers.path; @@ -609,7 +610,7 @@ private synchronized AbstractResponse getTipsStatement() throws Exception { public void storeTransactionStatement(final List trys) throws Exception { final List elements = new LinkedList<>(); - int[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); + byte[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); for (final String trytes : trys) { //validate all trytes Converter.trits(trytes, txTrits, 0); @@ -636,7 +637,7 @@ private AbstractResponse getNewInclusionStateStatement(final List trans, final List transactions = trans.stream().map(Hash::new).collect(Collectors.toList()); final List tips = tps.stream().map(Hash::new).collect(Collectors.toList()); int numberOfNonMetTransactions = transactions.size(); - final int[] inclusionStates = new int[numberOfNonMetTransactions]; + final byte[] inclusionStates = new byte[numberOfNonMetTransactions]; List tipsIndex = new LinkedList<>(); { @@ -701,7 +702,7 @@ private AbstractResponse getNewInclusionStateStatement(final List trans, return GetInclusionStatesResponse.create(inclusionStatesBoolean); } } - private boolean exhaustiveSearchWithinIndex(Queue nonAnalyzedTransactions, Set analyzedTips, List transactions, int[] inclusionStates, int count, int index) throws Exception { + private boolean exhaustiveSearchWithinIndex(Queue nonAnalyzedTransactions, Set analyzedTips, List transactions, byte[] inclusionStates, int count, int index) throws Exception { Hash pointer; MAIN_LOOP: while ((pointer = nonAnalyzedTransactions.poll()) != null) { @@ -829,7 +830,7 @@ private HashSet getParameterAsSet(Map request, String pa public void broadcastTransactionStatement(final List trytes2) { final List elements = new LinkedList<>(); - int[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); + byte[] txTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); for (final String tryte : trytes2) { //validate all trytes Converter.trits(tryte, txTrits, 0); @@ -917,7 +918,7 @@ public synchronized List attachToTangleStatement(final Hash trunkTransac Hash prevTransaction = null; pearlDiver = new PearlDiver(); - int[] transactionTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); + byte[] transactionTrits = Converter.allocateTritsForTrytes(TRYTES_SIZE); for (final String tryte : trytes) { long startTime = System.nanoTime(); @@ -934,10 +935,10 @@ public synchronized List attachToTangleStatement(final Hash trunkTransac //attachment fields: tag and timestamps //tag - copy the obsolete tag to the attachment tag field only if tag isn't set. - if(Arrays.stream(transactionTrits, TransactionViewModel.TAG_TRINARY_OFFSET, TransactionViewModel.TAG_TRINARY_OFFSET + TransactionViewModel.TAG_TRINARY_SIZE).allMatch(s -> s == 0)) { + if(IntStream.range(TransactionViewModel.TAG_TRINARY_OFFSET, TransactionViewModel.TAG_TRINARY_OFFSET + TransactionViewModel.TAG_TRINARY_SIZE).allMatch(idx -> transactionTrits[idx] == ((byte) 0))) { System.arraycopy(transactionTrits, TransactionViewModel.OBSOLETE_TAG_TRINARY_OFFSET, - transactionTrits, TransactionViewModel.TAG_TRINARY_OFFSET, - TransactionViewModel.TAG_TRINARY_SIZE); + transactionTrits, TransactionViewModel.TAG_TRINARY_OFFSET, + TransactionViewModel.TAG_TRINARY_SIZE); } Converter.copyTrits(timestamp,transactionTrits,TransactionViewModel.ATTACHMENT_TIMESTAMP_TRINARY_OFFSET, @@ -1082,12 +1083,12 @@ private synchronized void storeMessageStatement(final String address, final Stri final int txCount = (message.length() + txMessageSize - 1) / txMessageSize; - final int[] timestampTrits = new int[TransactionViewModel.TIMESTAMP_TRINARY_SIZE]; + final byte[] timestampTrits = new byte[TransactionViewModel.TIMESTAMP_TRINARY_SIZE]; Converter.copyTrits(System.currentTimeMillis(), timestampTrits, 0, timestampTrits.length); final String timestampTrytes = StringUtils.rightPad(Converter.trytes(timestampTrits), timestampTrits.length / 3, '9'); - final int[] lastIndexTrits = new int[TransactionViewModel.LAST_INDEX_TRINARY_SIZE]; - int[] currentIndexTrits = new int[TransactionViewModel.CURRENT_INDEX_TRINARY_SIZE]; + final byte[] lastIndexTrits = new byte[TransactionViewModel.LAST_INDEX_TRINARY_SIZE]; + byte[] currentIndexTrits = new byte[TransactionViewModel.CURRENT_INDEX_TRINARY_SIZE]; Converter.copyTrits(txCount - 1, lastIndexTrits, 0, lastIndexTrits.length); final String lastIndexTrytes = Converter.trytes(lastIndexTrits); @@ -1124,12 +1125,12 @@ private synchronized void storeMessageStatement(final String address, final Stri for (String tx : transactions) { String essence = tx.substring(startIdx); - int[] essenceTrits = new int[essence.length() * Converter.NUMBER_OF_TRITS_IN_A_TRYTE]; + byte[] essenceTrits = new byte[essence.length() * Converter.NUMBER_OF_TRITS_IN_A_TRYTE]; Converter.trits(essence, essenceTrits, 0); sponge.absorb(essenceTrits, 0, essenceTrits.length); } - int[] essenceTrits = new int[243]; + byte[] essenceTrits = new byte[243]; sponge.squeeze(essenceTrits, 0, essenceTrits.length); final String bundleHash = Converter.trytes(essenceTrits, 0, essenceTrits.length); diff --git a/src/main/java/com/iota/iri/storage/FileExportProvider.java b/src/main/java/com/iota/iri/storage/FileExportProvider.java index a46004a86b..189f6cecca 100644 --- a/src/main/java/com/iota/iri/storage/FileExportProvider.java +++ b/src/main/java/com/iota/iri/storage/FileExportProvider.java @@ -167,8 +167,8 @@ public static long getFileNumber() { } return now; } - int[] trits(Transaction transaction) { - int[] trits = new int[TRINARY_SIZE]; + byte[] trits(Transaction transaction) { + byte[] trits = new byte[TRINARY_SIZE]; if(transaction.bytes != null) { Converter.getTrits(transaction.bytes, trits); } diff --git a/src/main/java/com/iota/iri/utils/Converter.java b/src/main/java/com/iota/iri/utils/Converter.java index 9ff05fb62f..41656b0c15 100644 --- a/src/main/java/com/iota/iri/utils/Converter.java +++ b/src/main/java/com/iota/iri/utils/Converter.java @@ -12,8 +12,8 @@ public class Converter { public static final int NUMBER_OF_TRITS_IN_A_BYTE = 5; public static final int NUMBER_OF_TRITS_IN_A_TRYTE = 3; - static final int[][] BYTE_TO_TRITS_MAPPINGS = new int[243][]; - static final int[][] TRYTE_TO_TRITS_MAPPINGS = new int[27][]; + static final byte[][] BYTE_TO_TRITS_MAPPINGS = new byte[243][]; + static final byte[][] TRYTE_TO_TRITS_MAPPINGS = new byte[27][]; public static final int HIGH_INTEGER_BITS = 0xFFFFFFFF; public static final long HIGH_LONG_BITS = 0xFFFFFFFFFFFFFFFFL; @@ -25,7 +25,7 @@ public class Converter { static { - final int[] trits = new int[NUMBER_OF_TRITS_IN_A_BYTE]; + final byte[] trits = new byte[NUMBER_OF_TRITS_IN_A_BYTE]; for (int i = 0; i < 243; i++) { BYTE_TO_TRITS_MAPPINGS[i] = Arrays.copyOf(trits, NUMBER_OF_TRITS_IN_A_BYTE); @@ -38,7 +38,7 @@ public class Converter { } } - public static long longValue(final int[] trits, final int srcPos, final int size) { + public static long longValue(final byte[] trits, final int srcPos, final int size) { long value = 0; for (int i = size; i-- > 0; ) { @@ -52,11 +52,11 @@ public static byte[] allocateBytesForTrits(int tritCount) { return new byte[expectedLength]; } - public static int[] allocateTritsForTrytes(int tryteCount) { - return new int[tryteCount * NUMBER_OF_TRITS_IN_A_TRYTE]; + public static byte[] allocateTritsForTrytes(int tryteCount) { + return new byte[tryteCount * NUMBER_OF_TRITS_IN_A_TRYTE]; } - public static void bytes(final int[] trits, final int srcPos, byte[] dest, int destPos, final int tritsLength) { + public static void bytes(final byte[] trits, final int srcPos, byte[] dest, int destPos, final int tritsLength) { final int expectedLength = (tritsLength + NUMBER_OF_TRITS_IN_A_BYTE - 1) / NUMBER_OF_TRITS_IN_A_BYTE; @@ -73,11 +73,11 @@ public static void bytes(final int[] trits, final int srcPos, byte[] dest, int d } } - public static void bytes(final int[] trits, byte[] dest) { + public static void bytes(final byte[] trits, byte[] dest) { bytes(trits, 0, dest, 0, trits.length); } - public static void getTrits(final byte[] bytes, final int[] trits) { + public static void getTrits(final byte[] bytes, final byte[] trits) { int offset = 0; for (int i = 0; i < bytes.length && offset < trits.length; i++) { @@ -89,7 +89,7 @@ public static void getTrits(final byte[] bytes, final int[] trits) { } } - public static void trits(final String trytes, int[] dest, int destOffset) { + public static void trits(final String trytes, byte[] dest, int destOffset) { if((dest.length - destOffset) < trytes.length() * NUMBER_OF_TRITS_IN_A_TRYTE) { throw new IllegalArgumentException("Destination array is not large enough."); } @@ -100,7 +100,7 @@ public static void trits(final String trytes, int[] dest, int destOffset) { } } - public static void copyTrits(final long value, final int[] destination, final int offset, final int size) { + public static void copyTrits(final long value, final byte[] destination, final int offset, final int size) { long absoluteValue = value < 0 ? -value : value; for (int i = 0; i < size; i++) { @@ -112,18 +112,18 @@ public static void copyTrits(final long value, final int[] destination, final in remainder = MIN_TRIT_VALUE; absoluteValue++; } - destination[offset + i] = remainder; + destination[offset + i] = (byte) remainder; } if (value < 0) { for (int i = 0; i < size; i++) { - destination[offset + i] = -destination[offset + i]; + destination[offset + i] = (byte) -destination[offset + i]; } } } - public static String trytes(final int[] trits, final int offset, final int size) { + public static String trytes(final byte[] trits, final int offset, final int size) { final StringBuilder trytes = new StringBuilder(); for (int i = 0; i < (size + NUMBER_OF_TRITS_IN_A_TRYTE - 1) / NUMBER_OF_TRITS_IN_A_TRYTE; i++) { @@ -136,25 +136,25 @@ public static String trytes(final int[] trits, final int offset, final int size) return trytes.toString(); } - public static String trytes(final int[] trits) { + public static String trytes(final byte[] trits) { return trytes(trits, 0, trits.length); } - public static int tryteValue(final int[] trits, final int offset) { + public static int tryteValue(final byte[] trits, final int offset) { return trits[offset] + trits[offset + 1] * 3 + trits[offset + 2] * 9; } - public static Pair intPair(int[] trits) { - int[] low = new int[trits.length]; - int[] hi = new int[trits.length]; + public static Pair intPair(byte[] trits) { + byte[] low = new byte[trits.length]; + byte[] hi = new byte[trits.length]; for(int i = 0; i< trits.length; i++) { - low[i] = trits[i] != 1 ? HIGH_INTEGER_BITS: 0; - hi[i] = trits[i] != -1 ? HIGH_INTEGER_BITS: 0; + low[i] = trits[i] != (byte) 1 ? HIGH_INTEGER_BITS: (byte) 0; + hi[i] = trits[i] != (byte) -1 ? HIGH_INTEGER_BITS: (byte) 0; } return new Pair<>(low, hi); } - public static Pair longPair(int[] trits) { + public static Pair longPair(byte[] trits) { long[] low = new long[trits.length]; long[] hi = new long[trits.length]; for(int i = 0; i< trits.length; i++) { @@ -177,14 +177,14 @@ public static void shiftPair(Pair source, Pair d } } - public static int[] trits(final Pair pair, final int bitIndex) { + public static byte[] trits(final Pair pair, final int bitIndex) { final int length; if(pair.low.length == pair.hi.length || pair.low.length < pair.hi.length) { length = pair.low.length; } else { length = pair.hi.length; } - final int[] trits = new int[length]; + final byte[] trits = new byte[length]; long low; long hi; int mask = 1 << bitIndex; @@ -202,23 +202,23 @@ public static int[] trits(final Pair pair, final int bitIndex) { return trits; } - public static int[] trits(long[] low, long[] hi) { - int[] trits = new int[low.length]; + public static byte[] trits(long[] low, long[] hi) { + byte[] trits = new byte[low.length]; for(int i = 0; i < trits.length; i++) { - trits[i] = low[i] == 0 ? 1 : hi[i] == 0 ? -1 : 0; + trits[i] = low[i] == 0 ? 1 : hi[i] == 0 ? (byte) -1 : (byte) 0; } return trits; } - public static int[] trits(int[] low, int[] hi) { - int[] trits = new int[low.length]; + public static byte[] trits(byte[] low, byte[] hi) { + byte[] trits = new byte[low.length]; for(int i = 0; i < trits.length; i++) { - trits[i] = low[i] == 0 ? 1 : hi[i] == 0 ? -1 : 0; + trits[i] = low[i] == 0 ? 1 : hi[i] == 0 ? (byte) -1 : (byte) 0; } return trits; } - private static void increment(final int[] trits, final int size) { + private static void increment(final byte[] trits, final int size) { for (int i = 0; i < size; i++) { if (++trits[i] > Converter.MAX_TRIT_VALUE) { trits[i] = Converter.MIN_TRIT_VALUE; @@ -244,8 +244,8 @@ public static String asciiToTrytes(String input) { return sb.toString(); } - public static int[] allocatingTritsFromTrytes(String trytes) { - int[] trits = allocateTritsForTrytes(trytes.length()); + public static byte[] allocatingTritsFromTrytes(String trytes) { + byte[] trits = allocateTritsForTrytes(trytes.length()); trits(trytes, trits, 0); return trits; } diff --git a/src/main/java/com/iota/iri/utils/MapIdentityManager.java b/src/main/java/com/iota/iri/utils/MapIdentityManager.java index 45582f7a9b..4f7bb10c37 100644 --- a/src/main/java/com/iota/iri/utils/MapIdentityManager.java +++ b/src/main/java/com/iota/iri/utils/MapIdentityManager.java @@ -49,9 +49,9 @@ private boolean verifyCredential(Account account, Credential credential) { if (credential instanceof PasswordCredential) { char[] givenPassword = ((PasswordCredential) credential).getPassword(); String trytes = Converter.asciiToTrytes(new String(givenPassword)); - int[] in_trits = Converter.allocateTritsForTrytes(trytes.length()); + byte[] in_trits = Converter.allocateTritsForTrytes(trytes.length()); Converter.trits(trytes, in_trits, 0); - int[] hash_trits = new int[Curl.HASH_LENGTH]; + byte[] hash_trits = new byte[Curl.HASH_LENGTH]; Sponge curl; curl = SpongeFactory.create(SpongeFactory.Mode.CURLP81); curl.absorb(in_trits, 0, in_trits.length); diff --git a/src/test/java/com/iota/iri/TransactionValidatorTest.java b/src/test/java/com/iota/iri/TransactionValidatorTest.java index b4a59c0fa9..85942fe6e3 100644 --- a/src/test/java/com/iota/iri/TransactionValidatorTest.java +++ b/src/test/java/com/iota/iri/TransactionValidatorTest.java @@ -65,7 +65,7 @@ public void testMinMwm() throws InterruptedException { @Test public void validateBytes() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); Converter.copyTrits(0, trits, 0, trits.length); byte[] bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, bytes); @@ -74,20 +74,20 @@ public void validateBytes() throws Exception { @Test public void validateTrits() { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); Converter.copyTrits(0, trits, 0, trits.length); TransactionValidator.validate(trits, MAINNET_MWM); } @Test(expected = RuntimeException.class) public void validateTritsWithInvalidMetadata() { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); TransactionValidator.validate(trits, MAINNET_MWM); } @Test public void validateBytesWithNewCurl() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); Converter.copyTrits(0, trits, 0, trits.length); byte[] bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, 0, bytes, 0, trits.length); @@ -110,7 +110,7 @@ public void verifyTxIsNotSolid() throws Exception { @Test public void addSolidTransactionWithoutErrors() { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); Converter.copyTrits(0, trits, 0, trits.length); txValidator.addSolidTransaction(Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); } @@ -119,12 +119,12 @@ private TransactionViewModel getTxWithBranchAndTrunk() throws Exception { TransactionViewModel tx, trunkTx, branchTx; String trytes = "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999CFDEZBLZQYA9999999999999999999999999999999999999999999ZZWQHWD99C99999999C99999999CKWWDBWSCLMQULCTAAJGXDEMFJXPMGMAQIHDGHRBGEMUYNNCOK9YPHKEEFLFCZUSPMCJHAKLCIBQSGWAS999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"; - int[] trits = Converter.allocateTritsForTrytes(trytes.length()); + byte[] trits = Converter.allocateTritsForTrytes(trytes.length()); Converter.trits(trytes, trits, 0); trunkTx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); branchTx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); - int[] childTx = getRandomTransactionTrits(); + byte[] childTx = getRandomTransactionTrits(); System.arraycopy(trunkTx.getHash().trits(), 0, childTx, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_SIZE); System.arraycopy(branchTx.getHash().trits(), 0, childTx, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE); tx = new TransactionViewModel(childTx, Hash.calculate(SpongeFactory.Mode.CURLP81, childTx)); @@ -137,7 +137,7 @@ private TransactionViewModel getTxWithBranchAndTrunk() throws Exception { } private TransactionViewModel getTxWithoutBranchAndTrunk() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); TransactionViewModel tx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); tx.store(tangle); diff --git a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java index b8904bb9ff..a304dd5d50 100644 --- a/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java +++ b/src/test/java/com/iota/iri/controllers/TransactionViewModelTest.java @@ -1,7 +1,6 @@ package com.iota.iri.controllers; import com.iota.iri.conf.Configuration; -import com.iota.iri.hash.Sponge; import com.iota.iri.hash.SpongeFactory; import com.iota.iri.model.Hash; import com.iota.iri.model.Transaction; @@ -18,9 +17,6 @@ import static org.junit.Assert.*; -/** - * Created by paul on 3/5/17 for iri. - */ public class TransactionViewModelTest { private static final TemporaryFolder dbFolder = new TemporaryFolder(); @@ -65,12 +61,12 @@ public void getApprovers() throws Exception { TransactionViewModel transactionViewModel, otherTxVM, trunkTx, branchTx; - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); trunkTx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); branchTx = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); - int[] childTx = getRandomTransactionTrits(); + byte[] childTx = getRandomTransactionTrits(); System.arraycopy(trunkTx.getHash().trits(), 0, childTx, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_SIZE); System.arraycopy(branchTx.getHash().trits(), 0, childTx, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE); transactionViewModel = new TransactionViewModel(childTx, Hash.calculate(SpongeFactory.Mode.CURLP81, childTx)); @@ -106,34 +102,32 @@ public void update() throws Exception { @Test public void trits() throws Exception { - /* - int[] blanks = new int[13]; + byte[] blanks = new byte[13]; for(int i=0; i++ < 1000;) { - int[] trits = getRandomTransactionTrits(seed), searchTrits; - System.arraycopy(new int[TransactionViewModel.VALUE_TRINARY_SIZE], 0, trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_TRINARY_SIZE); + byte[] trits = getRandomTransactionTrits(), searchTrits; + System.arraycopy(new byte[TransactionViewModel.VALUE_TRINARY_SIZE], 0, trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_TRINARY_SIZE); Converter.copyTrits(seed.nextLong(), trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_USABLE_TRINARY_SIZE); System.arraycopy(blanks, 0, trits, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET-blanks.length, blanks.length); System.arraycopy(blanks, 0, trits, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET-blanks.length, blanks.length); System.arraycopy(blanks, 0, trits, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET + TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE-blanks.length, blanks.length); - TransactionViewModel transactionViewModel = new TransactionViewModel(trits); - transactionViewModel.store(); - assertArrayEquals(transactionViewModel.trits(), TransactionViewModel.fromHash(transactionViewModel.getHash()).trits()); + Hash hash = getRandomTransactionHash(); + TransactionViewModel transactionViewModel = new TransactionViewModel(trits, hash); + transactionViewModel.store(tangle); + assertArrayEquals(transactionViewModel.trits(), TransactionViewModel.fromHash(tangle, transactionViewModel.getHash()).trits()); } - */ } @Test public void getBytes() throws Exception { - /* for(int i=0; i++ < 1000;) { - int[] trits = getRandomTransactionTrits(seed); - System.arraycopy(new int[TransactionViewModel.VALUE_TRINARY_SIZE], 0, trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_TRINARY_SIZE); + byte[] trits = getRandomTransactionTrits(); + System.arraycopy(new byte[TransactionViewModel.VALUE_TRINARY_SIZE], 0, trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_TRINARY_SIZE); Converter.copyTrits(seed.nextLong(), trits, TransactionViewModel.VALUE_TRINARY_OFFSET, TransactionViewModel.VALUE_USABLE_TRINARY_SIZE); - TransactionViewModel transactionViewModel = new TransactionViewModel(trits); - transactionViewModel.store(); - assertArrayEquals(transactionViewModel.getBytes(), TransactionViewModel.fromHash(transactionViewModel.getHash()).getBytes()); + Hash hash = getRandomTransactionHash(); + TransactionViewModel transactionViewModel = new TransactionViewModel(trits, hash); + transactionViewModel.store(tangle); + assertArrayEquals(transactionViewModel.getBytes(), TransactionViewModel.fromHash(tangle, transactionViewModel.getHash()).getBytes()); } - */ } @Test @@ -322,7 +316,7 @@ public void updateHeightPrefilledSlotShouldFail() throws Exception { @Test public void findShouldBeSuccessful() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); transactionViewModel.store(tangle); Hash hash = transactionViewModel.getHash(); @@ -331,7 +325,7 @@ public void findShouldBeSuccessful() throws Exception { @Test public void findShouldReturnNull() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); trits = getRandomTransactionTrits(); TransactionViewModel transactionViewModelNoSave = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); @@ -396,47 +390,40 @@ public void testManyTXInDB() throws Exception { private Transaction getRandomTransaction(Random seed) { Transaction transaction = new Transaction(); - int[] trits = Arrays.stream(new int[TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE]).map(i -> seed.nextInt(3)-1).toArray(); + byte[] trits = new byte[TransactionViewModel.SIGNATURE_MESSAGE_FRAGMENT_TRINARY_SIZE]; + for(int i = 0; i < trits.length; i++) { + trits[i] = (byte) (seed.nextInt(3) - 1); + } + transaction.bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, 0, transaction.bytes, 0, trits.length); return transaction; } - public static int[] getRandomTransactionWithTrunkAndBranch(Hash trunk, Hash branch) { - int[] trits = getRandomTransactionTrits(); + public static byte[] getRandomTransactionWithTrunkAndBranch(Hash trunk, Hash branch) { + byte[] trits = getRandomTransactionTrits(); System.arraycopy(trunk.trits(), 0, trits, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_SIZE); System.arraycopy(branch.trits(), 0, trits, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE); return trits; } - public static int[] getRandomTransactionWithTrunkAndBranchValidBundle(Hash trunk, Hash branch) { - int[] trits = getRandomTransactionTrits(); - System.arraycopy(trunk.trits(), 0, trits, TransactionViewModel.TRUNK_TRANSACTION_TRINARY_OFFSET, - TransactionViewModel.TRUNK_TRANSACTION_TRINARY_SIZE); - System.arraycopy(branch.trits(), 0, trits, TransactionViewModel.BRANCH_TRANSACTION_TRINARY_OFFSET, - TransactionViewModel.BRANCH_TRANSACTION_TRINARY_SIZE); - System.arraycopy(Hash.NULL_HASH.trits(), 0, trits, TransactionViewModel.CURRENT_INDEX_TRINARY_OFFSET, - TransactionViewModel.CURRENT_INDEX_TRINARY_SIZE); - System.arraycopy(Hash.NULL_HASH.trits(), 0, trits, TransactionViewModel.LAST_INDEX_TRINARY_OFFSET, - TransactionViewModel.LAST_INDEX_TRINARY_SIZE); - System.arraycopy(Hash.NULL_HASH.trits(), 0, trits, TransactionViewModel.VALUE_TRINARY_OFFSET, - TransactionViewModel.VALUE_TRINARY_SIZE); - - final Sponge curlInstance = SpongeFactory.create(SpongeFactory.Mode.KERL); - final int[] bundleHashTrits = new int[TransactionViewModel.BUNDLE_TRINARY_SIZE]; - curlInstance.reset(); - curlInstance.absorb(trits, TransactionViewModel.ESSENCE_TRINARY_OFFSET, TransactionViewModel.ESSENCE_TRINARY_SIZE); - curlInstance.squeeze(bundleHashTrits, 0, bundleHashTrits.length); - - System.arraycopy(bundleHashTrits, 0, trits, TransactionViewModel.BUNDLE_TRINARY_OFFSET, - TransactionViewModel.BUNDLE_TRINARY_SIZE); + public static byte[] getRandomTransactionTrits() { + byte[] out = new byte[TransactionViewModel.TRINARY_SIZE]; - return trits; - } - public static int[] getRandomTransactionTrits() { - return Arrays.stream(new int[TransactionViewModel.TRINARY_SIZE]).map(i -> seed.nextInt(3)-1).toArray(); + for(int i = 0; i < out.length; i++) { + out[i] = (byte) (seed.nextInt(3) - 1); + } + + return out; } + public static Hash getRandomTransactionHash() { - return new Hash(Arrays.stream(new int[Hash.SIZE_IN_TRITS]).map(i -> seed.nextInt(3)-1).toArray()); + byte[] out = new byte[Hash.SIZE_IN_TRITS]; + + for(int i = 0; i < out.length; i++) { + out[i] = (byte) (seed.nextInt(3) - 1); + } + + return new Hash(out); } } \ No newline at end of file diff --git a/src/test/java/com/iota/iri/hash/CurlTest.java b/src/test/java/com/iota/iri/hash/CurlTest.java index 25937463d8..d76a4dffbe 100644 --- a/src/test/java/com/iota/iri/hash/CurlTest.java +++ b/src/test/java/com/iota/iri/hash/CurlTest.java @@ -22,9 +22,9 @@ public class CurlTest { @Test public void normalHashWorks() { int size = 8019; - int[] in_trits = new int[size]; + byte[] in_trits = new byte[size]; Converter.trits(trytes, in_trits, 0); - int[] hash_trits = new int[Curl.HASH_LENGTH]; + byte[] hash_trits = new byte[Curl.HASH_LENGTH]; Sponge curl; curl = new Curl(SpongeFactory.Mode.CURLP81); curl.absorb(in_trits, 0, in_trits.length); @@ -36,14 +36,14 @@ public void normalHashWorks() { @Test public void pairHashWorks() { int size = 8019; - int[] in_trits = new int[size]; + byte[] in_trits = new byte[size]; Converter.trits(trytes, in_trits, 0); Pair hashPair = new Pair<>(new long[Curl.HASH_LENGTH], new long[Curl.HASH_LENGTH]); Curl curl; curl = new Curl(true, SpongeFactory.Mode.CURLP81); curl.absorb(Converter.longPair(in_trits), 0, in_trits.length); curl.squeeze(hashPair, 0, Curl.HASH_LENGTH); - int[] hash_trits = Converter.trits(hashPair.low, hashPair.hi); + byte[] hash_trits = Converter.trits(hashPair.low, hashPair.hi); String out_trytes = Converter.trytes(hash_trits); Assert.assertEquals(hash, out_trytes); } @@ -52,9 +52,9 @@ public void pairHashWorks() { public void pairHashIsFasterThanNormalHash() { int size = 8019; long start1, diff1, start2, diff2; - int[] in_trits = new int[size]; + byte[] in_trits = new byte[size]; Converter.trits(trytes, in_trits, 0); - final int[] hash_trits = new int[Curl.HASH_LENGTH]; + final byte[] hash_trits = new byte[Curl.HASH_LENGTH]; Curl curl, curl1; curl = new Curl(true, SpongeFactory.Mode.CURLP81); curl1 = new Curl(SpongeFactory.Mode.CURLP81); diff --git a/src/test/java/com/iota/iri/hash/ISSTest.java b/src/test/java/com/iota/iri/hash/ISSTest.java index 7ba2b49f0d..27706a999c 100644 --- a/src/test/java/com/iota/iri/hash/ISSTest.java +++ b/src/test/java/com/iota/iri/hash/ISSTest.java @@ -30,28 +30,28 @@ public void testSignatureResolvesToAddressISS() throws Exception { int nof = 1; SpongeFactory.Mode[] modes = {SpongeFactory.Mode.CURLP81, SpongeFactory.Mode.KERL}; - int[] seedTrits = new int[Sponge.HASH_LENGTH]; + byte[] seedTrits = new byte[Sponge.HASH_LENGTH]; for (SpongeFactory.Mode mode: modes) { Converter.trits(seed, seedTrits, 0); - int[] subseed = ISS.subseed(mode, seedTrits, index); - int[] key = ISS.key(mode, subseed, nof); + byte[] subseed = ISS.subseed(mode, seedTrits, index); + byte[] key = ISS.key(mode, subseed, nof); Kerl curl = new Kerl(); - int[] messageTrits = Converter.allocateTritsForTrytes(message.length()); + byte[] messageTrits = Converter.allocateTritsForTrytes(message.length()); Converter.trits(message, messageTrits, 0); curl.absorb(messageTrits, 0, messageTrits.length); - int[] messageHash = new int[Curl.HASH_LENGTH]; + byte[] messageHash = new byte[Curl.HASH_LENGTH]; curl.squeeze(messageHash, 0, Curl.HASH_LENGTH); - int[] normalizedFragment = + byte[] normalizedFragment = Arrays.copyOf(ISS.normalizedBundle(messageHash), ISS.NUMBER_OF_FRAGMENT_CHUNKS); - int[] signature = ISS.signatureFragment(mode, normalizedFragment, key); - int[] sigDigest = ISS.digest(mode, normalizedFragment, signature); - int[] signedAddress = ISS.address(mode, sigDigest); - int[] digest = ISS.digests(mode, key); - int[] address = ISS.address(mode, digest); + byte[] signature = ISS.signatureFragment(mode, normalizedFragment, key); + byte[] sigDigest = ISS.digest(mode, normalizedFragment, signature); + byte[] signedAddress = ISS.address(mode, sigDigest); + byte[] digest = ISS.digests(mode, key); + byte[] address = ISS.address(mode, digest); assertTrue(Arrays.equals(address, signedAddress)); } } @@ -65,13 +65,13 @@ public void addressGenerationISS() throws Exception { new Hash("MDWYEJJHJDIUVPKDY9EACGDJUOP9TLYDWETUBOYCBLYXYYYJYUXYUTCTPTDGJYFKMQMCNZDQPTBE9AFIW")}; for (int i=0;i rnd_seed.nextInt(3)-1).toArray(); + public static byte[] getRandomTrits(int length) { + byte[] out = new byte[length]; + + for(int i = 0; i < out.length; i++) { + out[i] = (byte) (rnd_seed.nextInt(3) - 1); + } + + return out; } //@Test @@ -96,16 +102,13 @@ public void generateNAddressesForSeed() throws Exception { Hash[] addresses = new Hash[4]; for (int j = 0; j< 4 ; j++) { - int[] subseed = ISS.subseed(mode, seed.trits(), j); - int[] key = ISS.key(mode, subseed, nof); - int[] digest = ISS.digests(mode, key); - int[] address = ISS.address(mode, digest); + byte[] subseed = ISS.subseed(mode, seed.trits(), j); + byte[] key = ISS.key(mode, subseed, nof); + byte[] digest = ISS.digests(mode, key); + byte[] address = ISS.address(mode, digest); addresses[j] = new Hash(address); } System.out.println(String.format("%s,%s,%s,%s,%s", seed, addresses[0],addresses[1],addresses[2],addresses[3])); - } - } - -} +} \ No newline at end of file diff --git a/src/test/java/com/iota/iri/hash/KerlTest.java b/src/test/java/com/iota/iri/hash/KerlTest.java index da68414896..c054ddb418 100644 --- a/src/test/java/com/iota/iri/hash/KerlTest.java +++ b/src/test/java/com/iota/iri/hash/KerlTest.java @@ -23,10 +23,10 @@ public class KerlTest { public void tritsFromBigInt() throws Exception { long value = 1433452143; int size = 50; - int[] trits = new int[size]; + byte[] trits = new byte[size]; Converter.copyTrits(value, trits, 0, trits.length); BigInteger bigInteger = Kerl.bigIntFromTrits(trits, 0, trits.length); - int[] outTrits = new int[size]; + byte[] outTrits = new byte[size]; Kerl.tritsFromBigInt(bigInteger, outTrits, 0, size); Assert.assertTrue(Arrays.equals(trits, outTrits)); } @@ -47,7 +47,7 @@ public void loopRandBytesFromBigInt() throws Exception { int byte_size = 48; int trit_size = 243; byte[] inBytes = new byte[byte_size]; - int[] trits = new int[Kerl.HASH_LENGTH]; + byte[] trits = new byte[Kerl.HASH_LENGTH]; byte[] outBytes = new byte[Kerl.BYTE_HASH_LENGTH]; for (int i = 0; i < 10_000; i++) { seed.nextBytes(inBytes); @@ -67,9 +67,9 @@ public void loopRandTritsFromBigInt() throws Exception { //generate random bytes, turn them to trits and back int byte_size = 48; int trit_size = 243; - int[] inTrits; + byte[] inTrits; byte[] bytes = new byte[Kerl.BYTE_HASH_LENGTH]; - int[] outTrits = new int[Kerl.HASH_LENGTH]; + byte[] outTrits = new byte[Kerl.HASH_LENGTH]; for (int i = 0; i < 10_000; i++) { inTrits = getRandomTrits(trit_size); inTrits[242] = 0; @@ -89,16 +89,16 @@ public void loopRandTritsFromBigInt() throws Exception { @Test public void limitBigIntFromTrits() { // this confirms that the long math does not produce an overflow. - int[] trits = new int[Kerl.MAX_POWERS_LONG]; - - Arrays.fill(trits, 1); + byte[] trits = new byte[Kerl.MAX_POWERS_LONG]; + + Arrays.fill(trits, (byte) 1); BigInteger result = Kerl.bigIntFromTrits(trits, 0, trits.length); - Arrays.fill(trits, 1); + Arrays.fill(trits, (byte) 1); BigInteger expected = BigInteger.ZERO; for (int i = trits.length; i-- > 0; ) { expected = expected.multiply(BigInteger.valueOf(Converter.RADIX)).add(BigInteger.valueOf(trits[i])); - } + } Assert.assertTrue("Overflow in long math", expected.equals(result)); } @@ -128,8 +128,8 @@ public void benchmarkCurl() { for (i = 0; i++ < max; ) { //pre int size = 8019; - int[] in_trits = getRandomTrits(size); - int[] hash_trits = new int[Curl.HASH_LENGTH]; + byte[] in_trits = getRandomTrits(size); + byte[] hash_trits = new byte[Curl.HASH_LENGTH]; start = System.nanoTime(); //measured @@ -167,10 +167,10 @@ public void benchmarkCurl() { @Test public void kerlOneAbsorb() throws Exception { - int[] initial_value = Converter.allocatingTritsFromTrytes("EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); + byte[] initial_value = Converter.allocatingTritsFromTrytes("EMIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH]; + byte[] hash_value = new byte[Curl.HASH_LENGTH]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); Assert.assertEquals("EJEAOOZYSAWFPZQESYDHZCGYNSTWXUMVJOVDWUNZJXDGWCLUFGIMZRMGCAZGKNPLBRLGUNYWKLJTYEAQX", hash); @@ -178,10 +178,10 @@ public void kerlOneAbsorb() throws Exception { @Test public void kerlMultiSqueeze() throws Exception { - int[] initial_value = Converter.allocatingTritsFromTrytes("9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); + byte[] initial_value = Converter.allocatingTritsFromTrytes("9MIDYNHBWMBCXVDEFOFWINXTERALUKYYPPHKP9JJFGJEIUY9MUDVNFZHMMWZUYUSWAIOWEVTHNWMHANBH"); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH * 2]; + byte[] hash_value = new byte[Curl.HASH_LENGTH * 2]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); Assert.assertEquals("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA", hash); @@ -189,17 +189,24 @@ public void kerlMultiSqueeze() throws Exception { @Test public void kerlMultiAbsorbMultiSqueeze() throws Exception { - int[] initial_value = Converter.allocatingTritsFromTrytes("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA"); + byte[] initial_value = Converter.allocatingTritsFromTrytes("G9JYBOMPUXHYHKSNRNMMSSZCSHOFYOYNZRSZMAAYWDYEIMVVOGKPJBVBM9TDPULSFUNMTVXRKFIDOHUXXVYDLFSZYZTWQYTE9SPYYWYTXJYQ9IFGYOLZXWZBKWZN9QOOTBQMWMUBLEWUEEASRHRTNIQWJQNDWRYLCA"); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH * 2]; + byte[] hash_value = new byte[Curl.HASH_LENGTH * 2]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); Assert.assertEquals("LUCKQVACOGBFYSPPVSSOXJEKNSQQRQKPZC9NXFSMQNRQCGGUL9OHVVKBDSKEQEBKXRNUJSRXYVHJTXBPDWQGNSCDCBAIRHAQCOWZEBSNHIJIGPZQITIBJQ9LNTDIBTCQ9EUWKHFLGFUVGGUWJONK9GBCDUIMAYMMQX", hash); } + final static Random rnd_seed = new Random(); + + public static byte[] getRandomTrits(int length) { + byte[] out = new byte[length]; + + for(int i = 0; i < out.length; i++) { + out[i] = (byte) (rnd_seed.nextInt(3) - 1); + } - public static int[] getRandomTrits(int length) { - return Arrays.stream(new int[length]).map(i -> seed.nextInt(3) - 1).toArray(); + return out; } public static Hash getRandomTransactionHash() { @@ -211,10 +218,10 @@ public void generateTrytesAndHashes() throws Exception { System.out.println("trytes,Kerl_hash"); for (int i = 0; i < 10000; i++) { Hash trytes = getRandomTransactionHash(); - int[] initial_value = trytes.trits(); + byte[] initial_value = trytes.trits(); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH]; + byte[] hash_value = new byte[Curl.HASH_LENGTH]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); System.out.println(String.format("%s,%s", trytes, hash)); @@ -226,10 +233,10 @@ public void generateTrytesAndMultiSqueeze() throws Exception { System.out.println("trytes,Kerl_squeeze1,Kerl_squeeze2,Kerl_squeeze3"); for (int i = 0; i < 10000; i++) { Hash trytes = getRandomTransactionHash(); - int[] initial_value = trytes.trits(); + byte[] initial_value = trytes.trits(); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH]; + byte[] hash_value = new byte[Curl.HASH_LENGTH]; k.squeeze(hash_value, 0, hash_value.length); String hash1 = Converter.trytes(hash_value); k.squeeze(hash_value, 0, hash_value.length); @@ -245,10 +252,10 @@ public void generateMultiTrytesAndHash() throws Exception { System.out.println("multiTrytes,Kerl_hash"); for (int i = 0; i < 10000; i++) { String multi = String.format("%s%s%s", getRandomTransactionHash(), getRandomTransactionHash(), getRandomTransactionHash()); - int[] initial_value = Converter.allocatingTritsFromTrytes(multi); + byte[] initial_value = Converter.allocatingTritsFromTrytes(multi); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH]; + byte[] hash_value = new byte[Curl.HASH_LENGTH]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); System.out.println(String.format("%s,%s", multi, hash)); @@ -261,10 +268,10 @@ public void generateHashes() throws Exception { //System.out.println("trytes,Kerl_hash"); for (int i = 0; i < 1_000_000; i++) { Hash trytes = getRandomTransactionHash(); - int[] initial_value = trytes.trits(); + byte[] initial_value = trytes.trits(); Sponge k = SpongeFactory.create(SpongeFactory.Mode.KERL); k.absorb(initial_value, 0, initial_value.length); - int[] hash_value = new int[Curl.HASH_LENGTH]; + byte[] hash_value = new byte[Curl.HASH_LENGTH]; k.squeeze(hash_value, 0, hash_value.length); String hash = Converter.trytes(hash_value); //System.out.println(String.format("%s,%s",trytes,hash)); diff --git a/src/test/java/com/iota/iri/hash/PearlDiverTest.java b/src/test/java/com/iota/iri/hash/PearlDiverTest.java index cda678dfc8..079a5c9501 100644 --- a/src/test/java/com/iota/iri/hash/PearlDiverTest.java +++ b/src/test/java/com/iota/iri/hash/PearlDiverTest.java @@ -19,12 +19,12 @@ public class PearlDiverTest { private static final int NUM_CORES = -1; // use n-1 cores private PearlDiver pearlDiver; - private int[] hashTrits; + private byte[] hashTrits; @Before public void setUp() throws Exception { pearlDiver = new PearlDiver(); - hashTrits = new int[Curl.HASH_LENGTH]; + hashTrits = new byte[Curl.HASH_LENGTH]; } @Test @@ -41,19 +41,19 @@ public void testCancel() { @Test(expected = RuntimeException.class) public void testInvalidMagnitude() { - pearlDiver.search(new int[8019], -1, NUM_CORES); + pearlDiver.search(new byte[8019], -1, NUM_CORES); } @Test(expected = RuntimeException.class) public void testInvalidTritsLength() { - pearlDiver.search(new int[0], MIN_WEIGHT_MAGNITUDE, NUM_CORES); + pearlDiver.search(new byte[0], MIN_WEIGHT_MAGNITUDE, NUM_CORES); } @Test @Ignore("to test pearlDiver iteratively") public void testNoRandomFail() { for (int i = 0; i < 10000; i++) { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); pearlDiver.search(trits, MIN_WEIGHT_MAGNITUDE, NUM_CORES); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); for (int j = Hash.SIZE_IN_TRITS - 1; j > Hash.SIZE_IN_TRITS - MIN_WEIGHT_MAGNITUDE; j--) { @@ -67,7 +67,7 @@ public void testNoRandomFail() { private String getHashFor(String trytes) { Sponge curl = new Curl(SpongeFactory.Mode.CURLP81); - int[] myTrits = Converter.allocateTritsForTrytes(trytes.length()); + byte[] myTrits = Converter.allocateTritsForTrytes(trytes.length()); Converter.trits(trytes, myTrits, 0); pearlDiver.search(myTrits, MIN_WEIGHT_MAGNITUDE, NUM_CORES); curl.absorb(myTrits, 0, myTrits.length); diff --git a/src/test/java/com/iota/iri/integration/NodeIntegrationTests.java b/src/test/java/com/iota/iri/integration/NodeIntegrationTests.java index 10d06c5694..bda9ed9c32 100644 --- a/src/test/java/com/iota/iri/integration/NodeIntegrationTests.java +++ b/src/test/java/com/iota/iri/integration/NodeIntegrationTests.java @@ -139,8 +139,8 @@ private void sendMilestone(API api, long index) throws Exception { } private void newMilestone(API api, List tips, long index) throws Exception { - List transactions = new ArrayList<>(); - transactions.add(new int[TRINARY_SIZE]); + List transactions = new ArrayList<>(); + transactions.add(new byte[TRINARY_SIZE]); Converter.copyTrits(index, transactions.get(0), OBSOLETE_TAG_TRINARY_OFFSET, OBSOLETE_TAG_TRINARY_SIZE); transactions.add(Arrays.copyOf(transactions.get(0), TRINARY_SIZE)); Hash coordinator = new Hash(Configuration.TESTNET_COORDINATOR_ADDRESS); @@ -151,31 +151,31 @@ private void newMilestone(API api, List tips, long index) throws Exception api.broadcastTransactionStatement(elements); } - public void setBundleHash(List transactions, Curl customCurl) { + public void setBundleHash(List transactions, Curl customCurl) { - int[] hash = new int[Curl.HASH_LENGTH]; + byte[] hash = new byte[Curl.HASH_LENGTH]; Sponge curl = customCurl == null ? SpongeFactory.create(SpongeFactory.Mode.CURLP81) : customCurl; curl.reset(); for (int i = 0; i < transactions.size(); i++) { - int[] t = Arrays.copyOfRange(transactions.get(i), ADDRESS_TRINARY_OFFSET, ADDRESS_TRINARY_OFFSET + ADDRESS_TRINARY_SIZE); + byte[] t = Arrays.copyOfRange(transactions.get(i), ADDRESS_TRINARY_OFFSET, ADDRESS_TRINARY_OFFSET + ADDRESS_TRINARY_SIZE); - int[] valueTrits = Arrays.copyOfRange(transactions.get(i), VALUE_TRINARY_OFFSET, VALUE_TRINARY_OFFSET + VALUE_TRINARY_SIZE); + byte[] valueTrits = Arrays.copyOfRange(transactions.get(i), VALUE_TRINARY_OFFSET, VALUE_TRINARY_OFFSET + VALUE_TRINARY_SIZE); t = ArrayUtils.addAll(t, valueTrits); - int[] tagTrits = Arrays.copyOfRange(transactions.get(i), OBSOLETE_TAG_TRINARY_OFFSET, OBSOLETE_TAG_TRINARY_OFFSET + OBSOLETE_TAG_TRINARY_SIZE); + byte[] tagTrits = Arrays.copyOfRange(transactions.get(i), OBSOLETE_TAG_TRINARY_OFFSET, OBSOLETE_TAG_TRINARY_OFFSET + OBSOLETE_TAG_TRINARY_SIZE); t = ArrayUtils.addAll(t, tagTrits); - int[] timestampTrits = Arrays.copyOfRange(transactions.get(i), TIMESTAMP_TRINARY_OFFSET, TIMESTAMP_TRINARY_OFFSET + TIMESTAMP_TRINARY_SIZE); + byte[] timestampTrits = Arrays.copyOfRange(transactions.get(i), TIMESTAMP_TRINARY_OFFSET, TIMESTAMP_TRINARY_OFFSET + TIMESTAMP_TRINARY_SIZE); t = ArrayUtils.addAll(t, timestampTrits); Converter.copyTrits(i, transactions.get(i), CURRENT_INDEX_TRINARY_OFFSET, CURRENT_INDEX_TRINARY_SIZE); - int[] currentIndexTrits = Arrays.copyOfRange(transactions.get(i), CURRENT_INDEX_TRINARY_OFFSET, CURRENT_INDEX_TRINARY_OFFSET + CURRENT_INDEX_TRINARY_SIZE); + byte[] currentIndexTrits = Arrays.copyOfRange(transactions.get(i), CURRENT_INDEX_TRINARY_OFFSET, CURRENT_INDEX_TRINARY_OFFSET + CURRENT_INDEX_TRINARY_SIZE); t = ArrayUtils.addAll(t, currentIndexTrits); Converter.copyTrits(transactions.size(), transactions.get(i), LAST_INDEX_TRINARY_OFFSET, LAST_INDEX_TRINARY_SIZE); - int[] lastIndexTrits = Arrays.copyOfRange(transactions.get(i), LAST_INDEX_TRINARY_OFFSET, LAST_INDEX_TRINARY_OFFSET + LAST_INDEX_TRINARY_SIZE); + byte[] lastIndexTrits = Arrays.copyOfRange(transactions.get(i), LAST_INDEX_TRINARY_OFFSET, LAST_INDEX_TRINARY_OFFSET + LAST_INDEX_TRINARY_SIZE); t = ArrayUtils.addAll(t, lastIndexTrits); curl.absorb(t, 0, t.length); diff --git a/src/test/java/com/iota/iri/model/HashTest.java b/src/test/java/com/iota/iri/model/HashTest.java index fcdc2ec9db..dd2cc2be66 100644 --- a/src/test/java/com/iota/iri/model/HashTest.java +++ b/src/test/java/com/iota/iri/model/HashTest.java @@ -31,7 +31,7 @@ public void calculate1() throws Exception { @Test public void calculate2() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); byte[] bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, bytes); Hash hash = Hash.calculate(bytes, TransactionViewModel.TRINARY_SIZE, SpongeFactory.create(SpongeFactory.Mode.CURLP81)); @@ -49,12 +49,12 @@ public void trailingZeros() throws Exception { @Test public void trits() throws Exception { Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, TransactionViewModelTest.getRandomTransactionTrits()); - Assert.assertFalse(Arrays.equals(new int[Hash.SIZE_IN_TRITS], hash.trits())); + Assert.assertFalse(Arrays.equals(new byte[Hash.SIZE_IN_TRITS], hash.trits())); } @Test public void equals() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Hash hash1 = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Assert.assertTrue(hash.equals(hash1)); @@ -64,7 +64,7 @@ public void equals() throws Exception { @Test public void hashCodeTest() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Assert.assertNotEquals(hash.hashCode(), 0); Assert.assertEquals(Hash.NULL_HASH.hashCode(), -240540129); @@ -72,7 +72,7 @@ public void hashCodeTest() throws Exception { @Test public void toStringTest() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Assert.assertEquals(Hash.NULL_HASH.toString(), "999999999999999999999999999999999999999999999999999999999999999999999999999999999"); Assert.assertNotEquals(hash.toString(), "999999999999999999999999999999999999999999999999999999999999999999999999999999999"); @@ -82,7 +82,7 @@ public void toStringTest() throws Exception { @Test public void bytes() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Assert.assertTrue(Arrays.equals(new byte[Hash.SIZE_IN_BYTES], Hash.NULL_HASH.bytes())); Assert.assertFalse(Arrays.equals(new byte[Hash.SIZE_IN_BYTES], hash.bytes())); @@ -91,7 +91,7 @@ public void bytes() throws Exception { @Test public void compareTo() throws Exception { - int[] trits = TransactionViewModelTest.getRandomTransactionTrits(); + byte[] trits = TransactionViewModelTest.getRandomTransactionTrits(); Hash hash = Hash.calculate(SpongeFactory.Mode.CURLP81, trits); Assert.assertEquals(hash.compareTo(Hash.NULL_HASH), -Hash.NULL_HASH.compareTo(hash)); } diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java index dc5808cd0e..36625bb328 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/EntryPointSelectorImplTest.java @@ -26,7 +26,7 @@ public class EntryPointSelectorImplTest { @Test public void testEntryPointWithTangleData() throws Exception { - Hash milestoneHash = Hash.calculate(SpongeFactory.Mode.CURLP81, new int[]{1}); + Hash milestoneHash = Hash.calculate(SpongeFactory.Mode.CURLP81, new byte[]{1}); mockTangleBehavior(milestoneHash); mockMilestoneTrackerBehavior(0, Hash.NULL_HASH); diff --git a/src/test/java/com/iota/iri/storage/TangleTest.java b/src/test/java/com/iota/iri/storage/TangleTest.java index 34de4831ac..3b9435183d 100644 --- a/src/test/java/com/iota/iri/storage/TangleTest.java +++ b/src/test/java/com/iota/iri/storage/TangleTest.java @@ -4,11 +4,13 @@ import com.iota.iri.hash.Sponge; import com.iota.iri.hash.SpongeFactory; import com.iota.iri.model.Hash; +import com.iota.iri.model.Tag; import com.iota.iri.model.Transaction; import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; import com.iota.iri.utils.Converter; import com.iota.iri.controllers.TransactionViewModel; import org.junit.After; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -18,15 +20,15 @@ import java.util.Set; import static com.iota.iri.controllers.TransactionViewModelTest.getRandomTransactionTrits; +import static org.junit.Assert.assertTrue; -/** - * Created by paul on 3/3/17 for iri. - */ public class TangleTest { private final TemporaryFolder dbFolder = new TemporaryFolder(); private final TemporaryFolder logFolder = new TemporaryFolder(); private Tangle tangle = new Tangle(); + private static final Random seed = new Random(); + @Before public void setUp() throws Exception { TemporaryFolder dbFolder = new TemporaryFolder(), logFolder = new TemporaryFolder(); @@ -46,47 +48,29 @@ public void tearDown() throws Exception { @Test public void save() throws Exception { - Transaction transaction = new Transaction(); - Random r = new Random(); - int[] hash = new int[Curl.HASH_LENGTH], - trits = Arrays.stream(new int[TransactionViewModel.TRINARY_SIZE]) - .map(i -> r.nextInt(3)-1).toArray(); - Sponge curl = SpongeFactory.create(SpongeFactory.Mode.CURLP81); - curl.absorb(trits, 0, trits.length); - curl.squeeze(hash, 0, Curl.HASH_LENGTH); - transaction.bytes = Converter.allocateBytesForTrits(trits.length); - Converter.bytes(trits, transaction.bytes); - - //assertTrue("Should be a new, unique transaction", !Tangle.instance().save(transaction).get()); } @Test public void getKeysStartingWithValue() throws Exception { - int[] trits = getRandomTransactionTrits(); + byte[] trits = getRandomTransactionTrits(); TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(SpongeFactory.Mode.CURLP81, trits)); transactionViewModel.store(tangle); - Set tag = tangle.keysStartingWith(Transaction.class, Arrays.copyOf(transactionViewModel.getTagValue().bytes(), 15)); - //Assert.assertNotEquals(tag.length, 0); + Set tag = tangle.keysStartingWith(Tag.class, Arrays.copyOf(transactionViewModel.getTagValue().bytes(), 15)); + Assert.assertNotEquals(tag.size(), 0); } @Test public void get() throws Exception { - /* - Transaction transaction = new Transaction(); - Random r = new Random(); - int[] hash = new int[Curl.HASH_LENGTH], - trits = Arrays.stream(new int[TransactionViewModel.TRINARY_SIZE]) - .map(i -> r.nextInt(3)-1).toArray(); - Curl curl = new Curl(); - curl.absorb(trits, 0, trits.length); - curl.squeeze(hash, 0, Curl.HASH_LENGTH); - transaction.value = Converter.value(trits); - byte[] byteHash = Converter.value(hash); + } + + public static byte[] getRandomTransactionTrits() { + byte[] out = new byte[TransactionViewModel.TRINARY_SIZE]; + + for(int i = 0; i < out.length; i++) { + out[i] = (byte) (seed.nextInt(3) - 1); + } - transaction = (Transaction) Tangle.instance().load(Transaction.class, byteHash).get(); - assertNotNull(transaction); - assertArrayEquals(transaction.hash, byteHash); - */ + return out; } } \ No newline at end of file From 3cc210d2748d8594517c4642b9702e003b526d2a Mon Sep 17 00:00:00 2001 From: Alon Elmaliah Date: Sat, 21 Jul 2018 23:17:09 +0300 Subject: [PATCH 02/26] make codacy changes --- src/test/java/com/iota/iri/hash/KerlTest.java | 2 +- src/test/java/com/iota/iri/storage/TangleTest.java | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/iota/iri/hash/KerlTest.java b/src/test/java/com/iota/iri/hash/KerlTest.java index c054ddb418..4cd5245e1d 100644 --- a/src/test/java/com/iota/iri/hash/KerlTest.java +++ b/src/test/java/com/iota/iri/hash/KerlTest.java @@ -17,6 +17,7 @@ public class KerlTest { final static Random seed = new Random(); Logger log = LoggerFactory.getLogger(CurlTest.class); + final static Random rnd_seed = new Random(); //Test conversion functions: @Test @@ -197,7 +198,6 @@ public void kerlMultiAbsorbMultiSqueeze() throws Exception { String hash = Converter.trytes(hash_value); Assert.assertEquals("LUCKQVACOGBFYSPPVSSOXJEKNSQQRQKPZC9NXFSMQNRQCGGUL9OHVVKBDSKEQEBKXRNUJSRXYVHJTXBPDWQGNSCDCBAIRHAQCOWZEBSNHIJIGPZQITIBJQ9LNTDIBTCQ9EUWKHFLGFUVGGUWJONK9GBCDUIMAYMMQX", hash); } - final static Random rnd_seed = new Random(); public static byte[] getRandomTrits(int length) { byte[] out = new byte[length]; diff --git a/src/test/java/com/iota/iri/storage/TangleTest.java b/src/test/java/com/iota/iri/storage/TangleTest.java index 3b9435183d..9fa3b102dd 100644 --- a/src/test/java/com/iota/iri/storage/TangleTest.java +++ b/src/test/java/com/iota/iri/storage/TangleTest.java @@ -1,14 +1,10 @@ package com.iota.iri.storage; -import com.iota.iri.hash.Curl; -import com.iota.iri.hash.Sponge; +import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.hash.SpongeFactory; import com.iota.iri.model.Hash; import com.iota.iri.model.Tag; -import com.iota.iri.model.Transaction; import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; -import com.iota.iri.utils.Converter; -import com.iota.iri.controllers.TransactionViewModel; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -19,9 +15,6 @@ import java.util.Random; import java.util.Set; -import static com.iota.iri.controllers.TransactionViewModelTest.getRandomTransactionTrits; -import static org.junit.Assert.assertTrue; - public class TangleTest { private final TemporaryFolder dbFolder = new TemporaryFolder(); private final TemporaryFolder logFolder = new TemporaryFolder(); @@ -31,7 +24,6 @@ public class TangleTest { @Before public void setUp() throws Exception { - TemporaryFolder dbFolder = new TemporaryFolder(), logFolder = new TemporaryFolder(); dbFolder.create(); logFolder.create(); RocksDBPersistenceProvider rocksDBPersistenceProvider; From 527e8b061c3f98a95d32bd0a8e00bf2629005d5f Mon Sep 17 00:00:00 2001 From: Andrea V Date: Sun, 22 Jul 2018 10:37:18 +0200 Subject: [PATCH 03/26] PPA webupd8team bumped Java to 8u181-1~webupd8~1 (#878) 8u171-1 is not in release anymore and Dockerfile does not build. --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0c1216b3f5..d901c9a66e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM ubuntu:18.04 as local_stage_java MAINTAINER giorgio@iota.org # Install Java -ARG JAVA_VERSION=8u171-1 +ARG JAVA_VERSION=8u181-1 RUN \ apt-get update && \ apt-get install -y software-properties-common --no-install-recommends && \ From b9371a4a762c02dec10d1f11a2e4c1e3b27cfb0b Mon Sep 17 00:00:00 2001 From: alon-e Date: Sun, 22 Jul 2018 11:38:23 +0300 Subject: [PATCH 04/26] make tx validate input type more explicit, MIN/MAX values of trit/trytes in bytes. --- .../com/iota/iri/TransactionValidator.java | 18 +++++++++--------- .../java/com/iota/iri/hash/ISSInPlace.java | 4 ++-- src/main/java/com/iota/iri/service/API.java | 6 +++--- .../com/iota/iri/TransactionValidatorTest.java | 8 ++++---- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/iota/iri/TransactionValidator.java b/src/main/java/com/iota/iri/TransactionValidator.java index b4e7b81480..bd135c871a 100644 --- a/src/main/java/com/iota/iri/TransactionValidator.java +++ b/src/main/java/com/iota/iri/TransactionValidator.java @@ -104,17 +104,17 @@ public static void runValidation(TransactionViewModel transactionViewModel, fina } } - public static TransactionViewModel validate(final byte[] trits, int minWeightMagnitude) { - if(trits.length == 8019) { - TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81))); - runValidation(transactionViewModel, minWeightMagnitude); - return transactionViewModel; - } else { - return validate(trits, minWeightMagnitude, SpongeFactory.create(SpongeFactory.Mode.CURLP81)); - } + public static TransactionViewModel validateTrits(final byte[] trits, int minWeightMagnitude) { + TransactionViewModel transactionViewModel = new TransactionViewModel(trits, Hash.calculate(trits, 0, trits.length, SpongeFactory.create(SpongeFactory.Mode.CURLP81))); + runValidation(transactionViewModel, minWeightMagnitude); + return transactionViewModel; + } + + public static TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude) { + return validateBytes(bytes, minWeightMagnitude, SpongeFactory.create(SpongeFactory.Mode.CURLP81)); } - public static TransactionViewModel validate(final byte[] bytes, int minWeightMagnitude, Sponge curl) { + public static TransactionViewModel validateBytes(final byte[] bytes, int minWeightMagnitude, Sponge curl) { TransactionViewModel transactionViewModel = new TransactionViewModel(bytes, Hash.calculate(bytes, TransactionViewModel.TRINARY_SIZE, curl)); runValidation(transactionViewModel, minWeightMagnitude); return transactionViewModel; diff --git a/src/main/java/com/iota/iri/hash/ISSInPlace.java b/src/main/java/com/iota/iri/hash/ISSInPlace.java index 39a61e9ccb..4686dda633 100644 --- a/src/main/java/com/iota/iri/hash/ISSInPlace.java +++ b/src/main/java/com/iota/iri/hash/ISSInPlace.java @@ -13,8 +13,8 @@ public class ISSInPlace { public static final int TRYTE_WIDTH = 3; private static final int NUMBER_OF_SECURITY_LEVELS = 3; public static final int NORMALIZED_FRAGMENT_LENGTH = Kerl.HASH_LENGTH / TRYTE_WIDTH / NUMBER_OF_SECURITY_LEVELS; - private static final int MIN_TRIT_VALUE = -1, MAX_TRIT_VALUE = 1; - private static final int MIN_TRYTE_VALUE = -13, MAX_TRYTE_VALUE = 13; + private static final byte MIN_TRIT_VALUE = -1, MAX_TRIT_VALUE = 1; + private static final byte MIN_TRYTE_VALUE = -13, MAX_TRYTE_VALUE = 13; public static void subseed(SpongeFactory.Mode mode, byte[] subseed, int index) { diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java index 53a2055e65..9dc11a7afc 100644 --- a/src/main/java/com/iota/iri/service/API.java +++ b/src/main/java/com/iota/iri/service/API.java @@ -614,7 +614,7 @@ public void storeTransactionStatement(final List trys) throws Exception for (final String trytes : trys) { //validate all trytes Converter.trits(trytes, txTrits, 0); - final TransactionViewModel transactionViewModel = instance.transactionValidator.validate(txTrits, + final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(txTrits, instance.transactionValidator.getMinWeightMagnitude()); elements.add(transactionViewModel); } @@ -834,7 +834,7 @@ public void broadcastTransactionStatement(final List trytes2) { for (final String tryte : trytes2) { //validate all trytes Converter.trits(tryte, txTrits, 0); - final TransactionViewModel transactionViewModel = instance.transactionValidator.validate(txTrits, instance.transactionValidator.getMinWeightMagnitude()); + final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(txTrits, instance.transactionValidator.getMinWeightMagnitude()); elements.add(transactionViewModel); } for (final TransactionViewModel transactionViewModel : elements) { @@ -953,7 +953,7 @@ public synchronized List attachToTangleStatement(final Hash trunkTransac break; } //validate PoW - throws exception if invalid - final TransactionViewModel transactionViewModel = instance.transactionValidator.validate(transactionTrits, instance.transactionValidator.getMinWeightMagnitude()); + final TransactionViewModel transactionViewModel = instance.transactionValidator.validateTrits(transactionTrits, instance.transactionValidator.getMinWeightMagnitude()); transactionViewModels.add(transactionViewModel); prevTransaction = transactionViewModel.getHash(); diff --git a/src/test/java/com/iota/iri/TransactionValidatorTest.java b/src/test/java/com/iota/iri/TransactionValidatorTest.java index 85942fe6e3..408b34254e 100644 --- a/src/test/java/com/iota/iri/TransactionValidatorTest.java +++ b/src/test/java/com/iota/iri/TransactionValidatorTest.java @@ -69,20 +69,20 @@ public void validateBytes() throws Exception { Converter.copyTrits(0, trits, 0, trits.length); byte[] bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, bytes); - TransactionValidator.validate(bytes, MAINNET_MWM); + TransactionValidator.validateBytes(bytes, MAINNET_MWM); } @Test public void validateTrits() { byte[] trits = getRandomTransactionTrits(); Converter.copyTrits(0, trits, 0, trits.length); - TransactionValidator.validate(trits, MAINNET_MWM); + TransactionValidator.validateTrits(trits, MAINNET_MWM); } @Test(expected = RuntimeException.class) public void validateTritsWithInvalidMetadata() { byte[] trits = getRandomTransactionTrits(); - TransactionValidator.validate(trits, MAINNET_MWM); + TransactionValidator.validateTrits(trits, MAINNET_MWM); } @Test @@ -91,7 +91,7 @@ public void validateBytesWithNewCurl() throws Exception { Converter.copyTrits(0, trits, 0, trits.length); byte[] bytes = Converter.allocateBytesForTrits(trits.length); Converter.bytes(trits, 0, bytes, 0, trits.length); - TransactionValidator.validate(bytes, txValidator.getMinWeightMagnitude(), SpongeFactory.create(SpongeFactory.Mode.CURLP81)); + TransactionValidator.validateBytes(bytes, txValidator.getMinWeightMagnitude(), SpongeFactory.create(SpongeFactory.Mode.CURLP81)); } @Test From 862f5eb6623aaced6caf0167646c0ce46e6001fe Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Mon, 23 Jul 2018 20:40:22 +0300 Subject: [PATCH 05/26] bounded set wrapper --- .../collections/impl/BoundedSetWrapper.java | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java diff --git a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java new file mode 100644 index 0000000000..d2246923e8 --- /dev/null +++ b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java @@ -0,0 +1,173 @@ +package com.iota.iri.utils.collections.impl; + +import com.iota.iri.utils.collections.interfaces.BoundedCollection; +import com.iota.iri.utils.collections.interfaces.BoundedSet; +import org.apache.commons.collections4.SetUtils; + +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * A set that doesn't allow to add elements to it once it is full + * + * @param the type parameter + */ +public class BoundedSetWrapper implements BoundedSet{ + private final int maxSize; + private final Set delegate; + + /** + * Wraps the given set {@code c} + * + * @param c the set which you delegate the actions to + * @param maxSize the max size + * @throws NullPointerException if the {@code c} is null + * @throws IllegalArgumentException if {@code c} is larger than {@code maxSize} + */ + public BoundedSetWrapper(Set c, int maxSize) { + Objects.requireNonNull(c, "trying to wrap a null set"); + if (c.size() > maxSize) { + throw new IllegalArgumentException(String.format("The given set size %d is larger then maxSize %d", c.size(), + maxSize)); + } + this.maxSize = maxSize; + this.delegate = c; + } + + @Override + public int getMaxSize() { + return maxSize; + } + + @Override + public int size() { + return delegate.size(); + } + + @Override + public boolean isEmpty() { + return delegate.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return delegate.contains(o); + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public void forEach(Consumer action) { + delegate.forEach(action); + } + + @Override + public Object[] toArray() { + return delegate.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return delegate.toArray(a); + } + + @Override + public boolean add(E e) { + if (isFull()) { + Iterator iterator = delegate.iterator(); + iterator.next(); + iterator.remove(); + } + + return delegate.add(e); + } + + @Override + public boolean remove(Object o) { + return delegate.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return delegate.containsAll(c); + } + + @Override + public boolean addAll(Collection c) { + if (canCollectionBeFullyAdded(c)) { + return delegate.addAll(c); + } + else { + Set transform = new HashSet<>(c); + Set difference = SetUtils.difference(delegate, transform).toSet(); + if (difference.size() > getMaxSize()) { + throw new IllegalArgumentException(String.format("The given set size %d is larger then maxSize %d", + difference.size(), maxSize)); + } + int itemsToDelete = delegate.size() + difference.size() - getMaxSize(); + Iterator iterator = delegate.iterator(); + for (int i = 0; i < itemsToDelete; i++) { + iterator.next(); + iterator.remove(); + } + return delegate.addAll(c); + } + } + + @Override + public boolean removeAll(Collection c) { + return delegate.removeAll(c); + } + + @Override + public boolean removeIf(Predicate filter) { + return delegate.removeIf(filter); + } + + @Override + public boolean retainAll(Collection c) { + return delegate.retainAll(c); + } + + @Override + public void clear() { + delegate.clear(); + } + + @Override + public Spliterator spliterator() { + return delegate.spliterator(); + } + + @Override + public Stream stream() { + return delegate.stream(); + } + + @Override + public Stream parallelStream() { + return delegate.parallelStream(); + } + + @Override + public boolean equals(Object obj) { + return delegate.equals(obj); + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } + + @Override + public String toString() { + return delegate.toString(); + } +} From f994ba5fe5700ef6c09fe41c088a77553e305448 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Mon, 23 Jul 2018 20:40:46 +0300 Subject: [PATCH 06/26] below max-depth cached --- .../service/tipselection/WalkValidator.java | 10 ++ .../tipselection/impl/WalkValidatorImpl.java | 31 ++++- .../impl/WalkValidatorImplTest.java | 106 +++++++++++++++++- .../impl/BoundedSetWrapperTest.java | 7 ++ 4 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java diff --git a/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java b/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java index 595dd36354..6529b4a685 100644 --- a/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java +++ b/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java @@ -1,6 +1,12 @@ package com.iota.iri.service.tipselection; +import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.model.Hash; +import com.iota.iri.utils.collections.impl.BoundedHashSet; +import com.iota.iri.utils.collections.interfaces.BoundedSet; + +import java.util.LinkedHashSet; +import java.util.Set; /** * Validates consistency of tails. @@ -8,6 +14,10 @@ @FunctionalInterface public interface WalkValidator { + int MAX_CACHE_SIZE = 2_000_000; + //As long as tip selection is synchronized we are fine with the collection not being thread safe + BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedHashSet<>(20_000, MAX_CACHE_SIZE); + /** * Validation *

diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index d17f9452b4..be1d3458c4 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -7,6 +7,8 @@ import com.iota.iri.Milestone; import com.iota.iri.service.tipselection.WalkValidator; import com.iota.iri.storage.Tangle; +import com.iota.iri.utils.collections.impl.BoundedSetWrapper; +import com.iota.iri.utils.collections.interfaces.BoundedSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +28,12 @@ */ public class WalkValidatorImpl implements WalkValidator { + public static final int MAX_CACHE_SIZE = 2_000_000; + //As long as tip selection is synchronized we are fine with the collection not being thread safe + private static final BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedSetWrapper<>( + new LinkedHashSet<>(10_000), MAX_CACHE_SIZE); + public static final int MAX_ANALYZED_TXS = 10_000; + private final Tangle tangle; private final Logger log = LoggerFactory.getLogger(WalkValidator.class); private final LedgerValidator ledgerValidator; @@ -55,7 +63,6 @@ public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, Transac public boolean isValid(Hash transactionHash) throws Exception { TransactionViewModel transactionViewModel = TransactionViewModel.fromHash(tangle, transactionHash); - if (transactionViewModel.getType() == TransactionViewModel.PREFILLED_SLOT) { log.debug("Validation failed: {} is missing in db", transactionHash); return false; @@ -75,9 +82,9 @@ public boolean isValid(Hash transactionHash) throws Exception { return true; } - private boolean belowMaxDepth(Hash tip, int depth) throws Exception { + private boolean belowMaxDepth(Hash tip, int allowedSnapshotIndex) throws Exception { //if tip is confirmed stop - if (TransactionViewModel.fromHash(tangle, tip).snapshotIndex() >= depth) { + if (TransactionViewModel.fromHash(tangle, tip).snapshotIndex() >= allowedSnapshotIndex) { return false; } //if tip unconfirmed, check if any referenced tx is confirmed below maxDepth @@ -85,9 +92,20 @@ private boolean belowMaxDepth(Hash tip, int depth) throws Exception { Set analyzedTransactions = new HashSet<>(); Hash hash; while ((hash = nonAnalyzedTransactions.poll()) != null) { + if (FAILED_BELOW_MAX_DEPTH_CACHE.contains(hash)) { + updateCache(analyzedTransactions); + return true; + } + if (analyzedTransactions.size() == MAX_ANALYZED_TXS) { + updateCache(analyzedTransactions); + return true; + } + if (analyzedTransactions.add(hash)) { TransactionViewModel transaction = TransactionViewModel.fromHash(tangle, hash); - if (transaction.snapshotIndex() != 0 && transaction.snapshotIndex() < depth) { + if ((transaction.snapshotIndex() != 0 || Objects.equals(Hash.NULL_HASH, transaction.getHash())) + && transaction.snapshotIndex() < allowedSnapshotIndex) { + updateCache(analyzedTransactions); return true; } if (transaction.snapshotIndex() == 0) { @@ -101,4 +119,9 @@ private boolean belowMaxDepth(Hash tip, int depth) throws Exception { maxDepthOkMemoization.add(tip); return false; } + + private void updateCache(Set txsToBeAdded) { + FAILED_BELOW_MAX_DEPTH_CACHE.addAll(txsToBeAdded); + } + } diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java index 6199f4ee46..0cbe7acbb8 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java @@ -5,7 +5,9 @@ import com.iota.iri.TransactionTestUtils; import com.iota.iri.TransactionValidator; import com.iota.iri.controllers.TransactionViewModel; +import com.iota.iri.controllers.TransactionViewModelTest; import com.iota.iri.model.Hash; +import com.iota.iri.model.Transaction; import com.iota.iri.storage.Tangle; import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; import org.junit.AfterClass; @@ -52,6 +54,7 @@ public static void setUp() throws Exception { @Test public void shouldPassValidation() throws Exception { + int depth = 15; TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); Hash hash = tx.getHash(); @@ -59,14 +62,15 @@ public void shouldPassValidation() throws Exception { .thenReturn(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); - milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; + milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, depth); Assert.assertTrue("Validation failed", walkValidator.isValid(hash)); } @Test public void failOnTxType() throws Exception { + int depth = 15; TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); Hash hash = tx.getTrunkTransactionHash(); @@ -74,9 +78,9 @@ public void failOnTxType() throws Exception { .thenReturn(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); - milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; + milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, depth); Assert.assertFalse("Validation succeded but should have failed since tx is missing", walkValidator.isValid(hash)); } @@ -112,7 +116,7 @@ public void failOnSolid() throws Exception { } @Test - public void failOnBelowMaxDepth() throws Exception { + public void failOnBelowMaxDepthDueToOldMilestone() throws Exception { TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); tx.setSnapshot(tangle, 2); @@ -123,10 +127,100 @@ public void failOnBelowMaxDepth() throws Exception { .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); - Assert.assertFalse("Validation succeded but should have failed tx is below max depth", + Assert.assertFalse("Validation succeeded but should have failed tx is below max depth", + walkValidator.isValid(hash)); + } + + @Test + public void belowMaxDepthWithFreshMilestone() throws Exception { + TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); + tx.store(tangle); + tx.setSnapshot(tangle, 92); + Hash hash = tx.getHash(); + for (int i = 0; i < 4 ; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + TransactionTestUtils.setLastIndex(tx,0); + TransactionTestUtils.setCurrentIndex(tx,0); + hash = tx.getHash(); + tx.store(tangle); + } + Mockito.when(transactionValidator.checkSolidity(hash, false)) + .thenReturn(true); + Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) + .thenReturn(true); + milestoneTracker.latestSolidSubtangleMilestoneIndex = 100; + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + Assert.assertTrue("Validation failed but should have succeeded since tx is above max depth", + walkValidator.isValid(hash)); + } + + @Test + public void failBelowMaxDepthWithFreshMilestoneDueToLongChain() throws Exception { + TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); + tx.store(tangle); + tx.setSnapshot(tangle, 92); + Hash hash = tx.getHash(); + for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS ; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + TransactionTestUtils.setLastIndex(tx,0); + TransactionTestUtils.setCurrentIndex(tx,0); + hash = tx.getHash(); + tx.store(tangle); + } + Mockito.when(transactionValidator.checkSolidity(hash, false)) + .thenReturn(true); + Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) + .thenReturn(true); + milestoneTracker.latestSolidSubtangleMilestoneIndex = 100; + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + Assert.assertFalse("Validation succeeded but should have failed since tx is below max depth", walkValidator.isValid(hash)); } + @Test + public void belowMaxDepthOnGenesis() throws Exception { + TransactionViewModel tx = null; + Hash hash = Hash.NULL_HASH; + for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS - 2 ; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + TransactionTestUtils.setLastIndex(tx,0); + TransactionTestUtils.setCurrentIndex(tx,0); + hash = tx.getHash(); + tx.store(tangle); + } + Mockito.when(transactionValidator.checkSolidity(tx.getHash(), false)) + .thenReturn(true); + Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash())) + .thenReturn(true); + milestoneTracker.latestSolidSubtangleMilestoneIndex = 15; + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + Assert.assertTrue("Validation failed but should have succeeded. We didn't exceed the maximal amount of" + + "transactions that may be analyzed.", + walkValidator.isValid(tx.getHash())); + } + + @Test + public void failBelowMaxDepthOnGenesisDueToLongChain() throws Exception { + TransactionViewModel tx = null; + Hash hash = Hash.NULL_HASH; + for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS ; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + TransactionTestUtils.setLastIndex(tx,0); + TransactionTestUtils.setCurrentIndex(tx,0); + tx.store(tangle); + hash = tx.getHash(); + } + Mockito.when(transactionValidator.checkSolidity(tx.getHash(), false)) + .thenReturn(true); + Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash())) + .thenReturn(true); + milestoneTracker.latestSolidSubtangleMilestoneIndex = 17; + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + Assert.assertFalse("Validation succeeded but should have failed. We exceeded the maximal amount of" + + "transactions that may be analyzed.", + walkValidator.isValid(tx.getHash())); + } + @Test public void failOnInconsistency() throws Exception { TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); diff --git a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java new file mode 100644 index 0000000000..6c11e23916 --- /dev/null +++ b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java @@ -0,0 +1,7 @@ +package com.iota.iri.utils.collections.impl; + +import static org.junit.Assert.*; + +public class BoundedSetWrapperTest { + +} \ No newline at end of file From 84d7bb9d828bcc94ef7cbbdae7f60d466669e47e Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 10:23:59 +0300 Subject: [PATCH 07/26] Fix WalkValidator --- .../iota/iri/service/tipselection/WalkValidator.java | 10 ---------- .../service/tipselection/impl/WalkValidatorImpl.java | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java b/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java index 6529b4a685..595dd36354 100644 --- a/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java +++ b/src/main/java/com/iota/iri/service/tipselection/WalkValidator.java @@ -1,12 +1,6 @@ package com.iota.iri.service.tipselection; -import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.model.Hash; -import com.iota.iri.utils.collections.impl.BoundedHashSet; -import com.iota.iri.utils.collections.interfaces.BoundedSet; - -import java.util.LinkedHashSet; -import java.util.Set; /** * Validates consistency of tails. @@ -14,10 +8,6 @@ @FunctionalInterface public interface WalkValidator { - int MAX_CACHE_SIZE = 2_000_000; - //As long as tip selection is synchronized we are fine with the collection not being thread safe - BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedHashSet<>(20_000, MAX_CACHE_SIZE); - /** * Validation *

diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index be1d3458c4..c4bb293b4e 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -82,9 +82,9 @@ public boolean isValid(Hash transactionHash) throws Exception { return true; } - private boolean belowMaxDepth(Hash tip, int allowedSnapshotIndex) throws Exception { + private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Exception { //if tip is confirmed stop - if (TransactionViewModel.fromHash(tangle, tip).snapshotIndex() >= allowedSnapshotIndex) { + if (TransactionViewModel.fromHash(tangle, tip).snapshotIndex() >= lowerAllowedSnapshotIndex) { return false; } //if tip unconfirmed, check if any referenced tx is confirmed below maxDepth @@ -104,7 +104,7 @@ private boolean belowMaxDepth(Hash tip, int allowedSnapshotIndex) throws Excepti if (analyzedTransactions.add(hash)) { TransactionViewModel transaction = TransactionViewModel.fromHash(tangle, hash); if ((transaction.snapshotIndex() != 0 || Objects.equals(Hash.NULL_HASH, transaction.getHash())) - && transaction.snapshotIndex() < allowedSnapshotIndex) { + && transaction.snapshotIndex() < lowerAllowedSnapshotIndex) { updateCache(analyzedTransactions); return true; } From d601753a03c59aa4c010fd93f637bd7a76b30d8e Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 10:24:39 +0300 Subject: [PATCH 08/26] change bounded set wrapper description --- .../iota/iri/utils/collections/impl/BoundedSetWrapper.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java index d2246923e8..68d0f23eb2 100644 --- a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java +++ b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java @@ -1,18 +1,19 @@ package com.iota.iri.utils.collections.impl; -import com.iota.iri.utils.collections.interfaces.BoundedCollection; import com.iota.iri.utils.collections.interfaces.BoundedSet; import org.apache.commons.collections4.SetUtils; import java.util.*; import java.util.function.Consumer; import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; /** - * A set that doesn't allow to add elements to it once it is full + * A wrapper for a set that allows up to {@code maxsize} elements. + * Old elements are removed once it is full and new elements are added. + * The way old elements are chosen depends on the underlying set implementation. + * * * @param the type parameter */ From fae76087b2d79bbc23000451d54476b5aa5eb732 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 10:56:08 +0300 Subject: [PATCH 09/26] add log messages --- .../service/tipselection/impl/WalkValidatorImpl.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index c4bb293b4e..2b3b6c1806 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -28,11 +28,12 @@ */ public class WalkValidatorImpl implements WalkValidator { + //calculate this magic number public static final int MAX_CACHE_SIZE = 2_000_000; //As long as tip selection is synchronized we are fine with the collection not being thread safe private static final BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedSetWrapper<>( new LinkedHashSet<>(10_000), MAX_CACHE_SIZE); - public static final int MAX_ANALYZED_TXS = 10_000; + private int maxAnalyzedTxs = 10_000; private final Tangle tangle; private final Logger log = LoggerFactory.getLogger(WalkValidator.class); @@ -93,10 +94,13 @@ private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Ex Hash hash; while ((hash = nonAnalyzedTransactions.poll()) != null) { if (FAILED_BELOW_MAX_DEPTH_CACHE.contains(hash)) { + log.debug("failed below max depth because of a previously failed tx cache hit"); updateCache(analyzedTransactions); return true; } - if (analyzedTransactions.size() == MAX_ANALYZED_TXS) { + if (analyzedTransactions.size() == maxAnalyzedTxs) { + log.debug("failed below max depth because of exceeding max threshold of {} analyzed transactions", + maxAnalyzedTxs); updateCache(analyzedTransactions); return true; } @@ -106,6 +110,8 @@ private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Ex if ((transaction.snapshotIndex() != 0 || Objects.equals(Hash.NULL_HASH, transaction.getHash())) && transaction.snapshotIndex() < lowerAllowedSnapshotIndex) { updateCache(analyzedTransactions); + log.debug("failed below max depth because of reaching a tx below the allowed snapshot index {}", + lowerAllowedSnapshotIndex); return true; } if (transaction.snapshotIndex() == 0) { From 9c1d623dcd81da51b6dbe8b05b9a4fe99daa24f4 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 12:16:24 +0300 Subject: [PATCH 10/26] add configuration for maximal number of transactions that may be analyzed by below_max_depth --- src/main/java/com/iota/iri/IRI.java | 9 +++++++++ src/main/java/com/iota/iri/Iota.java | 8 +++++--- src/main/java/com/iota/iri/conf/Configuration.java | 8 ++++---- .../iri/service/tipselection/impl/TipSelectorImpl.java | 8 ++++++-- .../iri/service/tipselection/impl/WalkValidatorImpl.java | 5 +++-- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/iota/iri/IRI.java b/src/main/java/com/iota/iri/IRI.java index 84311aa0d1..05911a40e1 100644 --- a/src/main/java/com/iota/iri/IRI.java +++ b/src/main/java/com/iota/iri/IRI.java @@ -154,6 +154,7 @@ private static boolean isValidated(final Configuration configuration, final Stri final Option milestoneStartIndex = parser.addIntegerOption("milestone-start"); final Option milestoneKeys = parser.addIntegerOption("milestone-keys"); final Option snapshotTime = parser.addLongOption("snapshot-timestamp"); + final Option belowMaxDepthTxLimit = parser.addIntegerOption("below-max-depth"); try { @@ -330,7 +331,15 @@ private static boolean isValidated(final Configuration configuration, final Stri if (vmaxPeers != null) { configuration.put(DefaultConfSettings.MAX_PEERS, vmaxPeers); } + + final Integer belowMaxDepthLimit = parser.getOptionValue(belowMaxDepthTxLimit); + if (belowMaxDepthLimit != null) { + configuration.put(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT, + String.valueOf(belowMaxDepthLimit)); + } + return true; + } private static void printUsage() { diff --git a/src/main/java/com/iota/iri/Iota.java b/src/main/java/com/iota/iri/Iota.java index 63048dee77..beea41adf7 100644 --- a/src/main/java/com/iota/iri/Iota.java +++ b/src/main/java/com/iota/iri/Iota.java @@ -66,6 +66,8 @@ public Iota(Configuration configuration) throws IOException { int milestoneStartIndex = configuration.integer(Configuration.DefaultConfSettings.MILESTONE_START_INDEX); int numKeysMilestone = configuration.integer(Configuration.DefaultConfSettings.NUMBER_OF_KEYS_IN_A_MILESTONE); double alpha = configuration.doubling(Configuration.DefaultConfSettings.TIPSELECTION_ALPHA.name()); + int belowMaxDepthTxLimit = configuration.integer( + Configuration.DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT); boolean dontValidateMilestoneSig = configuration.booling(Configuration.DefaultConfSettings .DONT_VALIDATE_TESTNET_MILESTONE_SIG); @@ -101,7 +103,7 @@ public Iota(Configuration configuration) throws IOException { udpReceiver = new UDPReceiver(udpPort, node, configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE)); ledgerValidator = new LedgerValidator(tangle, milestone, transactionRequester, messageQ); tipsSolidifier = new TipsSolidifier(tangle, transactionValidator, tipsViewModel); - tipsSelector = createTipSelector(milestoneStartIndex, alpha); + tipsSelector = createTipSelector(milestoneStartIndex, alpha, belowMaxDepthTxLimit); } public void init() throws Exception { @@ -198,12 +200,12 @@ private void initializeTangle() { } } - private TipSelector createTipSelector(int milestoneStartIndex, double alpha) { + private TipSelector createTipSelector(int milestoneStartIndex, double alpha, int belowMaxDepthTxLimit) { EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, milestone, testnet, milestoneStartIndex); RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle); TailFinder tailFinder = new TailFinderImpl(tangle); Walker walker = new WalkerAlpha(alpha, new SecureRandom(), tangle, messageQ, tailFinder); return new TipSelectorImpl(tangle, ledgerValidator, transactionValidator, entryPointSelector, ratingCalculator, - walker, milestone, maxTipSearchDepth); + walker, milestone, maxTipSearchDepth, belowMaxDepthTxLimit); } } diff --git a/src/main/java/com/iota/iri/conf/Configuration.java b/src/main/java/com/iota/iri/conf/Configuration.java index 0cdd1c7851..1b82c9c5da 100644 --- a/src/main/java/com/iota/iri/conf/Configuration.java +++ b/src/main/java/com/iota/iri/conf/Configuration.java @@ -48,7 +48,7 @@ public class Configuration { public static final String TESTNET_PACKET_SIZE = "1653"; public static final String REQ_HASH_SIZE = "46"; public static final String TESTNET_REQ_HASH_SIZE = "49"; - + public static final String BELOW_MAX_DEPTH_LIMIT = "20000"; @@ -104,11 +104,11 @@ public enum DefaultConfSettings { TRANSACTION_PACKET_SIZE, REQUEST_HASH_SIZE, SNAPSHOT_TIME, - TIPSELECTION_ALPHA + TIPSELECTION_ALPHA, + BELOW_MAX_DEPTH_TRANSACTION_LIMIT } - { // defaults conf.put(DefaultConfSettings.PORT.name(), "14600"); @@ -170,7 +170,7 @@ public enum DefaultConfSettings { conf.put(DefaultConfSettings.REQUEST_HASH_SIZE.name(), REQ_HASH_SIZE); conf.put(DefaultConfSettings.SNAPSHOT_TIME.name(), GLOBAL_SNAPSHOT_TIME); conf.put(DefaultConfSettings.TIPSELECTION_ALPHA.name(), "0.001"); - + conf.put(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT.name(), BELOW_MAX_DEPTH_LIMIT); } public boolean init() throws IOException { diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java index d7e4e66977..831b2f5594 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java @@ -33,6 +33,7 @@ public class TipSelectorImpl implements TipSelector { private final TransactionValidator transactionValidator; private final Tangle tangle; private final Milestone milestone; + private final int belowMaxDepthTxLimit; @Override public int getMaxDepth() { @@ -46,7 +47,9 @@ public TipSelectorImpl(Tangle tangle, RatingCalculator ratingCalculator, Walker walkerAlpha, Milestone milestone, - int maxDepth) { + int maxDepth, + int belowMaxDepthTxLimit) { + this.entryPointSelector = entryPointSelector; this.ratingCalculator = ratingCalculator; @@ -55,6 +58,7 @@ public TipSelectorImpl(Tangle tangle, //used by walkValidator this.maxDepth = maxDepth; + this.belowMaxDepthTxLimit = belowMaxDepthTxLimit; this.ledgerValidator = ledgerValidator; this.transactionValidator = transactionValidator; this.tangle = tangle; @@ -89,7 +93,7 @@ public List getTransactionsToApprove(int depth, Optional reference) //random walk List tips = new LinkedList<>(); WalkValidator walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestone, - maxDepth); + maxDepth, belowMaxDepthTxLimit); Hash tip = walker.walk(entryPoint, rating, walkValidator); tips.add(tip); diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index 2b3b6c1806..dbeab5e7b5 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -33,7 +33,7 @@ public class WalkValidatorImpl implements WalkValidator { //As long as tip selection is synchronized we are fine with the collection not being thread safe private static final BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedSetWrapper<>( new LinkedHashSet<>(10_000), MAX_CACHE_SIZE); - private int maxAnalyzedTxs = 10_000; + private int maxAnalyzedTxs; private final Tangle tangle; private final Logger log = LoggerFactory.getLogger(WalkValidator.class); @@ -48,12 +48,13 @@ public class WalkValidatorImpl implements WalkValidator { private Set myApprovedHashes; public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, TransactionValidator transactionValidator, - Milestone milestone, int maxDepth) { + Milestone milestone, int maxDepth, int maxAnalyzedTxs) { this.tangle = tangle; this.ledgerValidator = ledgerValidator; this.transactionValidator = transactionValidator; this.milestone = milestone; this.maxDepth = maxDepth; + this.maxAnalyzedTxs = maxAnalyzedTxs; maxDepthOkMemoization = new HashSet<>(); myDiff = new HashMap<>(); From a598ec010b5306effd735dda5dccac20a907641f Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 12:27:22 +0300 Subject: [PATCH 11/26] add below max_depth to check consistency api call --- src/main/java/com/iota/iri/service/API.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java index 9dc11a7afc..b1c2759d90 100644 --- a/src/main/java/com/iota/iri/service/API.java +++ b/src/main/java/com/iota/iri/service/API.java @@ -16,6 +16,7 @@ import com.iota.iri.model.Hash; import com.iota.iri.network.Neighbor; import com.iota.iri.service.dto.*; +import com.iota.iri.service.tipselection.impl.WalkValidatorImpl; import com.iota.iri.utils.Converter; import com.iota.iri.utils.IotaIOUtils; import com.iota.iri.utils.MapIdentityManager; @@ -457,17 +458,22 @@ private AbstractResponse checkConsistencyStatement(List transactionsList if (state) { instance.milestone.latestSnapshot.rwlock.readLock().lock(); try { - - if (!instance.ledgerValidator.checkConsistency(transactions)) { - state = false; - info = "tails are not consistent (would lead to inconsistent ledger state)"; + WalkValidatorImpl walkValidator = new WalkValidatorImpl(instance.tangle, instance.ledgerValidator, + instance.transactionValidator, instance.milestone, instance.tipsSelector.getMaxDepth(), + instance.configuration.integer(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT)); + for (Hash transaction : transactions) { + if (!walkValidator.isValid(transaction)) { + state = false; + info = "tails are not consistent (would lead to inconsistent ledger state or below max depth)"; + break; + } } } finally { instance.milestone.latestSnapshot.rwlock.readLock().unlock(); } } - return CheckConsistency.create(state,info); + return CheckConsistency.create(state, info); } private double getParameterAsDouble(Map request, String paramName) throws ValidationException { From 137fa50b4a4b172a7992afbc178b25b160b32b97 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 13:02:27 +0300 Subject: [PATCH 12/26] add walk validator cache size to configurations --- src/main/java/com/iota/iri/Iota.java | 8 ++++--- .../java/com/iota/iri/conf/Configuration.java | 6 +++++- src/main/java/com/iota/iri/service/API.java | 3 ++- .../tipselection/impl/TipSelectorImpl.java | 7 +++++-- .../tipselection/impl/WalkValidatorImpl.java | 21 ++++++++++++------- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/iota/iri/Iota.java b/src/main/java/com/iota/iri/Iota.java index beea41adf7..94fe8ea2cf 100644 --- a/src/main/java/com/iota/iri/Iota.java +++ b/src/main/java/com/iota/iri/Iota.java @@ -68,6 +68,7 @@ public Iota(Configuration configuration) throws IOException { double alpha = configuration.doubling(Configuration.DefaultConfSettings.TIPSELECTION_ALPHA.name()); int belowMaxDepthTxLimit = configuration.integer( Configuration.DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT); + int walkValidatorCacheSize = configuration.integer(Configuration.DefaultConfSettings.WALK_VALIDATOR_CACHE_SIZE); boolean dontValidateMilestoneSig = configuration.booling(Configuration.DefaultConfSettings .DONT_VALIDATE_TESTNET_MILESTONE_SIG); @@ -103,7 +104,7 @@ public Iota(Configuration configuration) throws IOException { udpReceiver = new UDPReceiver(udpPort, node, configuration.integer(Configuration.DefaultConfSettings.TRANSACTION_PACKET_SIZE)); ledgerValidator = new LedgerValidator(tangle, milestone, transactionRequester, messageQ); tipsSolidifier = new TipsSolidifier(tangle, transactionValidator, tipsViewModel); - tipsSelector = createTipSelector(milestoneStartIndex, alpha, belowMaxDepthTxLimit); + tipsSelector = createTipSelector(milestoneStartIndex, alpha, belowMaxDepthTxLimit, walkValidatorCacheSize); } public void init() throws Exception { @@ -200,12 +201,13 @@ private void initializeTangle() { } } - private TipSelector createTipSelector(int milestoneStartIndex, double alpha, int belowMaxDepthTxLimit) { + private TipSelector createTipSelector(int milestoneStartIndex, double alpha, int belowMaxDepthTxLimit, + int walkValidatorCacheSize) { EntryPointSelector entryPointSelector = new EntryPointSelectorImpl(tangle, milestone, testnet, milestoneStartIndex); RatingCalculator ratingCalculator = new CumulativeWeightCalculator(tangle); TailFinder tailFinder = new TailFinderImpl(tangle); Walker walker = new WalkerAlpha(alpha, new SecureRandom(), tangle, messageQ, tailFinder); return new TipSelectorImpl(tangle, ledgerValidator, transactionValidator, entryPointSelector, ratingCalculator, - walker, milestone, maxTipSearchDepth, belowMaxDepthTxLimit); + walker, milestone, maxTipSearchDepth, belowMaxDepthTxLimit, walkValidatorCacheSize); } } diff --git a/src/main/java/com/iota/iri/conf/Configuration.java b/src/main/java/com/iota/iri/conf/Configuration.java index 1b82c9c5da..087e03b633 100644 --- a/src/main/java/com/iota/iri/conf/Configuration.java +++ b/src/main/java/com/iota/iri/conf/Configuration.java @@ -49,6 +49,7 @@ public class Configuration { public static final String REQ_HASH_SIZE = "46"; public static final String TESTNET_REQ_HASH_SIZE = "49"; public static final String BELOW_MAX_DEPTH_LIMIT = "20000"; + public static final String WALK_VALIDATOR_CACHE = "20000"; @@ -105,10 +106,12 @@ public enum DefaultConfSettings { REQUEST_HASH_SIZE, SNAPSHOT_TIME, TIPSELECTION_ALPHA, - BELOW_MAX_DEPTH_TRANSACTION_LIMIT + BELOW_MAX_DEPTH_TRANSACTION_LIMIT, + WALK_VALIDATOR_CACHE_SIZE } + { // defaults conf.put(DefaultConfSettings.PORT.name(), "14600"); @@ -171,6 +174,7 @@ public enum DefaultConfSettings { conf.put(DefaultConfSettings.SNAPSHOT_TIME.name(), GLOBAL_SNAPSHOT_TIME); conf.put(DefaultConfSettings.TIPSELECTION_ALPHA.name(), "0.001"); conf.put(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT.name(), BELOW_MAX_DEPTH_LIMIT); + conf.put(DefaultConfSettings.WALK_VALIDATOR_CACHE_SIZE.name(), WALK_VALIDATOR_CACHE); } public boolean init() throws IOException { diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java index b1c2759d90..d03257e9eb 100644 --- a/src/main/java/com/iota/iri/service/API.java +++ b/src/main/java/com/iota/iri/service/API.java @@ -460,7 +460,8 @@ private AbstractResponse checkConsistencyStatement(List transactionsList try { WalkValidatorImpl walkValidator = new WalkValidatorImpl(instance.tangle, instance.ledgerValidator, instance.transactionValidator, instance.milestone, instance.tipsSelector.getMaxDepth(), - instance.configuration.integer(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT)); + instance.configuration.integer(DefaultConfSettings.BELOW_MAX_DEPTH_TRANSACTION_LIMIT), + instance.configuration.integer(DefaultConfSettings.WALK_VALIDATOR_CACHE_SIZE)); for (Hash transaction : transactions) { if (!walkValidator.isValid(transaction)) { state = false; diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java index 831b2f5594..5ad3332814 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/TipSelectorImpl.java @@ -34,6 +34,7 @@ public class TipSelectorImpl implements TipSelector { private final Tangle tangle; private final Milestone milestone; private final int belowMaxDepthTxLimit; + private final int validatorCacheSize; @Override public int getMaxDepth() { @@ -48,7 +49,8 @@ public TipSelectorImpl(Tangle tangle, Walker walkerAlpha, Milestone milestone, int maxDepth, - int belowMaxDepthTxLimit) { + int belowMaxDepthTxLimit, + int validatorCacheSize) { this.entryPointSelector = entryPointSelector; @@ -63,6 +65,7 @@ public TipSelectorImpl(Tangle tangle, this.transactionValidator = transactionValidator; this.tangle = tangle; this.milestone = milestone; + this.validatorCacheSize = validatorCacheSize; } /** @@ -93,7 +96,7 @@ public List getTransactionsToApprove(int depth, Optional reference) //random walk List tips = new LinkedList<>(); WalkValidator walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestone, - maxDepth, belowMaxDepthTxLimit); + maxDepth, belowMaxDepthTxLimit, validatorCacheSize); Hash tip = walker.walk(entryPoint, rating, walkValidator); tips.add(tip); diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index dbeab5e7b5..dc648fc006 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -28,11 +28,9 @@ */ public class WalkValidatorImpl implements WalkValidator { - //calculate this magic number - public static final int MAX_CACHE_SIZE = 2_000_000; + public static final int INITIAL_CACHE_CAPACITY = 10_000; //As long as tip selection is synchronized we are fine with the collection not being thread safe - private static final BoundedSet FAILED_BELOW_MAX_DEPTH_CACHE = new BoundedSetWrapper<>( - new LinkedHashSet<>(10_000), MAX_CACHE_SIZE); + private static BoundedSet failedBelowMaxDepthCache; private int maxAnalyzedTxs; private final Tangle tangle; @@ -48,7 +46,7 @@ public class WalkValidatorImpl implements WalkValidator { private Set myApprovedHashes; public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, TransactionValidator transactionValidator, - Milestone milestone, int maxDepth, int maxAnalyzedTxs) { + Milestone milestone, int maxDepth, int maxAnalyzedTxs, int cacheSize) { this.tangle = tangle; this.ledgerValidator = ledgerValidator; this.transactionValidator = transactionValidator; @@ -56,11 +54,20 @@ public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, Transac this.maxDepth = maxDepth; this.maxAnalyzedTxs = maxAnalyzedTxs; + failedBelowMaxDepthCache = fetchCache(cacheSize); maxDepthOkMemoization = new HashSet<>(); myDiff = new HashMap<>(); myApprovedHashes = new HashSet<>(); } + private BoundedSet fetchCache(int cacheSize) { + if (failedBelowMaxDepthCache == null) { + failedBelowMaxDepthCache = new BoundedSetWrapper<>( + new LinkedHashSet<>(INITIAL_CACHE_CAPACITY), cacheSize); + } + return failedBelowMaxDepthCache; + } + @Override public boolean isValid(Hash transactionHash) throws Exception { @@ -94,7 +101,7 @@ private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Ex Set analyzedTransactions = new HashSet<>(); Hash hash; while ((hash = nonAnalyzedTransactions.poll()) != null) { - if (FAILED_BELOW_MAX_DEPTH_CACHE.contains(hash)) { + if (failedBelowMaxDepthCache.contains(hash)) { log.debug("failed below max depth because of a previously failed tx cache hit"); updateCache(analyzedTransactions); return true; @@ -128,7 +135,7 @@ private boolean belowMaxDepth(Hash tip, int lowerAllowedSnapshotIndex) throws Ex } private void updateCache(Set txsToBeAdded) { - FAILED_BELOW_MAX_DEPTH_CACHE.addAll(txsToBeAdded); + failedBelowMaxDepthCache.addAll(txsToBeAdded); } } From 3b37fbe7e7c2980a7f385071a2d2b20d92631dae Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 15:56:07 +0300 Subject: [PATCH 13/26] Fix walk validator test --- .../impl/WalkValidatorImplTest.java | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java index 0cbe7acbb8..3a56c1f78a 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java @@ -4,6 +4,7 @@ import com.iota.iri.Milestone; import com.iota.iri.TransactionTestUtils; import com.iota.iri.TransactionValidator; +import com.iota.iri.conf.Configuration; import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.controllers.TransactionViewModelTest; import com.iota.iri.model.Hash; @@ -64,7 +65,9 @@ public void shouldPassValidation() throws Exception { .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, depth); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, depth, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT) , + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertTrue("Validation failed", walkValidator.isValid(hash)); } @@ -80,7 +83,9 @@ public void failOnTxType() throws Exception { .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, depth); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, depth, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT), + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeded but should have failed since tx is missing", walkValidator.isValid(hash)); } @@ -95,7 +100,9 @@ public void failOnTxIndex() throws Exception { .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT), + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeded but should have failed since we are not on a tail", walkValidator.isValid(hash)); } @@ -110,7 +117,9 @@ public void failOnSolid() throws Exception { .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator,transactionValidator, + milestoneTracker, 15, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT) , + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeded but should have failed since tx is not solid", walkValidator.isValid(hash)); } @@ -126,7 +135,9 @@ public void failOnBelowMaxDepthDueToOldMilestone() throws Exception { Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT), + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeeded but should have failed tx is below max depth", walkValidator.isValid(hash)); } @@ -149,19 +160,23 @@ public void belowMaxDepthWithFreshMilestone() throws Exception { Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 100; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT) , + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertTrue("Validation failed but should have succeeded since tx is above max depth", walkValidator.isValid(hash)); } @Test public void failBelowMaxDepthWithFreshMilestoneDueToLongChain() throws Exception { + final int maxAnalyzedTxs = Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT); TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); tx.setSnapshot(tangle, 92); Hash hash = tx.getHash(); - for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS ; i++) { - tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + for (int i = 0; i < maxAnalyzedTxs ; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), + TransactionViewModelTest.getRandomTransactionHash()); TransactionTestUtils.setLastIndex(tx,0); TransactionTestUtils.setCurrentIndex(tx,0); hash = tx.getHash(); @@ -172,7 +187,9 @@ public void failBelowMaxDepthWithFreshMilestoneDueToLongChain() throws Exception Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 100; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, maxAnalyzedTxs, + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeeded but should have failed since tx is below max depth", walkValidator.isValid(hash)); } @@ -180,8 +197,9 @@ public void failBelowMaxDepthWithFreshMilestoneDueToLongChain() throws Exception @Test public void belowMaxDepthOnGenesis() throws Exception { TransactionViewModel tx = null; + final int maxAnalyzedTxs = Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT); Hash hash = Hash.NULL_HASH; - for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS - 2 ; i++) { + for (int i = 0; i < maxAnalyzedTxs - 2 ; i++) { tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); TransactionTestUtils.setLastIndex(tx,0); TransactionTestUtils.setCurrentIndex(tx,0); @@ -193,7 +211,9 @@ public void belowMaxDepthOnGenesis() throws Exception { Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash())) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 15; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, maxAnalyzedTxs, + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertTrue("Validation failed but should have succeeded. We didn't exceed the maximal amount of" + "transactions that may be analyzed.", walkValidator.isValid(tx.getHash())); @@ -201,10 +221,12 @@ public void belowMaxDepthOnGenesis() throws Exception { @Test public void failBelowMaxDepthOnGenesisDueToLongChain() throws Exception { + final int maxAnalyzedTxs = Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT); TransactionViewModel tx = null; Hash hash = Hash.NULL_HASH; - for (int i = 0; i < WalkValidatorImpl.MAX_ANALYZED_TXS ; i++) { - tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); + for (int i = 0; i < maxAnalyzedTxs; i++) { + tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), + TransactionViewModelTest.getRandomTransactionHash()); TransactionTestUtils.setLastIndex(tx,0); TransactionTestUtils.setCurrentIndex(tx,0); tx.store(tangle); @@ -215,7 +237,9 @@ public void failBelowMaxDepthOnGenesisDueToLongChain() throws Exception { Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash())) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 17; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, maxAnalyzedTxs, + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeeded but should have failed. We exceeded the maximal amount of" + "transactions that may be analyzed.", walkValidator.isValid(tx.getHash())); @@ -232,7 +256,9 @@ public void failOnInconsistency() throws Exception { .thenReturn(false); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; - WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, milestoneTracker, 15); + WalkValidatorImpl walkValidator = new WalkValidatorImpl(tangle, ledgerValidator, transactionValidator, + milestoneTracker, 15, Integer.parseInt(Configuration.BELOW_MAX_DEPTH_LIMIT), + Integer.parseInt(Configuration.WALK_VALIDATOR_CACHE)); Assert.assertFalse("Validation succeded but should have failed due to inconsistent ledger state", walkValidator.isValid(hash)); } From 207e6dc8a2452fd6644928a7e8339884191e44b0 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 16:26:59 +0300 Subject: [PATCH 14/26] fix cache size --- src/main/java/com/iota/iri/conf/Configuration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/iota/iri/conf/Configuration.java b/src/main/java/com/iota/iri/conf/Configuration.java index 087e03b633..ff40a90109 100644 --- a/src/main/java/com/iota/iri/conf/Configuration.java +++ b/src/main/java/com/iota/iri/conf/Configuration.java @@ -49,7 +49,7 @@ public class Configuration { public static final String REQ_HASH_SIZE = "46"; public static final String TESTNET_REQ_HASH_SIZE = "49"; public static final String BELOW_MAX_DEPTH_LIMIT = "20000"; - public static final String WALK_VALIDATOR_CACHE = "20000"; + public static final String WALK_VALIDATOR_CACHE = "200000"; From 59441fe8511a09e1a35ac246f8b2dc078961293f Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 16:59:59 +0300 Subject: [PATCH 15/26] fix add all in bounded Set Wrapper --- .../collections/impl/BoundedSetWrapper.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java index 68d0f23eb2..b3e515cc6f 100644 --- a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java +++ b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java @@ -31,10 +31,7 @@ public class BoundedSetWrapper implements BoundedSet{ */ public BoundedSetWrapper(Set c, int maxSize) { Objects.requireNonNull(c, "trying to wrap a null set"); - if (c.size() > maxSize) { - throw new IllegalArgumentException(String.format("The given set size %d is larger then maxSize %d", c.size(), - maxSize)); - } + requireCollectionIsNotAboveMaxSize(c, maxSize); this.maxSize = maxSize; this.delegate = c; } @@ -102,17 +99,12 @@ public boolean containsAll(Collection c) { @Override public boolean addAll(Collection c) { + requireCollectionIsNotAboveMaxSize(c, getMaxSize()); if (canCollectionBeFullyAdded(c)) { return delegate.addAll(c); } else { - Set transform = new HashSet<>(c); - Set difference = SetUtils.difference(delegate, transform).toSet(); - if (difference.size() > getMaxSize()) { - throw new IllegalArgumentException(String.format("The given set size %d is larger then maxSize %d", - difference.size(), maxSize)); - } - int itemsToDelete = delegate.size() + difference.size() - getMaxSize(); + int itemsToDelete = delegate.size() + c.size() - getMaxSize(); Iterator iterator = delegate.iterator(); for (int i = 0; i < itemsToDelete; i++) { iterator.next(); @@ -171,4 +163,11 @@ public int hashCode() { public String toString() { return delegate.toString(); } + + private void requireCollectionIsNotAboveMaxSize(Collection c, int maxSize) { + if (c.size() > maxSize) { + throw new IllegalArgumentException(String.format("The given collection size %d is larger then maxSize %d", c.size(), + maxSize)); + } + } } From 19e26277191d2840ebffe8fcc2d3dfe932fdf8c5 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 17:21:59 +0300 Subject: [PATCH 16/26] BoundedSetWrapperTest --- .../impl/BoundedSetWrapperTest.java | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java index 6c11e23916..f3798631df 100644 --- a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java +++ b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java @@ -1,7 +1,46 @@ package com.iota.iri.utils.collections.impl; -import static org.junit.Assert.*; +import com.iota.iri.utils.collections.interfaces.BoundedSet; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.internal.util.collections.Sets; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Set; public class BoundedSetWrapperTest { + @Test(expected = IllegalArgumentException.class) + public void createSetWithException() { + Set set = Sets.newSet(1, 2, 3, 4, 5, 6); + new BoundedSetWrapper<>(set, 4); + } + + @Test + public void createSetAndAssertEquals() { + Set set = Sets.newSet(1, 2, 3, 4, 5, 6); + BoundedSet boundedSetWrapper = new BoundedSetWrapper<>(set, 4); + Assert.assertEquals("sets should be equal", set, boundedSetWrapper); + + } + + @Test + public void testAdd() { + BoundedSet boundedSet = new BoundedSetWrapper<>(new LinkedHashSet<>(), 3); + Assert.assertTrue("can't add", boundedSet.add(1)); + Assert.assertTrue("can't add", boundedSet.add(2)); + Assert.assertTrue("can't add", boundedSet.add(3)); + Assert.assertTrue("can't add", boundedSet.add(4)); + Assert.assertEquals("bounded set doesn't have expected contents", + Sets.newSet(2, 3, 4), boundedSet); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddAll() { + BoundedSet boundedSet = new BoundedSetWrapper<>(new LinkedHashSet<>(), 3); + boundedSet.addAll(Arrays.asList(5, 6, 7, 8, 9)); + } + } \ No newline at end of file From 3bd507bfaaff0fc6037c61c031d4fd2691bda232 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 17:22:50 +0300 Subject: [PATCH 17/26] remove import --- .../iota/iri/utils/collections/impl/BoundedSetWrapperTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java index f3798631df..88140f5c56 100644 --- a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java +++ b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java @@ -6,7 +6,6 @@ import org.mockito.internal.util.collections.Sets; import java.util.Arrays; -import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Set; From 5f734ad31f52bd13d070b3f4a0354653fe585de7 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 17:25:25 +0300 Subject: [PATCH 18/26] clear cache after tests --- .../iota/iri/service/tipselection/impl/WalkValidatorImpl.java | 4 ++-- .../iri/service/tipselection/impl/WalkValidatorImplTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index dc648fc006..cd1908f937 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -1,10 +1,10 @@ package com.iota.iri.service.tipselection.impl; import com.iota.iri.LedgerValidator; +import com.iota.iri.Milestone; import com.iota.iri.TransactionValidator; import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.model.Hash; -import com.iota.iri.Milestone; import com.iota.iri.service.tipselection.WalkValidator; import com.iota.iri.storage.Tangle; import com.iota.iri.utils.collections.impl.BoundedSetWrapper; @@ -30,7 +30,7 @@ public class WalkValidatorImpl implements WalkValidator { public static final int INITIAL_CACHE_CAPACITY = 10_000; //As long as tip selection is synchronized we are fine with the collection not being thread safe - private static BoundedSet failedBelowMaxDepthCache; + static BoundedSet failedBelowMaxDepthCache; private int maxAnalyzedTxs; private final Tangle tangle; diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java index 3a56c1f78a..e368396739 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java @@ -8,7 +8,6 @@ import com.iota.iri.controllers.TransactionViewModel; import com.iota.iri.controllers.TransactionViewModelTest; import com.iota.iri.model.Hash; -import com.iota.iri.model.Transaction; import com.iota.iri.storage.Tangle; import com.iota.iri.storage.rocksDB.RocksDBPersistenceProvider; import org.junit.AfterClass; @@ -41,6 +40,7 @@ public class WalkValidatorImplTest { public static void tearDown() throws Exception { tangle.shutdown(); dbFolder.delete(); + WalkValidatorImpl.failedBelowMaxDepthCache.clear(); } @BeforeClass From 2c956057923e8fb969cdae6e7062e8ba48bf0e3a Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 17:49:37 +0300 Subject: [PATCH 19/26] fix test --- .../iota/iri/utils/collections/impl/BoundedSetWrapperTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java index 88140f5c56..406bc3fa7c 100644 --- a/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java +++ b/src/test/java/com/iota/iri/utils/collections/impl/BoundedSetWrapperTest.java @@ -20,7 +20,7 @@ public void createSetWithException() { @Test public void createSetAndAssertEquals() { Set set = Sets.newSet(1, 2, 3, 4, 5, 6); - BoundedSet boundedSetWrapper = new BoundedSetWrapper<>(set, 4); + BoundedSet boundedSetWrapper = new BoundedSetWrapper<>(set, 6); Assert.assertEquals("sets should be equal", set, boundedSetWrapper); } From 043c69e1c0f53dfbc8ec997e673aec14e44bc4ea Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 20:17:39 +0300 Subject: [PATCH 20/26] add cli walk validator cache size config option --- src/main/java/com/iota/iri/IRI.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iota/iri/IRI.java b/src/main/java/com/iota/iri/IRI.java index 05911a40e1..31d9bef55a 100644 --- a/src/main/java/com/iota/iri/IRI.java +++ b/src/main/java/com/iota/iri/IRI.java @@ -154,8 +154,8 @@ private static boolean isValidated(final Configuration configuration, final Stri final Option milestoneStartIndex = parser.addIntegerOption("milestone-start"); final Option milestoneKeys = parser.addIntegerOption("milestone-keys"); final Option snapshotTime = parser.addLongOption("snapshot-timestamp"); - final Option belowMaxDepthTxLimit = parser.addIntegerOption("below-max-depth"); - + final Option belowMaxDepthTxLimit = parser.addIntegerOption("max-depth-tx-limit"); + final Option walkValidatorCacheSize = parser.addIntegerOption("walk-validator-cache"); try { parser.parse(args); @@ -338,6 +338,11 @@ private static boolean isValidated(final Configuration configuration, final Stri String.valueOf(belowMaxDepthLimit)); } + final Integer walkValidatorCache = parser.getOptionValue(walkValidatorCacheSize); + if (walkValidatorCache != null) { + configuration.put(DefaultConfSettings.WALK_VALIDATOR_CACHE_SIZE, String.valueOf(walkValidatorCache)); + } + return true; } From 03d868e30ed163f7ed0ea9eb4f1934bf98480ab6 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Tue, 24 Jul 2018 20:20:56 +0300 Subject: [PATCH 21/26] remove unused import --- .../com/iota/iri/utils/collections/impl/BoundedSetWrapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java index b3e515cc6f..8e2e55babc 100644 --- a/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java +++ b/src/main/java/com/iota/iri/utils/collections/impl/BoundedSetWrapper.java @@ -1,7 +1,6 @@ package com.iota.iri.utils.collections.impl; import com.iota.iri.utils.collections.interfaces.BoundedSet; -import org.apache.commons.collections4.SetUtils; import java.util.*; import java.util.function.Consumer; From bed15673709a033bd32029d6e567b032ec7d5bd8 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 25 Jul 2018 13:11:08 +0300 Subject: [PATCH 22/26] API calls won't trigger solidity routines --- src/main/java/com/iota/iri/service/API.java | 3 ++- .../service/tipselection/impl/WalkValidatorImpl.java | 2 +- .../tipselection/impl/WalkValidatorImplTest.java | 12 ++++-------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/iota/iri/service/API.java b/src/main/java/com/iota/iri/service/API.java index d03257e9eb..b9721cd6df 100644 --- a/src/main/java/com/iota/iri/service/API.java +++ b/src/main/java/com/iota/iri/service/API.java @@ -444,7 +444,7 @@ private AbstractResponse checkConsistencyStatement(List transactionsList } - if (!instance.transactionValidator.checkSolidity(txVM.getHash(), false)) { + if (!txVM.isSolid()) { state = false; info = "tails are not solid (missing a referenced tx): " + transaction; break; @@ -737,6 +737,7 @@ private boolean exhaustiveSearchWithinIndex(Queue nonAnalyzedTransactions, } private synchronized AbstractResponse findTransactionStatement(final Map request) throws Exception { + final Set foundTransactions = new HashSet<>(); boolean containsKey = false; diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index cd1908f937..1b0f2bdffa 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -78,7 +78,7 @@ public boolean isValid(Hash transactionHash) throws Exception { } else if (transactionViewModel.getCurrentIndex() != 0) { log.debug("Validation failed: {} not a tail", transactionHash); return false; - } else if (!transactionValidator.checkSolidity(transactionViewModel.getHash(), false)) { + } else if (!transactionViewModel.isSolid()) { log.debug("Validation failed: {} is not solid", transactionHash); return false; } else if (belowMaxDepth(transactionViewModel.getHash(), milestone.latestSolidSubtangleMilestoneIndex - maxDepth)) { diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java index e368396739..3149d67d5f 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java @@ -57,10 +57,9 @@ public static void setUp() throws Exception { public void shouldPassValidation() throws Exception { int depth = 15; TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); + tx.updateSolid(true); tx.store(tangle); Hash hash = tx.getHash(); - Mockito.when(transactionValidator.checkSolidity(hash, false)) - .thenReturn(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; @@ -111,8 +110,7 @@ public void failOnSolid() throws Exception { TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); Hash hash = tx.getHash(); - Mockito.when(transactionValidator.checkSolidity(hash, false)) - .thenReturn(false); + tx.updateSolid(false); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; @@ -152,11 +150,10 @@ public void belowMaxDepthWithFreshMilestone() throws Exception { tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); TransactionTestUtils.setLastIndex(tx,0); TransactionTestUtils.setCurrentIndex(tx,0); + tx.updateSolid(true); hash = tx.getHash(); tx.store(tangle); } - Mockito.when(transactionValidator.checkSolidity(hash, false)) - .thenReturn(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 100; @@ -203,11 +200,10 @@ public void belowMaxDepthOnGenesis() throws Exception { tx = new TransactionViewModel(TransactionViewModelTest.getRandomTransactionWithTrunkAndBranch(hash, hash), TransactionViewModelTest.getRandomTransactionHash()); TransactionTestUtils.setLastIndex(tx,0); TransactionTestUtils.setCurrentIndex(tx,0); + tx.updateSolid(true); hash = tx.getHash(); tx.store(tangle); } - Mockito.when(transactionValidator.checkSolidity(tx.getHash(), false)) - .thenReturn(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), tx.getHash())) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = 15; From cc84f3774d5d56cb13be5b706713d232561d2505 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 25 Jul 2018 18:36:30 +0300 Subject: [PATCH 23/26] remove unneccessary mock --- .../service/tipselection/impl/WalkValidatorImplTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java index 3149d67d5f..ebfe15fa99 100644 --- a/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java +++ b/src/test/java/com/iota/iri/service/tipselection/impl/WalkValidatorImplTest.java @@ -76,8 +76,7 @@ public void failOnTxType() throws Exception { TransactionViewModel tx = TransactionTestUtils.createBundleHead(0); tx.store(tangle); Hash hash = tx.getTrunkTransactionHash(); - Mockito.when(transactionValidator.checkSolidity(hash, false)) - .thenReturn(true); + tx.updateSolid(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = depth; @@ -128,8 +127,7 @@ public void failOnBelowMaxDepthDueToOldMilestone() throws Exception { tx.store(tangle); tx.setSnapshot(tangle, 2); Hash hash = tx.getHash(); - Mockito.when(transactionValidator.checkSolidity(hash, false)) - .thenReturn(true); + tx.updateSolid(true); Mockito.when(ledgerValidator.updateDiff(new HashSet<>(), new HashMap<>(), hash)) .thenReturn(true); milestoneTracker.latestSolidSubtangleMilestoneIndex = Integer.MAX_VALUE; From 1829df5dde8dadbc78f482d4b7db43ca0a934015 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 25 Jul 2018 19:37:00 +0300 Subject: [PATCH 24/26] use concurrent skip list set --- .../iota/iri/service/tipselection/impl/WalkValidatorImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java index 1b0f2bdffa..3d48967615 100644 --- a/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java +++ b/src/main/java/com/iota/iri/service/tipselection/impl/WalkValidatorImpl.java @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory; import java.util.*; +import java.util.concurrent.ConcurrentSkipListSet; /** * Implementation of WalkValidator that checks consistency of the ledger as part of validity checks. @@ -63,7 +64,7 @@ public WalkValidatorImpl(Tangle tangle, LedgerValidator ledgerValidator, Transac private BoundedSet fetchCache(int cacheSize) { if (failedBelowMaxDepthCache == null) { failedBelowMaxDepthCache = new BoundedSetWrapper<>( - new LinkedHashSet<>(INITIAL_CACHE_CAPACITY), cacheSize); + new ConcurrentSkipListSet<>(), cacheSize); } return failedBelowMaxDepthCache; } From ef97ae5e2513537b50b9a95b7441e96301ffc49c Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 25 Jul 2018 21:06:30 +0300 Subject: [PATCH 25/26] version bump v1.5.2 --- DOCKER.md | 6 +++--- changelog.txt | 4 ++++ pom.xml | 2 +- src/main/java/com/iota/iri/IRI.java | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 41112a6c3f..f2281e4839 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -2,13 +2,13 @@ Run the official iotaledger/iri container, passing the mandatory -p option: -```docker run iotaledger/iri:v1.5.1 -p 14265``` +```docker run iotaledger/iri:v1.5.2 -p 14265``` This will get your a running IRI with its API listening on port 14265, no neighbours and an empty database. The IRI Docker container by default expects data at /iri/data. Use the `-v` option of the `docker run` command to mount volumes so to have persistent data. You can also pass more command line options to the docker run command and those will be passed to IRI. If you want to use a iri.ini file with the docker container, supposing it's stored under /path/to/conf/iri.ini on your docker host, then pass `-v /path/to/conf:/iri/conf` and add -c /iri/conf/iri.ini as docker run arguments. So for example the `docker run` command above would become: -```docker run -v /path/to/conf:/iri/conf -v /path/to/data:/iri/data iotaledger/iri:v1.5.1 -p 14265 -c /iri/conf/iri.ini``` +```docker run -v /path/to/conf:/iri/conf -v /path/to/data:/iri/data iotaledger/iri:v1.5.2 -p 14265 -c /iri/conf/iri.ini``` Please refer to the IRI documentation for further command line options and iri.ini options. @@ -61,7 +61,7 @@ ExecStart=/usr/bin/docker run \ -p 14265:14265 \ -p 15600:15600 \ -p 14600:14600/udp \ -iotaledger/iri:v1.5.1 \ +iotaledger/iri:v1.5.2 \ -p 14265 \ --zmq-enabled \ --testnet diff --git a/changelog.txt b/changelog.txt index 80a744dbb7..d4cfe6de3d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +1.5.2 + - Fail early on below max depth and don't solidify on api calls (#883) + - Replace all trit representations from int[] to byte[] (#879) + 1.5.1 - Update snapshot to 2018-07-09 8:00 UTC (#855) diff --git a/pom.xml b/pom.xml index 3277ce8cb6..4267bba97b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.iota iri - 1.5.1 + 1.5.2 IRI IOTA Reference Implementation diff --git a/src/main/java/com/iota/iri/IRI.java b/src/main/java/com/iota/iri/IRI.java index 31d9bef55a..95cf1c3e3a 100644 --- a/src/main/java/com/iota/iri/IRI.java +++ b/src/main/java/com/iota/iri/IRI.java @@ -22,7 +22,7 @@ public class IRI { public static final String MAINNET_NAME = "IRI"; public static final String TESTNET_NAME = "IRI Testnet"; - public static final String VERSION = "1.5.1"; + public static final String VERSION = "1.5.2"; public static void main(String[] args) throws Exception { // Logging is configured first before any references to Logger or LoggerFactory. From 0797ce8ca4b786f4b98dae24a92ad3f7a8ad2883 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Wed, 25 Jul 2018 21:33:53 +0300 Subject: [PATCH 26/26] add configurations info in changelog --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index d4cfe6de3d..23d61aad79 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,6 @@ 1.5.2 - Fail early on below max depth and don't solidify on api calls (#883) + - Two new configurations added: "max-depth-tx-limit" and "--walk-validator-cache" - Replace all trit representations from int[] to byte[] (#879) 1.5.1