diff --git a/.gitignore b/.gitignore
index 1e5d2d9..2cd97a1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,61 +1,10 @@
-/.idea/.gitignore
-/build/reports/tests/test/css/base-style.css
-/build/classes/java/main/model/Block.class
-/out/production/blockchain_gitea/model/Block.class
-/build/classes/java/main/model/BlockChain.class
-/out/production/blockchain_gitea/model/BlockChain.class
-/blockChain.txt
-/build/classes/java/test/BlockChainTest.class
-/build/reports/tests/test/classes/BlockChainTest.html
-/.gradle/buildOutputCleanup/buildOutputCleanup.lock
-/.gradle/buildOutputCleanup/cache.properties
-/.gradle/checksums/checksums.lock
-/.idea/compiler.xml
-/build/reports/tests/test/packages/default-package.html
-/.gradle/7.1/dependencies-accessors/dependencies-accessors.lock
-/.gradle/7.1/executionHistory/executionHistory.lock
-/.gradle/7.1/fileHashes/fileHashes.lock
-/build/classes/java/main/util/FileManagement.class
-/out/production/blockchain_gitea/util/FileManagement.class
-/.gradle/7.1/dependencies-accessors/gc.properties
-/.gradle/7.1/gc.properties
-/.gradle/vcs-1/gc.properties
-/.idea/gradle.xml
-/gradle/wrapper/gradle-wrapper.jar
-/gradle/wrapper/gradle-wrapper.properties
+/.idea/*
+/.gradle/*
+/build/*
+/out/*
+/gradle/*
/gradlew
/gradlew.bat
-/build/classes/java/main/util/HashFunction.class
-/out/production/blockchain_gitea/util/HashFunction.class
-/build/reports/tests/test/index.html
-/.idea/sonarlint/issuestore/index.pb
-/.idea/jarRepositories.xml
-/.gradle/7.1/fileChanges/last-build.bin
-/build/classes/java/main/Main.class
-/out/production/blockchain_gitea/Main.class
-/build/classes/java/main/model/Miner.class
-/out/production/blockchain_gitea/model/Miner.class
-/.idea/misc.xml
-/build/classes/java/main/exceptions/NoSelfTransactionException.class
-/build/classes/java/main/exceptions/NotEnoughCoinsException.class
-/out/production/blockchain_gitea/exceptions/NotEnoughCoinsException.class
-/build/test-results/test/binary/output.bin
-/build/test-results/test/binary/output.bin.idx
-/build/tmp/compileJava/previous-compilation-data.bin
-/build/tmp/compileTestJava/previous-compilation-data.bin
+/blockchain.txt
/KeyPair/privateKey
-/.idea/inspectionProfiles/Project_Default.xml
-/KeyPair/publicKey
-/build/reports/tests/test/js/report.js
-/build/test-results/test/binary/results.bin
-/.idea/runConfigurations.xml
-/build/classes/java/main/util/Security.class
-/out/production/blockchain_gitea/util/Security.class
-/build/reports/tests/test/css/style.css
-/build/test-results/test/TEST-BlockChainTest.xml
-/build/classes/java/main/model/Transaction.class
-/out/production/blockchain_gitea/model/Transaction.class
-/build/classes/java/main/util/TransactionsGenerator.class
-/out/production/blockchain_gitea/util/TransactionsGenerator.class
-/.idea/uiDesigner.xml
-/.idea/vcs.xml
+/KeyPair/publicKey
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..376fcd8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,13 @@
+
Blockchain
+
+Blockchain implementation with following characteristics:
+
+- Ability to store transactions between users.
+- Mining reward for each block added to the blockchain.
+- Proof of work with magic number self-balancing hashing.
+- SHA-256 algorithm based hashing.
+
+Main method allows to test it by creating fake miners, and it is also included a transaction generator to mock a series of users interacting each other.
+Execution example:
+
+ 
\ No newline at end of file
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
index f4111ed..f1af7e8 100644
--- a/src/main/java/Main.java
+++ b/src/main/java/Main.java
@@ -3,7 +3,7 @@ import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
-import model.BlockChain;
+import model.Blockchain;
import util.TransactionsGenerator;
import model.Miner;
import util.FileManagement;
@@ -14,7 +14,7 @@ public final class Main {
public static void main(final String[] args) throws InterruptedException, IOException {
final var nThreads = Runtime.getRuntime().availableProcessors();
- final var blockChain = BlockChain.getInstance();
+ final var blockchain = Blockchain.getInstance();
// Cryptographic keys management
final File publicKey = new File(Security.PUBLIC_KEY);
@@ -27,13 +27,13 @@ public final class Main {
final var transactionsExecutor = Executors.newScheduledThreadPool(nThreads);
// Mocks a generator to send transactions into the blockchain
- transactionsExecutor.scheduleAtFixedRate(new TransactionsGenerator(blockChain), 0, 200, TimeUnit.MILLISECONDS);
+ transactionsExecutor.scheduleAtFixedRate(new TransactionsGenerator(blockchain), 0, 200, TimeUnit.MILLISECONDS);
final var minerExecutor = Executors.newFixedThreadPool(nThreads);
// Creation of 15 miners
IntStream.range(0, 15)
- .mapToObj(minerId -> new Miner(minerId, blockChain))
+ .mapToObj(minerId -> new Miner(minerId, blockchain))
.forEach(minerExecutor::submit);
minerExecutor.shutdown();
@@ -48,7 +48,7 @@ public final class Main {
transactionsExecutor.shutdownNow();
}
- FileManagement.saveBlockChain(blockChain);
+ FileManagement.saveBlockchain(blockchain);
}
diff --git a/src/main/java/model/Block.java b/src/main/java/model/Block.java
index f6952a4..7ab5d9a 100644
--- a/src/main/java/model/Block.java
+++ b/src/main/java/model/Block.java
@@ -48,7 +48,7 @@ public class Block implements Serializable {
public String toString() {
return "Block: " + "\n"
+ "Created by miner #" + this.minerId + "\n"
- + "miner #" + this.minerId + " gets 100 VC\n"
+ + "miner #" + this.minerId + " gets 100 KarmaCoins\n"
+ "Id: " + this.id + "\n"
+ "Timestamp: " + this.timeStamp + "\n"
+ "Magic number: " + this.magicNumber + "\n"
@@ -61,7 +61,7 @@ public class Block implements Serializable {
public String messagesToString() {
return transactions.isEmpty() ? "No transactions\n" : transactions.stream()
- .map(m -> "ID: ".concat(String.valueOf(m.getId()).concat(" - ").concat(m.getText()).concat("\n")))
+ .map(m -> "Id: ".concat(String.valueOf(m.getId()).concat(" - ").concat(m.getText()).concat("\n")))
.collect(Collectors.joining());
}
diff --git a/src/main/java/model/BlockChain.java b/src/main/java/model/Blockchain.java
similarity index 94%
rename from src/main/java/model/BlockChain.java
rename to src/main/java/model/Blockchain.java
index 39dd89a..16c5fac 100644
--- a/src/main/java/model/BlockChain.java
+++ b/src/main/java/model/Blockchain.java
@@ -18,7 +18,7 @@ import java.util.stream.Collectors;
import static java.lang.String.valueOf;
-public class BlockChain implements Serializable {
+public class Blockchain implements Serializable {
private static final long serialVersionUID = 1L;
private static final float LOWER_LIMIT_SECS = 0.1F;
@@ -35,17 +35,17 @@ public class BlockChain implements Serializable {
private int magicNumber;
private float generationSecs = 0;
- public static BlockChain getInstance() {
+ public static Blockchain getInstance() {
try {
- final BlockChain blockChain = (BlockChain) FileManagement.loadBlockChain();
- if (!blockChain.validateBlockchain()) {
+ final Blockchain blockchain = (Blockchain) FileManagement.loadBlockchain();
+ if (!blockchain.validateBlockchain()) {
System.out.println("Blockchain not valid! Creating new one");
- return new BlockChain();
+ return new Blockchain();
} else {
- return blockChain;
+ return blockchain;
}
} catch (final ClassNotFoundException | IOException e) {
- return new BlockChain();
+ return new Blockchain();
}
}
diff --git a/src/main/java/model/Miner.java b/src/main/java/model/Miner.java
index 6586b96..441326e 100644
--- a/src/main/java/model/Miner.java
+++ b/src/main/java/model/Miner.java
@@ -3,16 +3,16 @@ package model;
public class Miner implements Runnable {
private final int minerId;
- private final BlockChain blockChain;
+ private final Blockchain blockchain;
- public Miner(final int minerId, final BlockChain blockChain) {
+ public Miner(final int minerId, final Blockchain blockchain) {
this.minerId = minerId;
- this.blockChain = blockChain;
+ this.blockchain = blockchain;
}
@Override
public void run() {
- blockChain.addBlock(minerId);
+ blockchain.addBlock(minerId);
}
}
diff --git a/src/main/java/model/Transaction.java b/src/main/java/model/Transaction.java
index 9419ae1..171da38 100644
--- a/src/main/java/model/Transaction.java
+++ b/src/main/java/model/Transaction.java
@@ -23,7 +23,7 @@ public class Transaction implements Serializable {
final PublicKey publicKey
) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
this.id = id;
- this.text = sender + " sent " + amount + " VC to " + receiver;
+ this.text = sender + " sent " + amount + " KarmaCoins to " + receiver;
this.signature = Security.sign(text, privateKey);
this.publicKey = publicKey;
}
diff --git a/src/main/java/util/FileManagement.java b/src/main/java/util/FileManagement.java
index 0ec215a..bfabf90 100644
--- a/src/main/java/util/FileManagement.java
+++ b/src/main/java/util/FileManagement.java
@@ -11,13 +11,13 @@ import java.io.ObjectOutputStream;
public final class FileManagement {
- private static final String BLOCKCHAIN = "blockChain.txt";
+ private static final String BLOCKCHAIN = "blockchain.txt";
private FileManagement() {
throw new IllegalStateException("FileManagement class");
}
- public static void saveBlockChain(final Object obj) throws IOException {
+ public static void saveBlockchain(final Object obj) throws IOException {
final FileOutputStream fos = new FileOutputStream(BLOCKCHAIN);
final BufferedOutputStream bos = new BufferedOutputStream(fos);
final ObjectOutputStream oos = new ObjectOutputStream(bos);
@@ -25,7 +25,7 @@ public final class FileManagement {
oos.close();
}
- public static Object loadBlockChain() throws IOException, ClassNotFoundException {
+ public static Object loadBlockchain() throws IOException, ClassNotFoundException {
final FileInputStream fis = new FileInputStream(BLOCKCHAIN);
final BufferedInputStream bis = new BufferedInputStream(fis);
final ObjectInputStream ois = new ObjectInputStream(bis);
diff --git a/src/main/java/util/TransactionsGenerator.java b/src/main/java/util/TransactionsGenerator.java
index c19394d..f9dae46 100644
--- a/src/main/java/util/TransactionsGenerator.java
+++ b/src/main/java/util/TransactionsGenerator.java
@@ -2,14 +2,7 @@ package util;
import java.util.Arrays;
import java.util.stream.Stream;
-import model.BlockChain;
-import exceptions.NotEnoughCoinsException;
-
-import java.io.IOException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SignatureException;
-import java.security.spec.InvalidKeySpecException;
+import model.Blockchain;
import java.util.Random;
public class TransactionsGenerator implements Runnable {
@@ -20,11 +13,11 @@ public class TransactionsGenerator implements Runnable {
"Thom", "Jonny", "Ed", "Colin", "Phil"
).toArray(String[]::new);
- private final BlockChain blockChain;
+ private final Blockchain blockchain;
- public TransactionsGenerator(final BlockChain blockChain) {
- this.blockChain = blockChain;
- if (blockChain.getUsersCoins().isEmpty()) {
+ public TransactionsGenerator(final Blockchain blockchain) {
+ this.blockchain = blockchain;
+ if (blockchain.getUsersCoins().isEmpty()) {
setInitialUserCoins();
}
}
@@ -32,20 +25,18 @@ public class TransactionsGenerator implements Runnable {
@Override
public void run() {
try {
- blockChain.acceptTransaction(
- blockChain.getNextTransactionId(),
+ blockchain.acceptTransaction(
+ blockchain.getNextTransactionId(),
getRandomUserName(),
getRandomAmount(),
getRandomUserName()
);
- } catch (final NoSuchAlgorithmException |
- SignatureException |
- InvalidKeyException |
- IOException |
- InvalidKeySpecException |
- NotEnoughCoinsException e)
- {
- e.printStackTrace();
+/*
+ Catching throwable instead of exception to avoid ScheduledExecutorService from stop working
+ because any thrown exception or error reaching the executor causes the executor to halt.
+*/
+ } catch (final Throwable t) {
+ t.printStackTrace();
}
}
@@ -55,13 +46,13 @@ public class TransactionsGenerator implements Runnable {
private int getRandomAmount(){
final int MIN_AMOUNT = 1;
- final int MAX_AMOUNT = 100;
+ final int MAX_AMOUNT = 50;
return random.nextInt((MAX_AMOUNT - MIN_AMOUNT) + 1) + MIN_AMOUNT;
}
private void setInitialUserCoins() {
- Arrays.stream(userNames).forEach(userName -> blockChain.acceptUser(userName, INITIAL_COINS));
+ Arrays.stream(userNames).forEach(userName -> blockchain.acceptUser(userName, INITIAL_COINS));
}
}
\ No newline at end of file
diff --git a/src/main/resources/img/blockchain.png b/src/main/resources/img/blockchain.png
new file mode 100644
index 0000000..a9aeeec
Binary files /dev/null and b/src/main/resources/img/blockchain.png differ
diff --git a/src/test/java/BlockChainTest.java b/src/test/java/BlockchainTest.java
similarity index 80%
rename from src/test/java/BlockChainTest.java
rename to src/test/java/BlockchainTest.java
index 6d84f1a..8240106 100644
--- a/src/test/java/BlockChainTest.java
+++ b/src/test/java/BlockchainTest.java
@@ -13,24 +13,24 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-import model.BlockChain;
+import model.Blockchain;
import model.Miner;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-class BlockChainTest {
+class BlockchainTest {
private final int nThreads = Runtime.getRuntime().availableProcessors();
private List miners;
- private BlockChain blockChain;
+ private Blockchain blockchain;
@BeforeEach
public void setUp() {
- blockChain = new BlockChain();
- blockChain.acceptUser("tester1", 100);
- blockChain.acceptUser("tester2", 100);
+ blockchain = new Blockchain();
+ blockchain.acceptUser("tester1", 100);
+ blockchain.acceptUser("tester2", 100);
miners = IntStream.range(0, 5)
- .mapToObj(minerId -> new Miner(minerId, blockChain))
+ .mapToObj(minerId -> new Miner(minerId, blockchain))
.collect(Collectors.toList());
}
@@ -41,8 +41,8 @@ class BlockChainTest {
final var minerExecutor = Executors.newFixedThreadPool(nThreads);
for (final Miner miner: miners){
- blockChain.acceptTransaction(blockChain.getNextTransactionId(), "tester1", 10, "tester2");
- blockChain.acceptTransaction(blockChain.getNextTransactionId(), "tester2", 10, "tester1");
+ blockchain.acceptTransaction(blockchain.getNextTransactionId(), "tester1", 10, "tester2");
+ blockchain.acceptTransaction(blockchain.getNextTransactionId(), "tester2", 10, "tester1");
minerExecutor.execute(miner);
}
@@ -52,14 +52,14 @@ class BlockChainTest {
minerExecutor.shutdownNow();
}
- assertTrue(blockChain.validateBlockchain());
+ assertTrue(blockchain.validateBlockchain());
}
@Test
void block_chain_not_enough_coins_test() {
final NotEnoughCoinsException thrown = assertThrows(
NotEnoughCoinsException.class,
- () -> blockChain.acceptTransaction(
+ () -> blockchain.acceptTransaction(
1,
"tester1",
110,
@@ -72,7 +72,7 @@ class BlockChainTest {
void block_chain_not_self_transaction_test() {
final NoSelfTransactionException thrown = assertThrows(
NoSelfTransactionException.class,
- () -> blockChain.acceptTransaction(
+ () -> blockchain.acceptTransaction(
1,
"tester1",
10,