diff --git a/assignment1/test/IsValidTest.java b/assignment1/test/IsValidTest.java
new file mode 100644
index 0000000..de6a461
--- /dev/null
+++ b/assignment1/test/IsValidTest.java
@@ -0,0 +1,191 @@
+// Copyright (C) 2016-2017 Enrique Albertos
+// Distributed under the GNU GPL v2 software license
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+
+import org.junit.Test;
+/**
+ * Unit tests for {@link TxHandler#isValidTx(Transaction)}
+ *
+ * Test Strategy:
+ * Test 1: test isValidTx() with valid transactions
+ * Test 2: test isValidTx() with transactions containing signatures of incorrect data
+ * Test 3: test isValidTx() with transactions containing signatures using incorrect private keys
+ * Test 4: test isValidTx() with transactions whose total output value exceeds total input value
+ * Test 5: test isValidTx() with transactions that claim outputs not in the current utxoPool
+ * Test 6: test isValidTx() with transactions that claim the same UTXO multiple times
+ * Test 7: test isValidTx() with transactions that contain a negative output value
+ *
+ * @author ealbertos
+ *
+ */
+
+public class IsValidTest {
+
+ private static void assertTestSetIsValid(final UtxoTestSet utxoTestSet) {
+ final ValidationLists trxsValidation = utxoTestSet.getValidationLists();
+
+ // Instantiate student solution
+ final TxHandler txHandler = new TxHandler(utxoTestSet.getUtxoPool());
+
+ // Check validation of all the transactions in the set
+ for (Transaction tx: trxsValidation.allElements()) {
+ assertEquals(txHandler.isValidTx(tx), trxsValidation.isValid(tx) );
+ }
+ }
+
+ // Test 1: test isValidTx() with valid transactions
+ @Test
+ public void testIsValidWithValidTransactions()
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setCorruptedPercentage(0) // All valid transactions
+ .build();
+ // check against student solution
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+
+ // Test 2: test isValidTx() with transactions containing signatures of incorrect data
+ @Test
+ public void testIsValidWithInvalidSignatures() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setForceCorruptedSignature(true)
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ // check against student solution
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+ // Test 3: test isValidTx() with transactions containing signatures using incorrect private keys
+ @Test
+ public void testIsValidSignaturesWithInvalidPrivateKeys() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setInvalidPrivateKeys(true) // corrupt the private key that signs
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ // check against student solution
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+ // Test 4: test isValidTx() with transactions whose total output value exceeds total input value
+ @Test
+ public void testIsValidTotalOutputExceedsTotalInput() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setInvalidTotals(true) // create transactions with invalid total value
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ // check against student solution
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+
+ // Test 5: test isValidTx() with transactions that claim outputs not in the current utxoPool
+ @Test
+ public void testIsValidTransactionsClamingOuputsNotInThePool() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setClaimingOutputsNotInPool(true) // create transactions claiming outputs not in the pool
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ // check against student solution
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+ // Test 6: test isValidTx() with transactions that claim the same UTXO multiple times
+ @Test
+ public void testIsValidTransactionsClaimingTheSameUTXOSeveralTimes() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setClaimingUtxoSeveralTimes(true) // create transactions claiming the same output several times
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+ // Test 7: test isValidTx() with transactions that contain a negative output value
+ @Test
+ public void testIsValidTransactionsWithNegativeOutput() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ // Create a new set of transactions for testing
+ final UtxoTestSet utxoTestSet = UtxoTestSet.builder()
+ .setPeopleSize(10)
+ .setUtxoTxNumber(10)
+ .setMaxUtxoTxOutput(10)
+ .setMaxValue(200)
+ .setTxPerTest(10)
+ .setMaxInput(10)
+ .setMaxOutput(10)
+ .setNegativeOutputs(true) // create transactions with negative values
+ .setCorruptedPercentage(.20) // probability of 20% of invalid transactions
+ .build();
+
+ assertTestSetIsValid(utxoTestSet);
+
+ }
+
+
+
+
+}
diff --git a/assignment1/test/UtxoTestSet.java b/assignment1/test/UtxoTestSet.java
new file mode 100644
index 0000000..b5319aa
--- /dev/null
+++ b/assignment1/test/UtxoTestSet.java
@@ -0,0 +1,511 @@
+// Copyright (C) 2016-2017 Enrique Albertos
+// Distributed under the GNU GPL v2 software license
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * UtxoTestSet represent a random created data test set for testing isValid and txHandler methods.
+ * Creates an UtxPool ans several transactions, valid, invalid or conflicted
+ * Several flags force different types of transactions
+ *
+ * A UtxoTestSet can be
+ * constructed wit by means of a builder:
+ *
+ *
+ * UtxoTestSet.builder()
+ * .setPeopleSize(10)
+ * .setUtxoTxNumber(10)
+ * .setMaxUtxoTxOutput(10)
+ * .setMaxValue(200)
+ * .setTxPerTest(10)
+ * .setMaxInput(10)
+ * .setMaxOutput(10)
+ * .setCorruptedPercentage(0)
+ * .build();
+ *
+ *
+ * @author ealbertos
+ *
+ */
+public class UtxoTestSet {
+
+ /**
+ * Factory method that constructs a new builder of UtxoTestSet
+ * @return a new builder
+ */
+ public static UtxoTestSetBuilder builder(){
+ return new UtxoTestSetBuilder();
+ }
+
+ /**
+ * Validation list contains list with valid transactions, invalid transactions and conflicted transactions
+ * @return the validationLists
+ */
+ public ValidationLists getValidationLists() {
+ return new ValidationLists<>(validationLists);
+ }
+
+ /**
+ * Return the created Utxo Pool
+ * @return a copy of the pool
+ */
+ public UTXOPool getUtxoPool() {
+ return new UTXOPool(utxoPool);
+ }
+
+
+ /**
+ * Builder for UtxoTestSet
+ * @author ealbertos
+ *
+ */
+ static class UtxoTestSetBuilder {
+ private int peopleSize;
+ private int utxoTxNumber;
+ private int maxUtxoTxOutput;
+ private double maxValue;
+ private int txNumberPerTest;
+ private int maxInputs;
+ private int maxOutputs;
+ private double corruptedPercentage = 0D;
+ private boolean isForceInvalidPrivateKeys = false;
+ private boolean isForceInvalidTotals = false;
+ private boolean isClaimingOutputsNotInPool = false;
+ private boolean isForceCorruptedSignature = false;
+ private boolean isClaimingUtxoSeveralTimes = false;
+ private boolean isForceNegativeOutputs = false;
+
+ /**
+ * Number of different people address in the test set
+ * @param peopleNumber the number of different people address in the test set
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setPeopleSize(final int peopleNumber) {
+ this.peopleSize = peopleNumber;
+ return this;
+ }
+
+ /**
+ * Number of utxo in the pool to create for the set, the same number is created for the extraPool set
+ * Extra Pool set is used to create transactions tha use UTXO no in the actual pool
+ * @param utxoTxNumber number of utxo in the pool to create for the set
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setUtxoTxNumber(final int utxoTxNumber) {
+ this.utxoTxNumber = utxoTxNumber;
+ return this;
+ }
+
+ /**
+ * Max Number of utxo per output in trx created
+ * @param maxUtxoTxOutput
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setMaxUtxoTxOutput(final int maxUtxoTxOutput) {
+ this.maxUtxoTxOutput = maxUtxoTxOutput;
+ return this;
+ }
+
+ /**
+ * Max coin value per transaction, can be exceed in invalid transactions
+ * @param maxValue
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setMaxValue(final double maxValue) {
+ this.maxValue = maxValue;
+ return this;
+ }
+
+ /**
+ * number of tx per test
+ * @param txNumberPerTest number of tx per test
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setTxPerTest(final int txNumberPerTest) {
+ this.txNumberPerTest = txNumberPerTest;
+ return this;
+ }
+
+ /**
+ * Max number of inputs
+ * @param maxInputs max number of inputs in transactions created
+ * @return
+ */
+ public UtxoTestSetBuilder setMaxInput(int maxInputs) {
+ this.maxInputs = maxInputs;
+ return this;
+ }
+
+ /**
+ * set the max number of outputs in transactions created
+ * @param maxOutputs max number of outputs in transactions created
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setMaxOutput(int maxOutputs) {
+ this.maxOutputs = maxOutputs;
+ return this;
+ }
+
+ /**
+ * Set the percentage of corrupted transactions
+ * @param corruptedPercentage 0 to 1
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setCorruptedPercentage(double corruptedPercentage) {
+ if(corruptedPercentage > 1 || corruptedPercentage < 0) {
+ throw new IllegalArgumentException("Percentage value must be in the range (0-1)");
+ }
+ this.corruptedPercentage = corruptedPercentage;
+ return this;
+ }
+
+ /**
+ * Create transactions containing signatures using incorrect private keys
+ * @param value
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setInvalidPrivateKeys(boolean value) {
+ isForceInvalidPrivateKeys = value;
+ return this;
+ }
+
+ /**
+ * Create transactions whose total output value exceeds total input value
+ * @param value True force creation
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setInvalidTotals(boolean value) {
+ isForceInvalidTotals = value;
+ return this;
+ }
+
+ /**
+ * Create transactions that claim outputs not in the current utxoPool
+ * @param value True force creation
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setClaimingOutputsNotInPool(boolean value) {
+ isClaimingOutputsNotInPool = value;
+ return this;
+ }
+
+ /**
+ * Create transactions containing signatures of incorrect data
+ * @param value True force creation
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setForceCorruptedSignature(boolean value) {
+ isForceCorruptedSignature = value;
+ return this;
+ }
+
+ /**
+ * Create transactions that claim the same UTXO multiple times
+ * @param value True force creation
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setClaimingUtxoSeveralTimes(boolean value) {
+ isClaimingUtxoSeveralTimes = value;
+ return this;
+ }
+
+ /**
+ * Create transactions that contain a negative output value
+ * @param value True force creation
+ * @return this builder
+ */
+ public UtxoTestSetBuilder setNegativeOutputs(boolean value) {
+ isForceNegativeOutputs = value;
+ return this;
+ }
+
+ public UtxoTestSet build() throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ return new UtxoTestSet(peopleSize,
+ utxoTxNumber,
+ maxUtxoTxOutput,
+ maxValue,
+ txNumberPerTest,
+ maxInputs,
+ maxOutputs,
+ corruptedPercentage,
+ isForceInvalidPrivateKeys,
+ isForceInvalidTotals,
+ isClaimingOutputsNotInPool,
+ isForceCorruptedSignature,
+ isClaimingUtxoSeveralTimes,
+ isForceNegativeOutputs);
+ }
+
+
+ }
+
+ private final UTXOPool utxoPool;
+ private final List people;
+ private final Map utxoToKeyPair;
+
+ private final UTXOPool utxoExtraPool;
+ private final List peopleExtra;
+
+ private final int maxInputs;
+ private final int maxOutputs;
+ private final int txNumberPerTest;
+ private final double corruptedPercentage;
+ private final boolean isForceInvalidPrivateKeys;
+ private final boolean isForceInvalidTotals;
+ private final boolean isClaimingOutputsNotInPool;
+ private final boolean isForceCorruptedSignature;
+ private final boolean isClaimingUtxoSeveralTimes;
+ private final double maxValue;
+ private final ValidationLists validationLists;
+ private final ThreadLocalRandom random;
+ private final boolean isForceNegativeOutputs;
+
+
+ /**
+ * Private construct, force the creation of set with the builder
+ * @param peopleSize
+ * @param utxoTxNumber
+ * @param maxUtxoTxOutput
+ * @param maxValue
+ * @param txNumberPerTest
+ * @param maxInputs
+ * @param maxOutputs
+ * @param corruptedPercentage
+ * @param isForceInvalidPrivateKeys
+ * @param isForceInvalidTotals
+ * @param isClaimingOutputsNotInPool
+ * @param isForceCorruptedSignature
+ * @param isClaimingUtxoSeveralTimes
+ * @param isForceNegativeOutputs
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ * @throws SignatureException
+ */
+ private UtxoTestSet(int peopleSize, int utxoTxNumber, int maxUtxoTxOutput, double maxValue, int txNumberPerTest,
+ int maxInputs, int maxOutputs, double corruptedPercentage, boolean isForceInvalidPrivateKeys,
+ boolean isForceInvalidTotals, boolean isClaimingOutputsNotInPool, boolean isForceCorruptedSignature,
+ boolean isClaimingUtxoSeveralTimes, boolean isForceNegativeOutputs)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ this.txNumberPerTest = txNumberPerTest;
+ this.maxInputs = maxInputs;
+ this.maxOutputs = maxOutputs;
+ this.corruptedPercentage = corruptedPercentage;
+ this.isForceInvalidPrivateKeys = isForceInvalidPrivateKeys;
+ this.isForceInvalidTotals = isForceInvalidTotals;
+ this.isClaimingOutputsNotInPool = isClaimingOutputsNotInPool;
+ this.isForceCorruptedSignature = isForceCorruptedSignature;
+ this.isClaimingUtxoSeveralTimes = isClaimingUtxoSeveralTimes;
+ this.isForceNegativeOutputs = isForceNegativeOutputs;
+ this.maxValue = maxValue;
+ this.random = ThreadLocalRandom.current();
+
+ people = createPeopleAddresses(peopleSize);
+ utxoToKeyPair = new HashMap<>();
+ utxoPool = createUtxoPool(people, utxoTxNumber, maxUtxoTxOutput, maxValue, utxoToKeyPair);
+
+ peopleExtra = createPeopleAddresses(peopleSize);
+ utxoExtraPool = createUtxoPool(peopleExtra, utxoTxNumber, maxUtxoTxOutput, maxValue, utxoToKeyPair);
+
+ validationLists = generateTrxWithCorruptedSignaturePercentage();
+
+ }
+
+ private UTXOPool createUtxoPool(List people, int utxoTxNumber, int maxUtxoTxOutput, double maxValue,
+ Map utxoToKeyPair) {
+ final UTXOPool utxoPool = new UTXOPool();
+ Map keyPairAtIndex = new HashMap<>();
+
+ for (int i = 0; i < utxoTxNumber; i++) {
+ int num = maxUtxoTxOutput;
+ Transaction tx = createTxWithOutputs(people, maxValue, keyPairAtIndex, num);
+ // add all tx outputs to utxo pool
+ addTxOutputsToPool(utxoPool, keyPairAtIndex, utxoToKeyPair, num, tx);
+ }
+ return utxoPool;
+ }
+
+ private Transaction createTxWithOutputs(List people, double maxValue, Map keyPairAtIndex, int num) {
+ final Transaction tx = new Transaction();
+ for (int j = 0; j < num; j++) {
+ // pick a random public address
+ int rIndex = random.nextInt(people.size());
+ PublicKey addr = people.get(rIndex).getPublic();
+ double value = random.nextDouble(maxValue);
+ tx.addOutput(value, addr);
+ keyPairAtIndex.put(j, people.get(rIndex));
+ }
+ tx.finalize();
+ return tx;
+ }
+
+ private void addTxOutputsToPool(UTXOPool utxoPool, Map keyPairAtIndex,
+ Map utxoToKeyPair,
+ int numTx, Transaction tx) {
+ for (int j = 0; j < numTx; j++) {
+ UTXO ut = new UTXO(tx.getHash(), j);
+ utxoPool.addUTXO(ut, tx.getOutput(j));
+ utxoToKeyPair.put(ut, keyPairAtIndex.get(j));
+ }
+ }
+
+ private List createPeopleAddresses(int peopleSize) throws NoSuchAlgorithmException {
+ final List people = new ArrayList<>();
+ for (int i = 0; i < peopleSize; i++)
+ people.add(KeyPairGenerator.getInstance("RSA").generateKeyPair());
+ return Collections.unmodifiableList(people);
+ }
+
+ private PublicKey getAddress(int rIndex) {
+ return people.get(rIndex).getPublic();
+ }
+
+ private PrivateKey getPrivate(UTXO utxo) {
+ return utxoToKeyPair.get(utxo).getPrivate();
+ }
+
+ private KeyPair getKeyPair(UTXO utxo) {
+ return utxoToKeyPair.get(utxo);
+ }
+
+ private ArrayList getAllUTXO(UTXOPool pool) {
+ return pool.getAllUTXO();
+ }
+
+
+ private byte[] sign(PrivateKey privateKey, byte[] rawDataToSign) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ Signature sig = Signature.getInstance("SHA256withRSA");
+ sig.initSign(privateKey);
+ sig.update(rawDataToSign);
+ return sig.sign();
+ }
+
+
+
+ private ValidationLists generateTrxWithCorruptedSignaturePercentage()
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
+ final ArrayList utxoList = getAllUTXO(utxoPool);
+ final ArrayList utxoExtraList = getAllUTXO(utxoExtraPool);
+ //final UTXOPool utxoPool = new UTXOPool();
+ final Map utxoAtIndex = new HashMap<>();
+ final Set utxosSeen = new HashSet<>();
+ final Set utxosToRepeat = new HashSet<>();
+
+ // create validationLists
+ final List valid = new ArrayList<>();
+ final List invalid = new ArrayList<>();
+ final List conflicted = new ArrayList<>();
+ for (int i = 0; i < txNumberPerTest; i++) {
+ boolean corrupted = false;
+ Transaction tx = new Transaction();
+
+ final int nInputs = random.nextInt(maxInputs) + 1;
+ final int nOutputs = random.nextInt(maxOutputs) + 1;
+
+ // create inputs
+ double inputValue = 0;
+ for (int j = 0; j < nInputs; j++) {
+ UTXO utxo = null;
+ if (isClaimingOutputsNotInPool && isRandomSelection()) {
+ do {
+ utxo = utxoExtraList.get(random.nextInt(utxoExtraList.size()));
+ } while (!utxosSeen.add(utxo));
+ inputValue += utxoExtraPool.getTxOutput(utxo).value;
+ corrupted = true;
+ } else {
+ do {
+ utxo = utxoList.get(random.nextInt(utxoList.size()));
+ } while (!utxosSeen.add(utxo));
+ inputValue += utxoPool.getTxOutput(utxo).value;
+ if (isClaimingUtxoSeveralTimes && isRandomSelection()) {
+ utxosToRepeat.add(utxo);
+ corrupted = true;
+ }
+ }
+ tx.addInput(utxo.getTxHash(), utxo.getIndex());
+ utxoAtIndex.put(j, utxo);
+ }
+
+ int count = 0;
+ for (UTXO utxo : utxosToRepeat) {
+ tx.addInput(utxo.getTxHash(), utxo.getIndex());
+ inputValue += utxoPool.getTxOutput(utxo).value;
+ utxoAtIndex.put(nInputs + count, utxo);
+ count++;
+ }
+
+ // create outpus
+ double outputValue = 0;
+ for (int j = 0; j < nOutputs; j++) {
+ double value;
+ if ((isForceInvalidTotals && isRandomSelection())
+ || outputValue > inputValue) {
+ value = random.nextDouble(maxValue);
+ } else {
+ value = random.nextDouble(inputValue - outputValue);
+ if (isForceNegativeOutputs && isRandomSelection()) {
+ value = -value;
+ corrupted = true;
+ }
+ }
+
+ tx.addOutput(value, getAddress(random.nextInt(people.size())));
+ outputValue += value;
+ }
+ corrupted |= (outputValue > inputValue);
+
+ // sign transaction
+ for (int j = 0; j < nInputs + utxosToRepeat.size(); j++) {
+ byte[] rawData = tx.getRawDataToSign(j);
+ PrivateKey privateKey = getPrivate(utxoAtIndex.get(j));
+ if (isRandomSelection()) {
+ if (isForceInvalidPrivateKeys && isRandomSelection()) {
+ // corrupt private key, change for other people
+ int index = people.indexOf(getKeyPair(utxoAtIndex.get(j)));
+ privateKey = people.get((index + 1) % people.size()).getPrivate();
+ corrupted = true;
+ } else if (isForceCorruptedSignature && isRandomSelection()) {
+ // corrupt data
+ rawData[0]++;
+ corrupted = true;
+ }
+
+ }
+ tx.addSignature(sign(privateKey, rawData), j);
+ }
+ tx.finalize();
+
+ if (corrupted){
+ invalid.add(tx);
+ } else{
+ valid.add(tx);
+ }
+
+ }
+
+ return ValidationLists.builder(Transaction.class)
+ .setValid(valid)
+ .setInvalid(invalid)
+ .setConflicted(conflicted)
+ .build();
+
+ }
+
+ private boolean isRandomSelection() {
+ return Math.abs(random.nextGaussian()) < corruptedPercentage;
+ }
+}
diff --git a/assignment1/test/ValidationLists.java b/assignment1/test/ValidationLists.java
new file mode 100644
index 0000000..709fb6d
--- /dev/null
+++ b/assignment1/test/ValidationLists.java
@@ -0,0 +1,73 @@
+// Copyright (C) 2016-2017 Enrique Albertos
+// Distributed under the GNU GPL v2 software license
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Validation Lists is a container for several lists of elements calssified in:
+ * Valid, Invalid or Conflicted
+ * @author ealbertos
+ *
+ * @param Type of the elements
+ */
+public class ValidationLists {
+ private final List valid;
+ private final List invalid;
+ private final List conflicted;
+
+ private ValidationLists(final List valid, final List invalid, final List conflicted) {
+ super();
+ this.valid = Collections.unmodifiableList( new ArrayList<>(valid));
+ this.invalid = Collections.unmodifiableList(new ArrayList<>(invalid));
+ this.conflicted = Collections.unmodifiableList(new ArrayList<>(conflicted));
+ }
+
+ public ValidationLists(ValidationLists original) {
+ this(original.valid, original.invalid, original.conflicted);
+ }
+
+ public boolean isValid(final E e) {
+ return valid.contains(e) && !invalid.contains(e);
+ }
+
+ public List allElements() {
+ final ArrayList list = new ArrayList<>(valid);
+ list.addAll(invalid);
+ return list;
+ }
+
+ public static Builder builder(Class c){
+ return new Builder();
+ }
+
+
+ public static final class Builder{
+ private List valid;
+ private List invalid;
+ private List conflicted;
+
+ Builder setValid(List valid){
+ this.valid = valid;
+ return this;
+ }
+
+ Builder setInvalid(List invalid){
+ this.invalid = invalid;
+ return this;
+ }
+
+ Builder setConflicted(List conflicted){
+ this.conflicted = conflicted;
+ return this;
+ }
+
+ ValidationLists build() {
+ return new ValidationLists<>(valid, invalid, conflicted);
+ }
+
+ }
+
+
+}