From ad57e674148439cd7dbb56f108bb8b0e40f26083 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Mon, 11 Oct 2021 11:42:26 +0200
Subject: [PATCH 01/12] [java][ideas][blockchain]review and notes for
exploration
---
README.md | 12 +++++-----
src/main/resources/BioJavaNotes.txt | 33 ----------------------------
src/main/resources/toInvestigate.txt | 14 ++++++++++++
3 files changed, 21 insertions(+), 38 deletions(-)
delete mode 100644 src/main/resources/BioJavaNotes.txt
create mode 100644 src/main/resources/toInvestigate.txt
diff --git a/README.md b/README.md
index 1724b08..0e5b8a2 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,10 @@
# DiversTestsJava
Quelques tests de programmation en Java, des notes diverses,
- * JDBC local (avec un peu de MySQL)
- * OAuth
- * Challenge CybserSec
- * Java Swing : Full Screen, SpalshScreen (à revoir / préciser)
- * Java reflect / réflexivité / introspection
+ * JDBC local (avec un peu de MySQL)
+ * OAuth
+ * Socket implementation
+ * HTTP use
+ * Challenge CybserSec (quelques notes)
+ * Java Swing : Full Screen, SpalshScreen (à revoir / préciser)
+ * Java reflect / réflexivité / introspection
diff --git a/src/main/resources/BioJavaNotes.txt b/src/main/resources/BioJavaNotes.txt
deleted file mode 100644
index e192846..0000000
--- a/src/main/resources/BioJavaNotes.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-https://biojava.org/wiki/BioJava%3AGetStarted --
-https://github.com/biojava/biojava --
-https://github.com/biojava/biojava-tutorial --
-https://mvnrepository.com/artifact/org.biojava --
-https://biojava.org/wiki/BioJava:CookBook4.0/ --
-https://biojava.org/docs/api/ --
-
-https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2530884/ BioJava: an open-source framework for bioinformatics
-
-https://www.developpez.net/forums/d827942/autres-langages/perl/bioinformatique/langage-bioinformatique/ --
-
-https://linuxfr.org/news/bioinformatique-libre --
-https://linuxfr.org/news/biologie-libre --
-http://www.bioinformatics.org/ --
-
-https://www.developpez.net/forums/d787364/autres-langages/perl/bioinformatique/creation-d-application-bioinformatique/ --
-https://www.developpez.net/forums/d253638-2/autres-langages/perl/bioinformatique/sondage-faq-bioinfo-tutoriaux/ --
-
-
-https://en.wikipedia.org/wiki/Bioinformatics --
- => Software and tools
- => Open-source bioinformatics software ;
- => Web services in bioinformatics ;
- => Bioinformatics workflow management systems ;
- => BioCompute and BioCompute Objects ;
- ...
-https://en.wikipedia.org/wiki/Bioinformatics_workflow_management_system -- Bioinformatics workflow management system
- => KNIME, Galaxy, (Pipeline Pilot)...
-https://en.wikipedia.org/wiki/List_of_bioinformatics_software -- List of bioinformatics software
-https://en.wikipedia.org/wiki/List_of_proprietary_bioinformatics_software -- List of proprietary bioinformatics software
-https://en.wikipedia.org/wiki/List_of_open-source_bioinformatics_software -- List of open-source bioinformatics software
-
-
diff --git a/src/main/resources/toInvestigate.txt b/src/main/resources/toInvestigate.txt
new file mode 100644
index 0000000..26671e0
--- /dev/null
+++ b/src/main/resources/toInvestigate.txt
@@ -0,0 +1,14 @@
+
+20211011
+
+Some tutorials and more ideas to test in java :
+ - security
+ - code project building
+ - blockchain
+
+#github #VeeralPatel "How to Secure Anything" #Security #CyberSecurity #Engineering ... https://github.com/veeral-patel/how-to-secure-anything
+#github #danistefanovic "Build Your Own {X}" Build #Code #Understanding #code #programming #development #Java #Python #JavaScript #Go #CPlusPlus #Git #Shell #Bot #BitTorrent #Game ... https://github.com/danistefanovic/build-your-own-x
+
+#medium #blockchain "Creating Your First Blockchain with Java. Part 1." #programmers #java #ProofOfWork ... https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+#medium #blockchain "Creating Your First Blockchain with Java. Part 2." #programmers #java #transactions ... https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+#medium #blockchain "Blockchain Development — Zero to Hero [Guide]" #programmers #development #guide ... https://medium.com/programmers-blockchain/blockchain-development-mega-guide-5a316e6d10df
From fd3bf6067632d46526d317fea81d57929acf24d6 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Mon, 11 Oct 2021 16:46:50 +0200
Subject: [PATCH 02/12] [blockchain]First Tutorial
---
pom.xml | 9 ++
.../gabywald/crypto/blockchain/Block.java | 48 ++++++
.../gabywald/crypto/blockchain/NoobChain.java | 144 ++++++++++++++++++
.../crypto/blockchain/StringUtil.java | 30 ++++
4 files changed, 231 insertions(+)
create mode 100644 src/main/java/gabywald/crypto/blockchain/Block.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/NoobChain.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/StringUtil.java
diff --git a/pom.xml b/pom.xml
index ab7560a..9089389 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,5 +48,14 @@
utilities
0.0.2-SNAPSHOT
+
+
+
+ com.google.code.gson
+ gson
+ 2.8.8
+
+
+
\ No newline at end of file
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
new file mode 100644
index 0000000..8cc624a
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -0,0 +1,48 @@
+package gabywald.crypto.blockchain;
+
+import java.util.Date;
+
+/**
+ * Block of BlockChain.
+ *
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ * @author Gabriel Chandesris (2021)
+ */
+public class Block {
+
+ public String hash;
+ public String previousHash;
+ private String data; //our data will be a simple message.
+ private long timeStamp; //as number of milliseconds since 1/1/1970.
+ private int nonce;
+
+ // Block Constructor.
+ public Block(String data,String previousHash ) {
+ this.data = data;
+ this.previousHash = previousHash;
+ this.timeStamp = new Date().getTime();
+
+ // Making sure we do this after we set the other values.
+ this.hash = calculateHash();
+ }
+
+ // Calculate new hash based on blocks contents
+ public String calculateHash() {
+ String calculatedhash = StringUtil.applySha256(
+ previousHash +
+ Long.toString(timeStamp) +
+ Integer.toString(nonce) +
+ data
+ );
+ return calculatedhash;
+ }
+
+ public void mineBlock(int difficulty) {
+ // Create a string with difficulty * "0"
+ String target = new String(new char[difficulty]).replace('\0', '0');
+ while(!hash.substring( 0, difficulty).equals(target)) {
+ nonce ++;
+ hash = calculateHash();
+ }
+ System.out.println("Block Mined!!! : " + hash);
+ }
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
new file mode 100644
index 0000000..d1e2d81
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -0,0 +1,144 @@
+package gabywald.crypto.blockchain;
+
+import java.util.ArrayList;
+
+import com.google.gson.GsonBuilder;
+
+/**
+ * StringUtil of BlockChain.
+ *
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ * @author Gabriel Chandesris (2021)
+ */
+public class NoobChain {
+
+ public static ArrayList blockchain = new ArrayList();
+ public static ArrayList blockchain2 = new ArrayList();
+
+ public static int difficulty = 5;
+
+ public static void main(String[] args) {
+
+ Block genesisBlock = new Block("Hi im the first block", "0");
+ System.out.println("Hash for block 1 : " + genesisBlock.hash);
+
+ Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
+ System.out.println("Hash for block 2 : " + secondBlock.hash);
+
+ Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
+ System.out.println("Hash for block 3 : " + thirdBlock.hash);
+
+
+ // Add our blocks to the blockchain ArrayList:
+ NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
+ NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+ NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
+ System.out.println(blockchainJson);
+
+
+ // Add our blocks to the blockchain ArrayList:
+ NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
+ System.out.println("Trying to Mine block 1... ");
+ NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
+
+ NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ System.out.println("Trying to Mine block 2... ");
+ NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
+
+ NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ System.out.println("Trying to Mine block 3... ");
+ NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
+
+ System.out.println("\nBlockchain is Valid: " + isChainValid());
+
+ String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
+ System.out.println("\nThe block chain: ");
+ System.out.println(blockchain2Json);
+
+ }
+
+ public static Boolean isChainValid() {
+ Block currentBlock;
+ Block previousBlock;
+
+ // Loop through blockchain to check hashes:
+ for (int i = 1 ; i < NoobChain.blockchain.size() ; i++) {
+ currentBlock = NoobChain.blockchain.get(i);
+ previousBlock = NoobChain.blockchain.get(i-1);
+ // Compare registered hash and calculated hash:
+ if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ System.out.println("Current Hashes not equal");
+ return false;
+ }
+ // Compare previous hash and registered previous hash
+ if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ System.out.println("Previous Hashes not equal");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /*
+Hash for block 1 : 9f98b14417f65bf7f55053d6ee948de264beaf4f4effdf1be1b80adb939a56bb
+Hash for block 2 : e7571024da930e1fee1dad719e0b8eeeefdf80c70a3a3739d83d9de1e23eced8
+Hash for block 3 : 7f18457511c26228726b46cb99248113973cb695df6918d78b1402c77435d003
+[
+ {
+ "hash": "b9e3632117413cb710d39c3a449747b6beeeb2b524f26c05882c3bd6af9d74e5",
+ "previousHash": "0",
+ "data": "Hi im the first block",
+ "timeStamp": 1633963207796
+ },
+ {
+ "hash": "7e27f719f013fec598427375fe7b880a5630ceaa901ee03348c17987cb4d392b",
+ "previousHash": "b9e3632117413cb710d39c3a449747b6beeeb2b524f26c05882c3bd6af9d74e5",
+ "data": "Yo im the second block",
+ "timeStamp": 1633963207796
+ },
+ {
+ "hash": "e12c29de9bbb838e5851d5d8ce59cac2e6225192c8e6b3afde054803e5483ee4",
+ "previousHash": "7e27f719f013fec598427375fe7b880a5630ceaa901ee03348c17987cb4d392b",
+ "data": "Hey im the third block",
+ "timeStamp": 1633963207796
+ }
+]
+ */
+
+ /*
+Trying to Mine block 1...
+Block Mined!!! : 00000206cc43b6e9b1e4d81cc5e2959296c0e1b90db2b0e509ef7fc3ec04095d
+Trying to Mine block 2...
+Block Mined!!! : 0000091a52ce1847ea50156a6cb4a5fd479fa0575f39a95011968c0b682cb5d9
+Trying to Mine block 3...
+Block Mined!!! : 0000043ba1e8397d791066bd0b9122339e03135abb451ccbf8b0efc37dc3a109
+
+Blockchain is Valid: true
+
+The block chain:
+[
+ {
+ "hash": "00000206cc43b6e9b1e4d81cc5e2959296c0e1b90db2b0e509ef7fc3ec04095d",
+ "previousHash": "0",
+ "data": "Hi im the first block",
+ "timeStamp": 1633963490480,
+ "nonce": 285549
+ },
+ {
+ "hash": "0000091a52ce1847ea50156a6cb4a5fd479fa0575f39a95011968c0b682cb5d9",
+ "previousHash": "00000206cc43b6e9b1e4d81cc5e2959296c0e1b90db2b0e509ef7fc3ec04095d",
+ "data": "Yo im the second block",
+ "timeStamp": 1633963491272,
+ "nonce": 3329949
+ },
+ {
+ "hash": "0000043ba1e8397d791066bd0b9122339e03135abb451ccbf8b0efc37dc3a109",
+ "previousHash": "0000091a52ce1847ea50156a6cb4a5fd479fa0575f39a95011968c0b682cb5d9",
+ "data": "Hey im the third block",
+ "timeStamp": 1633963497804,
+ "nonce": 3752258
+ }
+]
+ */
+}
+
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtil.java b/src/main/java/gabywald/crypto/blockchain/StringUtil.java
new file mode 100644
index 0000000..5ad1cdc
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtil.java
@@ -0,0 +1,30 @@
+package gabywald.crypto.blockchain;
+
+import java.security.MessageDigest;
+
+/**
+ * StringUtil of BlockChain.
+ *
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ * @author Gabriel Chandesris (2021)
+ */
+public class StringUtil {
+ //Applies Sha256 to a string and returns the result.
+ public static String applySha256(String input){
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ // Applies sha256 to our input,
+ byte[] hash = digest.digest(input.getBytes("UTF-8"));
+ StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
+ for (int i = 0; i < hash.length; i++) {
+ String hex = Integer.toHexString(0xff & hash[i]);
+ if(hex.length() == 1) hexString.append('0');
+ hexString.append(hex);
+ }
+ return hexString.toString();
+ }
+ catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
+
From 1ead7a9133a15b121ae4b0b955994867cc6d9935 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Mon, 11 Oct 2021 19:15:05 +0200
Subject: [PATCH 03/12] [blockchain]Second Tutorial intermediate notes
---
.../gabywald/crypto/blockchain/Block.java | 19 ++-
.../gabywald/crypto/blockchain/NoobChain.java | 118 ++++++++-----
.../crypto/blockchain/StringUtil.java | 30 ----
.../crypto/blockchain/StringUtils.java | 104 +++++++++++
.../crypto/blockchain/Transaction.java | 161 ++++++++++++++++++
.../crypto/blockchain/TransactionInput.java | 16 ++
.../crypto/blockchain/TransactionOutput.java | 30 ++++
.../gabywald/crypto/blockchain/Wallet.java | 43 +++++
8 files changed, 440 insertions(+), 81 deletions(-)
delete mode 100644 src/main/java/gabywald/crypto/blockchain/StringUtil.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/StringUtils.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/Transaction.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/TransactionInput.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/Wallet.java
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 8cc624a..0e1d0fa 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -5,6 +5,7 @@
/**
* Block of BlockChain.
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
* @author Gabriel Chandesris (2021)
*/
public class Block {
@@ -27,11 +28,11 @@ public Block(String data,String previousHash ) {
// Calculate new hash based on blocks contents
public String calculateHash() {
- String calculatedhash = StringUtil.applySha256(
- previousHash +
- Long.toString(timeStamp) +
- Integer.toString(nonce) +
- data
+ String calculatedhash = StringUtils.applySha256(
+ this.previousHash +
+ Long.toString(this.timeStamp) +
+ Integer.toString(this.nonce) +
+ this.data
);
return calculatedhash;
}
@@ -39,10 +40,10 @@ public String calculateHash() {
public void mineBlock(int difficulty) {
// Create a string with difficulty * "0"
String target = new String(new char[difficulty]).replace('\0', '0');
- while(!hash.substring( 0, difficulty).equals(target)) {
- nonce ++;
- hash = calculateHash();
+ while ( ! this.hash.substring( 0, difficulty).equals(target)) {
+ this.nonce++;
+ this.hash = this.calculateHash();
}
- System.out.println("Block Mined!!! : " + hash);
+ System.out.println("Block Mined!!! : " + this.hash);
}
}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index d1e2d81..db5c8ae 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -1,62 +1,96 @@
package gabywald.crypto.blockchain;
+import java.security.Security;
import java.util.ArrayList;
+import java.util.HashMap;
+// TODO replace GsonBuilder !! (build json from objet !)
import com.google.gson.GsonBuilder;
/**
- * StringUtil of BlockChain.
+ * NoobChain Test and Main Class of BlockChain.
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
+ *
* @author Gabriel Chandesris (2021)
*/
public class NoobChain {
public static ArrayList blockchain = new ArrayList();
- public static ArrayList blockchain2 = new ArrayList();
+ public static ArrayList blockchain2 = new ArrayList();
+ public static ArrayList blockchain3 = new ArrayList();
+
+ public static int difficulty = 3;
+
+ public static Wallet walletA;
+ public static Wallet walletB;
+
+ // List of all unspent transactions.
+ public static HashMap UTXOs = new HashMap();
- public static int difficulty = 5;
+ public static float minimumTransaction = 0.1f;
+ public static Transaction genesisTransaction;
public static void main(String[] args) {
- Block genesisBlock = new Block("Hi im the first block", "0");
- System.out.println("Hash for block 1 : " + genesisBlock.hash);
-
- Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
- System.out.println("Hash for block 2 : " + secondBlock.hash);
-
- Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
- System.out.println("Hash for block 3 : " + thirdBlock.hash);
-
-
- // Add our blocks to the blockchain ArrayList:
- NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
- NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
- NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
- String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
- System.out.println(blockchainJson);
-
-
- // Add our blocks to the blockchain ArrayList:
- NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
- System.out.println("Trying to Mine block 1... ");
- NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
-
- NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
- System.out.println("Trying to Mine block 2... ");
- NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
-
- NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
- System.out.println("Trying to Mine block 3... ");
- NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
-
- System.out.println("\nBlockchain is Valid: " + isChainValid());
-
- String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
- System.out.println("\nThe block chain: ");
- System.out.println(blockchain2Json);
+// Block genesisBlock = new Block("Hi im the first block", "0");
+// System.out.println("Hash for block 1 : " + genesisBlock.hash);
+//
+// Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
+// System.out.println("Hash for block 2 : " + secondBlock.hash);
+//
+// Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
+// System.out.println("Hash for block 3 : " + thirdBlock.hash);
+//
+//
+// // Add our blocks to the blockchain ArrayList:
+// NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
+// NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+// NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+// String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
+// System.out.println(blockchainJson);
+//
+//
+// // Add our blocks to the blockchain ArrayList:
+// NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
+// System.out.println("Trying to Mine block 1... ");
+// NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
+//
+// NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+// System.out.println("Trying to Mine block 2... ");
+// NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
+//
+// NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+// System.out.println("Trying to Mine block 3... ");
+// NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
+//
+// System.out.println("\nBlockchain is Valid: " + isChainValid());
+//
+// String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
+// System.out.println("\nThe block chain: ");
+// System.out.println(blockchain2Json);
+
+
+ // Setup Bouncey castle as a Security Provider
+ // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ // Security.addProvider(new sun.security.provider.Sun());
+ // XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+ //Create the new wallets
+ walletA = new Wallet();
+ walletB = new Wallet();
+ //Test public and private keys
+ System.out.println("Private and public keys:");
+ System.out.println(StringUtils.getStringFromKey(walletA.privateKey));
+ System.out.println(StringUtils.getStringFromKey(walletA.publicKey));
+ //Create a test transaction from WalletA to walletB
+ Transaction transaction = new Transaction(NoobChain.walletA.publicKey, NoobChain.walletB.publicKey, 5, null);
+ transaction.generateSignature(NoobChain.walletA.privateKey);
+ //Verify the signature works and verify it from the public key
+ System.out.println("Is signature verified");
+ System.out.println(transaction.verifiySignature());
}
-
+
public static Boolean isChainValid() {
Block currentBlock;
Block previousBlock;
@@ -78,7 +112,7 @@ public static Boolean isChainValid() {
}
return true;
}
-
+
/*
Hash for block 1 : 9f98b14417f65bf7f55053d6ee948de264beaf4f4effdf1be1b80adb939a56bb
Hash for block 2 : e7571024da930e1fee1dad719e0b8eeeefdf80c70a3a3739d83d9de1e23eced8
@@ -104,7 +138,7 @@ public static Boolean isChainValid() {
}
]
*/
-
+
/*
Trying to Mine block 1...
Block Mined!!! : 00000206cc43b6e9b1e4d81cc5e2959296c0e1b90db2b0e509ef7fc3ec04095d
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtil.java b/src/main/java/gabywald/crypto/blockchain/StringUtil.java
deleted file mode 100644
index 5ad1cdc..0000000
--- a/src/main/java/gabywald/crypto/blockchain/StringUtil.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package gabywald.crypto.blockchain;
-
-import java.security.MessageDigest;
-
-/**
- * StringUtil of BlockChain.
- *
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
- * @author Gabriel Chandesris (2021)
- */
-public class StringUtil {
- //Applies Sha256 to a string and returns the result.
- public static String applySha256(String input){
- try {
- MessageDigest digest = MessageDigest.getInstance("SHA-256");
- // Applies sha256 to our input,
- byte[] hash = digest.digest(input.getBytes("UTF-8"));
- StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
- for (int i = 0; i < hash.length; i++) {
- String hex = Integer.toHexString(0xff & hash[i]);
- if(hex.length() == 1) hexString.append('0');
- hexString.append(hex);
- }
- return hexString.toString();
- }
- catch(Exception e) {
- throw new RuntimeException(e);
- }
- }
-}
-
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
new file mode 100644
index 0000000..811ab22
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -0,0 +1,104 @@
+package gabywald.crypto.blockchain;
+
+import java.security.Key;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.util.ArrayList;
+import java.util.Base64;
+
+/**
+ * StringUtil of BlockChain.
+ *
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ * @author Gabriel Chandesris (2021)
+ */
+public class StringUtils {
+
+ //Applies Sha256 to a string and returns the result.
+ public static String applySha256(String input){
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ // Applies sha256 to our input,
+ byte[] hash = digest.digest(input.getBytes("UTF-8"));
+ StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
+ for (int i = 0; i < hash.length; i++) {
+ String hex = Integer.toHexString(0xff & hash[i]);
+ if(hex.length() == 1) hexString.append('0');
+ hexString.append(hex);
+ }
+ return hexString.toString();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static final String ECDSA = "ECDSA";
+ public static final String BC = "BC";
+
+ public static final String CipherAlgorithm = "DiffieHellman"; // "SHA1withDSA";
+ public static final String CipherProvider = "SunJCE"; // "SUN";
+
+ // XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+
+ // Applies ECDSA Signature and returns the result ( as bytes ).
+ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
+ Signature dsa;
+ byte[] output = new byte[0];
+ try {
+ dsa = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
+ Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ dsa.initSign(privateKey);
+ byte[] strByte = input.getBytes();
+ dsa.update(strByte);
+ byte[] realSig = dsa.sign();
+ output = realSig;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return output;
+ }
+
+ // Verifies a String signature
+ public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
+ try {
+ Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
+ Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ ecdsaVerify.initVerify(publicKey);
+ ecdsaVerify.update(data.getBytes());
+ return ecdsaVerify.verify(signature);
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String getStringFromKey(Key key) {
+ return Base64.getEncoder().encodeToString(key.getEncoded());
+ }
+
+ // Tacks in array of transactions and returns a merkle root.
+ public static String getMerkleRoot(ArrayList transactions) {
+ int count = transactions.size();
+ ArrayList previousTreeLayer = new ArrayList();
+ for(Transaction transaction : transactions) {
+ previousTreeLayer.add(transaction.transactionId);
+ }
+ ArrayList treeLayer = previousTreeLayer;
+ while(count > 1) {
+ treeLayer = new ArrayList();
+ for(int i=1; i < previousTreeLayer.size(); i++) {
+ treeLayer.add(applySha256(previousTreeLayer.get(i-1) + previousTreeLayer.get(i)));
+ }
+ count = treeLayer.size();
+ previousTreeLayer = treeLayer;
+ }
+ String merkleRoot = (treeLayer.size() == 1) ? treeLayer.get(0) : "";
+ return merkleRoot;
+ }
+
+}
+
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
new file mode 100644
index 0000000..6bf3be4
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -0,0 +1,161 @@
+package gabywald.crypto.blockchain;
+
+import java.security.Key;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+
+import java.util.ArrayList;
+import java.util.Base64;
+
+/**
+ * Transaction of BlockChain.
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ * @author Gabriel Chandesris (2021)
+ */
+public class Transaction {
+ /** This is also the hash of the transaction. */
+ public String transactionId;
+ /** senders address/public key. */
+ public PublicKey sender;
+ /** Recipients address/public key. */
+ public PublicKey reciepient;
+ public float value;
+ /** This is to prevent anybody else from spending funds in our wallet. */
+ public byte[] signature;
+
+ public ArrayList inputs = new ArrayList();
+ public ArrayList outputs = new ArrayList();
+
+ private static int sequence = 0; // a rough count of how many transactions have been generated.
+
+ // Constructor:
+ public Transaction(PublicKey from, PublicKey to, float value, ArrayList inputs) {
+ this.sender = from;
+ this.reciepient = to;
+ this.value = value;
+ this.inputs = inputs;
+ }
+
+ // This Calculates the transaction hash (which will be used as its Id)
+ private String calulateHash() {
+ // Increase the sequence to avoid 2 identical transactions having the same hash
+ Transaction.sequence++;
+ return StringUtils.applySha256(
+ StringUtils.getStringFromKey(this.sender) +
+ StringUtils.getStringFromKey(this.reciepient) +
+ Float.toString(value) + Transaction.sequence
+ );
+ }
+
+ // Applies ECDSA Signature and returns the result ( as bytes ).
+ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
+ Signature dsa;
+ byte[] output = new byte[0];
+ try {
+ dsa = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
+ Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ dsa.initSign(privateKey);
+ byte[] strByte = input.getBytes();
+ dsa.update(strByte);
+ byte[] realSig = dsa.sign();
+ output = realSig;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return output;
+ }
+
+ // Verifies a String signature
+ public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
+ try {
+ Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
+ Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ ecdsaVerify.initVerify(publicKey);
+ ecdsaVerify.update(data.getBytes());
+ return ecdsaVerify.verify(signature);
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static String getStringFromKey(Key key) {
+ return Base64.getEncoder().encodeToString(key.getEncoded());
+ }
+
+ // Signs all the data we don't wish to be tampered with.
+ public void generateSignature(PrivateKey privateKey) {
+ String data = StringUtils.getStringFromKey(this.sender)
+ + StringUtils.getStringFromKey(this.reciepient)
+ + Float.toString(this.value);
+ this.signature = StringUtils.applyECDSASig(privateKey,data);
+ }
+
+ // Verifies the data we signed hasn't been tampered with
+ public boolean verifiySignature() {
+ String data = StringUtils.getStringFromKey(this.sender)
+ + StringUtils.getStringFromKey(this.reciepient)
+ + Float.toString(this.value);
+ return StringUtils.verifyECDSASig(this.sender, data, this.signature);
+ }
+
+ // Returns true if new transaction could be created.
+ public boolean processTransaction() {
+
+ if(verifiySignature() == false) {
+ System.out.println("#Transaction Signature failed to verify");
+ return false;
+ }
+
+ // gather transaction inputs (Make sure they are unspent):
+ for(TransactionInput i : inputs) {
+ i.UTXO = NoobChain.UTXOs.get(i.transactionOutputId);
+ }
+
+ // check if transaction is valid:
+ if (getInputsValue() < NoobChain.minimumTransaction) {
+ System.out.println("#Transaction Inputs to small: " + getInputsValue());
+ return false;
+ }
+
+ // generate transaction outputs:
+ float leftOver = getInputsValue() - value; // get value of inputs then the left over change:
+ transactionId = calulateHash();
+ outputs.add(new TransactionOutput( this.reciepient, value, transactionId)); // send value to recipient
+ outputs.add(new TransactionOutput( this.sender, leftOver ,transactionId)); // send the left over 'change' back to sender
+
+ // add outputs to Unspent list
+ for(TransactionOutput o : outputs) {
+ NoobChain.UTXOs.put(o.id , o);
+ }
+
+ //remove transaction inputs from UTXO lists as spent:
+ for(TransactionInput i : inputs) {
+ if(i.UTXO == null) continue; //if Transaction can't be found skip it
+ NoobChain.UTXOs.remove(i.UTXO.id);
+ }
+
+ return true;
+ }
+
+ //returns sum of inputs(UTXOs) values
+ public float getInputsValue() {
+ float total = 0;
+ for(TransactionInput i : inputs) {
+ if(i.UTXO == null) continue; //if Transaction can't be found skip it
+ total += i.UTXO.value;
+ }
+ return total;
+ }
+
+ //returns sum of outputs:
+ public float getOutputsValue() {
+ float total = 0;
+ for(TransactionOutput o : outputs) {
+ total += o.value;
+ }
+ return total;
+ }
+
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionInput.java b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
new file mode 100644
index 0000000..831955b
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
@@ -0,0 +1,16 @@
+package gabywald.crypto.blockchain;
+
+/**
+ * TransactionInput of BlockChain.
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ * @author Gabriel Chandesris (2021)
+ */
+public class TransactionInput {
+ public String transactionOutputId; //Reference to TransactionOutputs -> transactionId
+ public TransactionOutput UTXO; //Contains the Unspent transaction output
+
+ public TransactionInput(String transactionOutputId) {
+ this.transactionOutputId = transactionOutputId;
+ }
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
new file mode 100644
index 0000000..07ac913
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
@@ -0,0 +1,30 @@
+package gabywald.crypto.blockchain;
+
+import java.security.PublicKey;
+
+/**
+ * TransactionOutput of BlockChain.
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ * @author Gabriel Chandesris (2021)
+ */
+public class TransactionOutput {
+ public String id;
+ public PublicKey reciepient; // Also known as the new owner of these coins.
+ public float value; // The amount of coins they own
+ public String parentTransactionId; // The id of the transaction this output was created in
+
+ //Constructor
+ public TransactionOutput(PublicKey reciepient, float value, String parentTransactionId) {
+ this.reciepient = reciepient;
+ this.value = value;
+ this.parentTransactionId = parentTransactionId;
+ this.id = StringUtils.applySha256(StringUtils.getStringFromKey(reciepient)+Float.toString(value)+parentTransactionId);
+ }
+
+ //Check if coin belongs to you
+ public boolean isMine(PublicKey publicKey) {
+ return (publicKey == reciepient);
+ }
+
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
new file mode 100644
index 0000000..b5f4810
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -0,0 +1,43 @@
+package gabywald.crypto.blockchain;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.ECGenParameterSpec;
+
+/**
+ * Wallet of BlockChain.
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ * @author Gabriel Chandesris (2021)
+ */
+public class Wallet {
+
+ public PrivateKey privateKey;
+ public PublicKey publicKey;
+
+ public Wallet() {
+ generateKeyPair();
+ }
+
+ public void generateKeyPair() {
+ try {
+ KeyPairGenerator keyGen = // KeyPairGenerator.getInstance(StringUtil.ECDSA, StringUtil.BC);
+ KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+ ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime192v1");
+ // Initialize the key generator and generate a KeyPair : 256 bytes provides an acceptable security level
+ keyGen.initialize(ecSpec, random);
+ KeyPair keyPair = keyGen.generateKeyPair();
+ // Set the public and private keys from the keyPair
+ privateKey = keyPair.getPrivate();
+ publicKey = keyPair.getPublic();
+ } catch(Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
+
From dca95f9afcb5430ea4651f71078805302d32fcac Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Mon, 11 Oct 2021 19:20:24 +0200
Subject: [PATCH 04/12] [blockchain]Second Tutorial intermediate notes TODO
---
src/main/java/gabywald/crypto/blockchain/NoobChain.java | 3 ++-
src/main/java/gabywald/crypto/blockchain/StringUtils.java | 1 +
src/main/java/gabywald/crypto/blockchain/Wallet.java | 1 +
3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index db5c8ae..d6c5057 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -11,7 +11,8 @@
* NoobChain Test and Main Class of BlockChain.
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
- *
+
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
* @author Gabriel Chandesris (2021)
*/
public class NoobChain {
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 811ab22..0b03ffb 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -44,6 +44,7 @@ public static String applySha256(String input){
public static final String CipherProvider = "SunJCE"; // "SUN";
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+ // TODO learning how security works here !
// Applies ECDSA Signature and returns the result ( as bytes ).
public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index b5f4810..7e3fb5e 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -24,6 +24,7 @@ public Wallet() {
public void generateKeyPair() {
try {
+ // TODO learning how security works here !
KeyPairGenerator keyGen = // KeyPairGenerator.getInstance(StringUtil.ECDSA, StringUtil.BC);
KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
From 0140831c22b3e4bfa23fb0024c99e5170f6871a5 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Mon, 11 Oct 2021 19:28:23 +0200
Subject: [PATCH 05/12] [blockchain]Second Tutorial intermediate notes Review
code / comments
---
.../gabywald/crypto/blockchain/Block.java | 6 +-
.../crypto/blockchain/StringUtils.java | 37 +++++++--
.../crypto/blockchain/Transaction.java | 80 +++++++++++++------
.../crypto/blockchain/TransactionInput.java | 6 +-
.../crypto/blockchain/TransactionOutput.java | 25 ++++--
.../gabywald/crypto/blockchain/Wallet.java | 2 +-
6 files changed, 115 insertions(+), 41 deletions(-)
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 0e1d0fa..32a756c 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -16,7 +16,11 @@ public class Block {
private long timeStamp; //as number of milliseconds since 1/1/1970.
private int nonce;
- // Block Constructor.
+ /**
+ * Block Constructor.
+ * @param data
+ * @param previousHash
+ */
public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 0b03ffb..3b64ba8 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -18,16 +18,22 @@
*/
public class StringUtils {
- //Applies Sha256 to a string and returns the result.
+ /**
+ * Applies Sha256 to a string and returns the result.
+ * @param input
+ * @return
+ */
public static String applySha256(String input){
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Applies sha256 to our input,
byte[] hash = digest.digest(input.getBytes("UTF-8"));
StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
- for (int i = 0; i < hash.length; i++) {
+ for (int i = 0 ; i < hash.length ; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
- if(hex.length() == 1) hexString.append('0');
+ if (hex.length() == 1) {
+ hexString.append('0');
+ }
hexString.append(hex);
}
return hexString.toString();
@@ -46,7 +52,12 @@ public static String applySha256(String input){
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
// TODO learning how security works here !
- // Applies ECDSA Signature and returns the result ( as bytes ).
+ /**
+ * Applies ECDSA Signature and returns the result ( as bytes ).
+ * @param privateKey
+ * @param input
+ * @return
+ */
public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
Signature dsa;
byte[] output = new byte[0];
@@ -64,7 +75,13 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
return output;
}
- // Verifies a String signature
+ /**
+ * Verifies a String signature.
+ * @param publicKey
+ * @param data
+ * @param signature
+ * @return
+ */
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
@@ -81,7 +98,11 @@ public static String getStringFromKey(Key key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
- // Tacks in array of transactions and returns a merkle root.
+ /**
+ * Tacks in array of transactions and returns a merkle root.
+ * @param transactions
+ * @return
+ */
public static String getMerkleRoot(ArrayList transactions) {
int count = transactions.size();
ArrayList previousTreeLayer = new ArrayList();
@@ -89,9 +110,9 @@ public static String getMerkleRoot(ArrayList transactions) {
previousTreeLayer.add(transaction.transactionId);
}
ArrayList treeLayer = previousTreeLayer;
- while(count > 1) {
+ while (count > 1) {
treeLayer = new ArrayList();
- for(int i=1; i < previousTreeLayer.size(); i++) {
+ for (int i = 1 ; i < previousTreeLayer.size() ; i++) {
treeLayer.add(applySha256(previousTreeLayer.get(i-1) + previousTreeLayer.get(i)));
}
count = treeLayer.size();
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index 6bf3be4..b1eae65 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -38,7 +38,10 @@ public Transaction(PublicKey from, PublicKey to, float value, ArrayList transactionId
- public TransactionOutput UTXO; //Contains the Unspent transaction output
+ /** Reference to TransactionOutputs -> transactionId */
+ public String transactionOutputId;
+ /** Contains the Unspent transaction output */
+ public TransactionOutput UTXO;
public TransactionInput(String transactionOutputId) {
this.transactionOutputId = transactionOutputId;
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
index 07ac913..95ab32f 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
@@ -10,19 +10,32 @@
*/
public class TransactionOutput {
public String id;
- public PublicKey reciepient; // Also known as the new owner of these coins.
- public float value; // The amount of coins they own
- public String parentTransactionId; // The id of the transaction this output was created in
+ /** Also known as the new owner of these coins. */
+ public PublicKey reciepient;
+ /** The amount of coins they own */
+ public float value;
+ /** The id of the transaction this output was created in */
+ public String parentTransactionId;
- //Constructor
+ /**
+ * Constructor
+ * @param reciepient
+ * @param value
+ * @param parentTransactionId
+ */
public TransactionOutput(PublicKey reciepient, float value, String parentTransactionId) {
this.reciepient = reciepient;
this.value = value;
this.parentTransactionId = parentTransactionId;
- this.id = StringUtils.applySha256(StringUtils.getStringFromKey(reciepient)+Float.toString(value)+parentTransactionId);
+ this.id = StringUtils.applySha256(StringUtils.getStringFromKey(reciepient)
+ + Float.toString(value)+parentTransactionId);
}
- //Check if coin belongs to you
+ /**
+ * Check if coin belongs to you.
+ * @param publicKey
+ * @return
+ */
public boolean isMine(PublicKey publicKey) {
return (publicKey == reciepient);
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 7e3fb5e..1b1dead 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -35,7 +35,7 @@ public void generateKeyPair() {
// Set the public and private keys from the keyPair
privateKey = keyPair.getPrivate();
publicKey = keyPair.getPublic();
- } catch(Exception e) {
+ } catch (Exception e) {
throw new RuntimeException(e);
}
}
From b0c7b355082cbfc9b06769152b6abd059bc86d48 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Tue, 12 Oct 2021 18:22:51 +0200
Subject: [PATCH 06/12] [blockchain]cryptography using Bouncy Castle Provider
---
pom.xml | 7 ++
.../gabywald/crypto/blockchain/NoobChain.java | 85 ++++++++++---------
.../crypto/blockchain/StringUtils.java | 21 ++---
.../crypto/blockchain/Transaction.java | 15 ++--
.../gabywald/crypto/blockchain/Wallet.java | 4 +-
5 files changed, 72 insertions(+), 60 deletions(-)
diff --git a/pom.xml b/pom.xml
index 9089389..9d6655d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,12 +49,19 @@
0.0.2-SNAPSHOT
+
com.google.code.gson
gson
2.8.8
+
+
+ org.bouncycastle
+ bcprov-jdk15to18
+ 1.69
+
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index d6c5057..3fd18c1 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -1,6 +1,7 @@
package gabywald.crypto.blockchain;
import java.security.Security;
+import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
@@ -11,15 +12,15 @@
* NoobChain Test and Main Class of BlockChain.
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
-
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
* @author Gabriel Chandesris (2021)
*/
public class NoobChain {
- public static ArrayList blockchain = new ArrayList();
- public static ArrayList blockchain2 = new ArrayList();
- public static ArrayList blockchain3 = new ArrayList();
+ public static List blockchain = new ArrayList();
+ public static List blockchain2 = new ArrayList();
+ public static List blockchain3 = new ArrayList();
public static int difficulty = 3;
@@ -34,47 +35,46 @@ public class NoobChain {
public static void main(String[] args) {
-// Block genesisBlock = new Block("Hi im the first block", "0");
-// System.out.println("Hash for block 1 : " + genesisBlock.hash);
-//
-// Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
-// System.out.println("Hash for block 2 : " + secondBlock.hash);
-//
-// Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
-// System.out.println("Hash for block 3 : " + thirdBlock.hash);
-//
-//
-// // Add our blocks to the blockchain ArrayList:
-// NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
-// NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
-// NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
-// String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
-// System.out.println(blockchainJson);
-//
-//
-// // Add our blocks to the blockchain ArrayList:
-// NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
-// System.out.println("Trying to Mine block 1... ");
-// NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
-//
-// NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
-// System.out.println("Trying to Mine block 2... ");
-// NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
-//
-// NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
-// System.out.println("Trying to Mine block 3... ");
-// NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
-//
-// System.out.println("\nBlockchain is Valid: " + isChainValid());
-//
-// String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
-// System.out.println("\nThe block chain: ");
-// System.out.println(blockchain2Json);
+ // ***** Part I
+ Block genesisBlock = new Block("Hi im the first block", "0");
+ System.out.println("Hash for block 1 : " + genesisBlock.hash);
+ Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
+ System.out.println("Hash for block 2 : " + secondBlock.hash);
+ Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
+ System.out.println("Hash for block 3 : " + thirdBlock.hash);
+ // ***** Part II
+ // Add our blocks to the blockchain List:
+ NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
+ NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+ NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
+ System.out.println(blockchainJson);
+ // ***** Part III
+ // Add our blocks to the blockchain List:
+ NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
+ System.out.println("Trying to Mine block 1... ");
+ NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
+
+ NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ System.out.println("Trying to Mine block 2... ");
+ NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
+
+ NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ System.out.println("Trying to Mine block 3... ");
+ NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
+
+ System.out.println("\nBlockchain is Valid: " + isChainValid());
+
+ String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
+ System.out.println("\nThe block chain: ");
+ System.out.println(blockchain2Json);
+
+ // ***** Part IV
// Setup Bouncey castle as a Security Provider
- // Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Security.addProvider(new sun.security.provider.Sun());
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
//Create the new wallets
@@ -90,6 +90,9 @@ public static void main(String[] args) {
//Verify the signature works and verify it from the public key
System.out.println("Is signature verified");
System.out.println(transaction.verifiySignature());
+
+ // ***** Part V
+ // TODO next step of tutorials !!
}
public static Boolean isChainValid() {
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 3b64ba8..e6581eb 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -5,6 +5,7 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
+import java.util.List;
import java.util.ArrayList;
import java.util.Base64;
@@ -43,11 +44,11 @@ public static String applySha256(String input){
}
}
- public static final String ECDSA = "ECDSA";
- public static final String BC = "BC";
+ public static final String ECDSA = "ECDSA"; // CipherAlgorithm
+ public static final String BC = "BC"; // CipherProvider
- public static final String CipherAlgorithm = "DiffieHellman"; // "SHA1withDSA";
- public static final String CipherProvider = "SunJCE"; // "SUN";
+// public static final String CipherAlgorithm = "DiffieHellman"; // "SHA1withDSA";
+// public static final String CipherProvider = "SunJCE"; // "SUN";
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
// TODO learning how security works here !
@@ -62,8 +63,8 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
Signature dsa;
byte[] output = new byte[0];
try {
- dsa = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
- Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ dsa = Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ // Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
dsa.initSign(privateKey);
byte[] strByte = input.getBytes();
dsa.update(strByte);
@@ -85,7 +86,7 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
- Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(data.getBytes());
return ecdsaVerify.verify(signature);
@@ -103,13 +104,13 @@ public static String getStringFromKey(Key key) {
* @param transactions
* @return
*/
- public static String getMerkleRoot(ArrayList transactions) {
+ public static String getMerkleRoot(List transactions) {
int count = transactions.size();
- ArrayList previousTreeLayer = new ArrayList();
+ List previousTreeLayer = new ArrayList();
for(Transaction transaction : transactions) {
previousTreeLayer.add(transaction.transactionId);
}
- ArrayList treeLayer = previousTreeLayer;
+ List treeLayer = previousTreeLayer;
while (count > 1) {
treeLayer = new ArrayList();
for (int i = 1 ; i < previousTreeLayer.size() ; i++) {
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index b1eae65..3be892f 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -5,6 +5,7 @@
import java.security.PublicKey;
import java.security.Signature;
+import java.util.List;
import java.util.ArrayList;
import java.util.Base64;
@@ -25,13 +26,13 @@ public class Transaction {
/** This is to prevent anybody else from spending funds in our wallet. */
public byte[] signature;
- public ArrayList inputs = new ArrayList();
- public ArrayList outputs = new ArrayList();
+ public List inputs = new ArrayList();
+ public List outputs = new ArrayList();
private static int sequence = 0; // a rough count of how many transactions have been generated.
// Constructor:
- public Transaction(PublicKey from, PublicKey to, float value, ArrayList inputs) {
+ public Transaction(PublicKey from, PublicKey to, float value, List inputs) {
this.sender = from;
this.reciepient = to;
this.value = value;
@@ -62,8 +63,8 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
Signature dsa;
byte[] output = new byte[0];
try {
- dsa = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
- Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ dsa = Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ // Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
dsa.initSign(privateKey);
byte[] strByte = input.getBytes();
dsa.update(strByte);
@@ -84,8 +85,8 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
*/
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
- Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
- Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ Signature ecdsaVerify = Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ // Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(data.getBytes());
return ecdsaVerify.verify(signature);
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 1b1dead..afba656 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -25,8 +25,8 @@ public Wallet() {
public void generateKeyPair() {
try {
// TODO learning how security works here !
- KeyPairGenerator keyGen = // KeyPairGenerator.getInstance(StringUtil.ECDSA, StringUtil.BC);
- KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ // KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime192v1");
// Initialize the key generator and generate a KeyPair : 256 bytes provides an acceptable security level
From f1427c0257ae7493d156681d5e789516d4e72588 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Wed, 13 Oct 2021 16:10:34 +0200
Subject: [PATCH 07/12] [blockchain]Some review and rework (exceptions)
---
README.md | 1 +
.../gabywald/crypto/blockchain/Block.java | 37 +++++++----
.../blockchain/BlockchainException.java | 14 ++++
.../gabywald/crypto/blockchain/NoobChain.java | 10 +--
.../crypto/blockchain/StringUtils.java | 54 ++++++++++++----
.../crypto/blockchain/Transaction.java | 64 +++++++++++--------
.../crypto/blockchain/TransactionOutput.java | 14 +++-
.../gabywald/crypto/blockchain/Wallet.java | 4 +-
8 files changed, 134 insertions(+), 64 deletions(-)
create mode 100644 src/main/java/gabywald/crypto/blockchain/BlockchainException.java
diff --git a/README.md b/README.md
index 0e5b8a2..ddd5df4 100644
--- a/README.md
+++ b/README.md
@@ -8,3 +8,4 @@ Quelques tests de programmation en Java, des notes diverses,
* Challenge CybserSec (quelques notes)
* Java Swing : Full Screen, SpalshScreen (à revoir / préciser)
* Java reflect / réflexivité / introspection
+ * "blockchain"
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 32a756c..93858ef 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -12,8 +12,10 @@ public class Block {
public String hash;
public String previousHash;
- private String data; //our data will be a simple message.
- private long timeStamp; //as number of milliseconds since 1/1/1970.
+ /** our data will be a simple message. */
+ private String data;
+ /** as number of milliseconds since 1/1/1970. */
+ private long timeStamp;
private int nonce;
/**
@@ -25,28 +27,39 @@ public Block(String data,String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
-
// Making sure we do this after we set the other values.
- this.hash = calculateHash();
+ this.hash = this.calculateHash();
}
- // Calculate new hash based on blocks contents
+ /**
+ * Calculate new hash based on blocks contents
+ * @return (null if exception apply internally).
+ * @see StringUtils#applySha256(String)
+ */
public String calculateHash() {
- String calculatedhash = StringUtils.applySha256(
- this.previousHash +
- Long.toString(this.timeStamp) +
- Integer.toString(this.nonce) +
- this.data
- );
+ String calculatedhash = null;
+ try {
+ calculatedhash = StringUtils.applySha256(
+ this.previousHash +
+ Long.toString(this.timeStamp) +
+ Integer.toString(this.nonce) +
+ this.data
+ );
+ } catch (BlockchainException e) {
+ // e.printStackTrace();
+ System.out.println( e.getMessage() );
+ calculatedhash = null;
+ }
return calculatedhash;
}
public void mineBlock(int difficulty) {
// Create a string with difficulty * "0"
String target = new String(new char[difficulty]).replace('\0', '0');
- while ( ! this.hash.substring( 0, difficulty).equals(target)) {
+ while ( (this.hash == null) || ( ! this.hash.substring( 0, difficulty ).equals(target)) ) {
this.nonce++;
this.hash = this.calculateHash();
+ // XXX NOTE if excpetion inside calculateHash : hash will be null !
}
System.out.println("Block Mined!!! : " + this.hash);
}
diff --git a/src/main/java/gabywald/crypto/blockchain/BlockchainException.java b/src/main/java/gabywald/crypto/blockchain/BlockchainException.java
new file mode 100644
index 0000000..52efef1
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/BlockchainException.java
@@ -0,0 +1,14 @@
+package gabywald.crypto.blockchain;
+
+/**
+ *
+ * @author Gabriel Chandesris (2021).
+ */
+@SuppressWarnings("serial")
+public class BlockchainException extends Exception {
+
+ public BlockchainException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index 3fd18c1..229113b 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -64,9 +64,9 @@ public static void main(String[] args) {
NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
System.out.println("Trying to Mine block 3... ");
- NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
+ NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
- System.out.println("\nBlockchain is Valid: " + isChainValid());
+ System.out.println("\nBlockchain is Valid: " + NoobChain.isChainValid());
String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
System.out.println("\nThe block chain: ");
@@ -100,9 +100,9 @@ public static Boolean isChainValid() {
Block previousBlock;
// Loop through blockchain to check hashes:
- for (int i = 1 ; i < NoobChain.blockchain.size() ; i++) {
- currentBlock = NoobChain.blockchain.get(i);
- previousBlock = NoobChain.blockchain.get(i-1);
+ for (int i = 1 ; i < NoobChain.blockchain2.size() ; i++) {
+ currentBlock = NoobChain.blockchain2.get(i);
+ previousBlock = NoobChain.blockchain2.get(i-1);
// Compare registered hash and calculated hash:
if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
System.out.println("Current Hashes not equal");
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index e6581eb..0842a05 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -1,10 +1,15 @@
package gabywald.crypto.blockchain;
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
+import java.security.SignatureException;
import java.util.List;
import java.util.ArrayList;
import java.util.Base64;
@@ -23,13 +28,17 @@ public class StringUtils {
* Applies Sha256 to a string and returns the result.
* @param input
* @return
+ * @throws BlockchainException
+ * TODO upgrade / improve this method (applySha256) to return null value if any exception inside !
*/
- public static String applySha256(String input){
+ public static String applySha256(String input)
+ throws BlockchainException {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Applies sha256 to our input,
- byte[] hash = digest.digest(input.getBytes("UTF-8"));
- StringBuffer hexString = new StringBuffer(); // This will contain hash as hexidecimal
+ byte[] hash = digest.digest(input.getBytes("UTF-8"));
+ // This will contain hash as hexidecimal
+ StringBuffer hexString = new StringBuffer();
for (int i = 0 ; i < hash.length ; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
if (hex.length() == 1) {
@@ -38,9 +47,10 @@ public static String applySha256(String input){
hexString.append(hex);
}
return hexString.toString();
- }
- catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new BlockchainException("StringUtils: NoSuchAlgorithmException: " + nsae.getMessage());
+ } catch (UnsupportedEncodingException uee) {
+ throw new BlockchainException("StringUtils: UnsupportedEncodingException: " + uee.getMessage());
}
}
@@ -58,20 +68,31 @@ public static String applySha256(String input){
* @param privateKey
* @param input
* @return
+ * @throws NoSuchProviderException
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeyException
+ * @throws SignatureException
*/
- public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
+ public static byte[] applyECDSASig(PrivateKey privateKey, String input)
+ throws BlockchainException {
Signature dsa;
byte[] output = new byte[0];
try {
dsa = Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
- // Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ // dsa = Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
dsa.initSign(privateKey);
byte[] strByte = input.getBytes();
dsa.update(strByte);
byte[] realSig = dsa.sign();
output = realSig;
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new BlockchainException("StringUtils: NoSuchAlgorithmException: " + nsae.getMessage());
+ } catch (NoSuchProviderException nspe) {
+ throw new BlockchainException("StringUtils: NoSuchProviderException: " + nspe.getMessage());
+ } catch (InvalidKeyException ike) {
+ throw new BlockchainException("StringUtils: InvalidKeyException: " + ike.getMessage());
+ } catch (SignatureException se) {
+ throw new BlockchainException("StringUtils: SignatureException: " + se.getMessage());
}
return output;
}
@@ -85,8 +106,8 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input) {
*/
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
- Signature ecdsaVerify = // Signature.getInstance(StringUtil.ECDSA, StringUtil.BC);
- Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ Signature ecdsaVerify = Signature.getInstance(StringUtils.ECDSA, StringUtils.BC);
+ // Signature ecdsaVerify = Signature.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(data.getBytes());
return ecdsaVerify.verify(signature);
@@ -107,14 +128,19 @@ public static String getStringFromKey(Key key) {
public static String getMerkleRoot(List transactions) {
int count = transactions.size();
List previousTreeLayer = new ArrayList();
- for(Transaction transaction : transactions) {
+ for (Transaction transaction : transactions) {
previousTreeLayer.add(transaction.transactionId);
}
List treeLayer = previousTreeLayer;
while (count > 1) {
treeLayer = new ArrayList();
for (int i = 1 ; i < previousTreeLayer.size() ; i++) {
- treeLayer.add(applySha256(previousTreeLayer.get(i-1) + previousTreeLayer.get(i)));
+ try {
+ treeLayer.add(StringUtils.applySha256(previousTreeLayer.get(i-1) + previousTreeLayer.get(i)));
+ } catch (BlockchainException e) {
+ // e.printStackTrace();
+ System.out.println( e.getMessage() );
+ }
}
count = treeLayer.size();
previousTreeLayer = treeLayer;
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index 3be892f..713ee42 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -40,17 +40,23 @@ public Transaction(PublicKey from, PublicKey to, float value, List ti.UTXO = NoobChain.UTXOs.get(ti.transactionOutputId) );
// Check if transaction is valid:
- if (getInputsValue() < NoobChain.minimumTransaction) {
+ if (this.getInputsValue() < NoobChain.minimumTransaction) {
System.out.println("#Transaction Inputs to small: " + getInputsValue());
return false;
}
// Generate transaction outputs:
- float leftOver = getInputsValue() - value; //
+ float leftOver = this.getInputsValue() - value; //
// - Get value of inputs then the left over change:
- transactionId = calulateHash();
+ this.transactionId = this.calculateHash();
// - Send value to recipient
- outputs.add(new TransactionOutput( this.reciepient, value, transactionId));
+ this.outputs.add(new TransactionOutput( this.reciepient, this.value, this.transactionId));
// - Send the left over 'change' back to sender
- outputs.add(new TransactionOutput( this.sender, leftOver ,transactionId));
+ this.outputs.add(new TransactionOutput( this.sender, leftOver, this.transactionId));
// Add outputs to Unspent list
- for (TransactionOutput o : outputs) {
- NoobChain.UTXOs.put(o.id , o);
- }
+ this.outputs.stream().forEach(to -> NoobChain.UTXOs.put(to.id , to) );
// Remove transaction inputs from UTXO lists as spent:
- for(TransactionInput i : inputs) {
+ this.inputs.stream().forEach(ti -> {
// If Transaction can't be found skip it
- if ( i.UTXO == null) { continue; }
- NoobChain.UTXOs.remove(i.UTXO.id);
- }
+ if ( ti.UTXO != null)
+ { NoobChain.UTXOs.remove(ti.UTXO.id); }
+ } );
return true;
}
@@ -173,10 +181,10 @@ public boolean processTransaction() {
*/
public float getInputsValue() {
float total = 0;
- for (TransactionInput i : inputs) {
+ for (TransactionInput ti : inputs) {
// If Transaction can't be found skip it
- if ( i.UTXO == null) { continue; }
- total += i.UTXO.value;
+ if ( ti.UTXO == null) { continue; }
+ total += ti.UTXO.value;
}
return total;
}
@@ -187,8 +195,8 @@ public float getInputsValue() {
*/
public float getOutputsValue() {
float total = 0;
- for (TransactionOutput o : outputs) {
- total += o.value;
+ for (TransactionOutput to : outputs) {
+ total += to.value;
}
return total;
}
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
index 95ab32f..ed10eed 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
@@ -27,8 +27,15 @@ public TransactionOutput(PublicKey reciepient, float value, String parentTransac
this.reciepient = reciepient;
this.value = value;
this.parentTransactionId = parentTransactionId;
- this.id = StringUtils.applySha256(StringUtils.getStringFromKey(reciepient)
- + Float.toString(value)+parentTransactionId);
+ try {
+ this.id = StringUtils.applySha256(StringUtils.getStringFromKey(reciepient)
+ + Float.toString(value) + parentTransactionId);
+ // TODO check alternatives for here when exception occurs !! (builder ?) : see StringUtils.applySha256 comment !
+ } catch (BlockchainException e) {
+ // e.printStackTrace();
+ System.out.println(e.getMessage());
+ this.id = null;
+ }
}
/**
@@ -37,7 +44,8 @@ public TransactionOutput(PublicKey reciepient, float value, String parentTransac
* @return
*/
public boolean isMine(PublicKey publicKey) {
- return (publicKey == reciepient);
+ return this.reciepient.equals(publicKey);
+ // return (publicKey == this.reciepient);
}
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index afba656..9695fbb 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -19,14 +19,14 @@ public class Wallet {
public PublicKey publicKey;
public Wallet() {
- generateKeyPair();
+ this.generateKeyPair();
}
public void generateKeyPair() {
try {
// TODO learning how security works here !
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(StringUtils.ECDSA, StringUtils.BC);
- // KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
+ // KeyPairGenerator keyGen = KeyPairGenerator.getInstance(StringUtils.CipherAlgorithm, StringUtils.CipherProvider);
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("prime192v1");
// Initialize the key generator and generate a KeyPair : 256 bytes provides an acceptable security level
From da394d69264b60f4590a348a02c20c25cada385a Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Wed, 13 Oct 2021 19:25:11 +0200
Subject: [PATCH 08/12] [blockchain]documentation link correction
---
src/main/java/gabywald/crypto/blockchain/NoobChain.java | 2 +-
src/main/java/gabywald/crypto/blockchain/StringUtils.java | 2 +-
src/main/java/gabywald/crypto/blockchain/Transaction.java | 2 +-
src/main/java/gabywald/crypto/blockchain/TransactionInput.java | 2 +-
src/main/java/gabywald/crypto/blockchain/TransactionOutput.java | 2 +-
src/main/java/gabywald/crypto/blockchain/Wallet.java | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index 229113b..e112a0e 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -13,7 +13,7 @@
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class NoobChain {
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 0842a05..eb53a02 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -19,7 +19,7 @@
*
https://medium.com/programmers-blockchain/create-simple-blockchain-java-tutorial-from-scratch-6eeed3cb03fa
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-1
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class StringUtils {
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index 713ee42..f472fc8 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -12,7 +12,7 @@
/**
* Transaction of BlockChain.
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class Transaction {
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionInput.java b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
index 16f7695..269c0be 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
@@ -3,7 +3,7 @@
/**
* TransactionInput of BlockChain.
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class TransactionInput {
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
index ed10eed..02271b6 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
@@ -5,7 +5,7 @@
/**
* TransactionOutput of BlockChain.
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class TransactionOutput {
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 9695fbb..705d2cd 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -10,7 +10,7 @@
/**
* Wallet of BlockChain.
*
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
- *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2/tree/master/src/noobchain
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
public class Wallet {
From c8480e6281dec92d0553650be70f778aca845745 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Wed, 13 Oct 2021 20:05:46 +0200
Subject: [PATCH 09/12] [blockchain]Finale adds (to check and tests)
---
.../gabywald/crypto/blockchain/Block.java | 46 ++++-
.../crypto/blockchain/NoobChainFinale.java | 169 ++++++++++++++++++
.../crypto/blockchain/StringUtils.java | 40 +++--
.../gabywald/crypto/blockchain/Wallet.java | 78 +++++++-
4 files changed, 303 insertions(+), 30 deletions(-)
create mode 100644 src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 93858ef..59b4824 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -1,6 +1,8 @@
package gabywald.crypto.blockchain;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
/**
* Block of BlockChain.
@@ -18,18 +20,30 @@ public class Block {
private long timeStamp;
private int nonce;
+ public String merkleRoot;
+ /** Our data will be a simple message. */
+ public List transactions = new ArrayList();
+
/**
* Block Constructor.
* @param data
* @param previousHash
*/
- public Block(String data,String previousHash ) {
+ public Block(String data, String previousHash ) {
this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
// Making sure we do this after we set the other values.
this.hash = this.calculateHash();
}
+
+ /**
+ * Block Constructor.
+ * @param previousHash
+ */
+ public Block(String previousHash ) {
+ this(null, previousHash);
+ }
/**
* Calculate new hash based on blocks contents
@@ -40,10 +54,10 @@ public String calculateHash() {
String calculatedhash = null;
try {
calculatedhash = StringUtils.applySha256(
- this.previousHash +
- Long.toString(this.timeStamp) +
- Integer.toString(this.nonce) +
- this.data
+ previousHash +
+ Long.toString(timeStamp) +
+ Integer.toString(nonce) +
+ merkleRoot
);
} catch (BlockchainException e) {
// e.printStackTrace();
@@ -54,8 +68,9 @@ public String calculateHash() {
}
public void mineBlock(int difficulty) {
+ this.merkleRoot = StringUtils.getMerkleRoot(this.transactions);
// Create a string with difficulty * "0"
- String target = new String(new char[difficulty]).replace('\0', '0');
+ String target = StringUtils.getDificultyString(difficulty);
while ( (this.hash == null) || ( ! this.hash.substring( 0, difficulty ).equals(target)) ) {
this.nonce++;
this.hash = this.calculateHash();
@@ -63,4 +78,23 @@ public void mineBlock(int difficulty) {
}
System.out.println("Block Mined!!! : " + this.hash);
}
+
+ /**
+ * Add transactions to this block.
+ * @param transaction
+ * @return
+ */
+ public boolean addTransaction(Transaction transaction) {
+ // Process transaction and check if valid, unless block is genesis block then ignore.
+ if (transaction == null) { return false; }
+ if (previousHash != "0") {
+ if (transaction.processTransaction() != true) {
+ System.out.println("Transaction failed to process. Discarded.");
+ return false;
+ }
+ }
+ transactions.add(transaction);
+ System.out.println("Transaction Successfully added to Block");
+ return true;
+ }
}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
new file mode 100644
index 0000000..1b65dde
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
@@ -0,0 +1,169 @@
+package gabywald.crypto.blockchain;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * NoobChain Test and Main Class of BlockChain.
+ *
https://medium.com/programmers-blockchain/creating-your-first-blockchain-with-java-part-2-transactions-2cdac335e0ce
+ *
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
+ * @author Gabriel Chandesris (2021)
+ */
+public class NoobChainFinale {
+
+ public static List blockchain = new ArrayList();
+ public static Map UTXOs = new HashMap();
+
+ public static int difficulty = 3;
+ public static float minimumTransaction = 0.1f;
+ public static Wallet walletA;
+ public static Wallet walletB;
+ public static Transaction genesisTransaction;
+
+ public static void main(String[] args) {
+ // Add our blocks to the blockchain List:
+
+ // Setup Bouncey castle as a Security Provider
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+ // Create wallets:
+ NoobChainFinale.walletA = new Wallet();
+ NoobChainFinale.walletB = new Wallet();
+ Wallet coinbase = new Wallet();
+
+ // Create genesis transaction, which sends 100 NoobCoin to walletA:
+ NoobChainFinale.genesisTransaction = new Transaction(coinbase.publicKey, NoobChainFinale.walletA.publicKey, 100f, null);
+ // Manually sign the genesis transaction
+ NoobChainFinale.genesisTransaction.generateSignature(coinbase.privateKey);
+ // Manually set the transaction id
+ NoobChainFinale.genesisTransaction.transactionId = "0";
+ // Manually add the Transactions Output
+ NoobChainFinale.genesisTransaction.outputs.add(new TransactionOutput( NoobChainFinale.genesisTransaction.reciepient,
+ NoobChainFinale.genesisTransaction.value,
+ NoobChainFinale.genesisTransaction.transactionId));
+
+ // Its important to store our first transaction in the UTXOs list.
+ UTXOs.put(NoobChainFinale.genesisTransaction.outputs.get(0).id, NoobChainFinale.genesisTransaction.outputs.get(0));
+
+ System.out.println("Creating and Mining Genesis block... ");
+ Block genesis = new Block("0");
+ genesis.addTransaction(NoobChainFinale.genesisTransaction);
+ NoobChainFinale.addBlock(genesis);
+
+ // Testing
+ Block block1 = new Block(genesis.hash);
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance());
+ System.out.println("\nWalletA is Attempting to send funds (40) to WalletB...");
+ block1.addTransaction(walletA.sendFunds(walletB.publicKey, 40f));
+ NoobChainFinale.addBlock(block1);
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance());
+ System.out.println("WalletB's balance is: " + walletB.getBalance());
+
+ Block block2 = new Block(block1.hash);
+ System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
+ block2.addTransaction(walletA.sendFunds(walletB.publicKey, 1000f));
+ NoobChainFinale.addBlock(block2);
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance());
+ System.out.println("WalletB's balance is: " + walletB.getBalance());
+
+ Block block3 = new Block(block2.hash);
+ System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
+ block3.addTransaction(walletB.sendFunds( walletA.publicKey, 20));
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance());
+ System.out.println("WalletB's balance is: " + walletB.getBalance());
+
+ NoobChainFinale.isChainValid();
+ }
+
+ public static Boolean isChainValid() {
+ Block currentBlock;
+ Block previousBlock;
+ String hashTarget = new String(new char[difficulty]).replace('\0', '0');
+
+ // A temporary working list of unspent transactions at a given block state.
+ HashMap tempUTXOs = new HashMap();
+ tempUTXOs.put(genesisTransaction.outputs.get(0).id, genesisTransaction.outputs.get(0));
+
+ // Loop through blockchain to check hashes:
+ for (int i = 1 ; i < NoobChainFinale.blockchain.size() ; i++) {
+
+ currentBlock = NoobChainFinale.blockchain.get(i);
+ previousBlock = NoobChainFinale.blockchain.get(i-1);
+
+ // Compare registered hash and calculated hash:
+ if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ System.out.println("#Current Hashes not equal");
+ return false;
+ }
+
+ // Compare previous hash and registered previous hash
+ if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ System.out.println("#Previous Hashes not equal");
+ return false;
+ }
+
+ // Check if hash is solved
+ if ( ! currentBlock.hash.substring( 0, NoobChainFinale.difficulty).equals(hashTarget)) {
+ System.out.println("#This block hasn't been mined");
+ return false;
+ }
+
+ // Loop thru blockchains transactions:
+ TransactionOutput tempOutput;
+ for (int t = 0 ; t < currentBlock.transactions.size() ; t++) {
+ Transaction currentTransaction = currentBlock.transactions.get(t);
+
+ if ( ! currentTransaction.verifiySignature()) {
+ System.out.println("#Signature on Transaction(" + t + ") is Invalid");
+ return false;
+ }
+
+ if (currentTransaction.getInputsValue() != currentTransaction.getOutputsValue()) {
+ System.out.println("#Inputs are note equal to outputs on Transaction(" + t + ")");
+ return false;
+ }
+
+ for (TransactionInput input: currentTransaction.inputs) {
+ tempOutput = tempUTXOs.get(input.transactionOutputId);
+
+ if (tempOutput == null) {
+ System.out.println("#Referenced input on Transaction(" + t + ") is Missing");
+ return false;
+ }
+
+ if (input.UTXO.value != tempOutput.value) {
+ System.out.println("#Referenced input Transaction(" + t + ") value is Invalid");
+ return false;
+ }
+
+ tempUTXOs.remove(input.transactionOutputId);
+ }
+
+ for (TransactionOutput output: currentTransaction.outputs) {
+ tempUTXOs.put(output.id, output);
+ }
+
+ if (currentTransaction.outputs.get(0).reciepient != currentTransaction.reciepient) {
+ System.out.println("#Transaction(" + t + ") output reciepient is not who it should be");
+ return false;
+ }
+ if (currentTransaction.outputs.get(1).reciepient != currentTransaction.sender) {
+ System.out.println("#Transaction(" + t + ") output 'change' is not sender.");
+ return false;
+ }
+
+ }
+
+ }
+ System.out.println("Blockchain is valid");
+ return true;
+ }
+
+ public static void addBlock(Block newBlock) {
+ newBlock.mineBlock(difficulty);
+ NoobChainFinale.blockchain.add(newBlock);
+ }
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index eb53a02..27ec9f9 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -37,7 +37,7 @@ public static String applySha256(String input)
MessageDigest digest = MessageDigest.getInstance("SHA-256");
// Applies sha256 to our input,
byte[] hash = digest.digest(input.getBytes("UTF-8"));
- // This will contain hash as hexidecimal
+ // This will contain hash as hexidecimal
StringBuffer hexString = new StringBuffer();
for (int i = 0 ; i < hash.length ; i++) {
String hex = Integer.toHexString(0xff & hash[i]);
@@ -47,18 +47,17 @@ public static String applySha256(String input)
hexString.append(hex);
}
return hexString.toString();
- } catch (NoSuchAlgorithmException nsae) {
- throw new BlockchainException("StringUtils: NoSuchAlgorithmException: " + nsae.getMessage());
- } catch (UnsupportedEncodingException uee) {
- throw new BlockchainException("StringUtils: UnsupportedEncodingException: " + uee.getMessage());
+ } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
+ System.out.println( "StringUtils: " + e.getClass().getName() + ": " + e.getMessage() );
+ throw new BlockchainException("StringUtils: " + e.getClass().getName() +": " + e.getMessage());
}
}
public static final String ECDSA = "ECDSA"; // CipherAlgorithm
public static final String BC = "BC"; // CipherProvider
-// public static final String CipherAlgorithm = "DiffieHellman"; // "SHA1withDSA";
-// public static final String CipherProvider = "SunJCE"; // "SUN";
+ // public static final String CipherAlgorithm = "DiffieHellman"; // "SHA1withDSA";
+ // public static final String CipherProvider = "SunJCE"; // "SUN";
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
// TODO learning how security works here !
@@ -85,14 +84,9 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input)
dsa.update(strByte);
byte[] realSig = dsa.sign();
output = realSig;
- } catch (NoSuchAlgorithmException nsae) {
- throw new BlockchainException("StringUtils: NoSuchAlgorithmException: " + nsae.getMessage());
- } catch (NoSuchProviderException nspe) {
- throw new BlockchainException("StringUtils: NoSuchProviderException: " + nspe.getMessage());
- } catch (InvalidKeyException ike) {
- throw new BlockchainException("StringUtils: InvalidKeyException: " + ike.getMessage());
- } catch (SignatureException se) {
- throw new BlockchainException("StringUtils: SignatureException: " + se.getMessage());
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException | SignatureException e) {
+ System.out.println( "StringUtils: " + e.getClass().getName() + ": " + e.getMessage() );
+ throw new BlockchainException("StringUtils: " + e.getClass().getName() + ": " + e.getMessage());
}
return output;
}
@@ -111,14 +105,25 @@ public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] si
ecdsaVerify.initVerify(publicKey);
ecdsaVerify.update(data.getBytes());
return ecdsaVerify.verify(signature);
- } catch(Exception e) {
- throw new RuntimeException(e);
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeyException | SignatureException e) {
+ // throw new BlockchainException("StringUtils: " + e.getClass().getName() + ": " + e.getMessage());
+ System.out.println( "StringUtils: " + e.getClass().getName() + ": " + e.getMessage() );
}
+ return false; // if any Exception is throwed !
}
public static String getStringFromKey(Key key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
+
+ /**
+ * Returns difficulty string target, to compare to hash. eg difficulty of 5 will return "00000"
+ * @param difficulty
+ * @return
+ */
+ public static String getDificultyString(int difficulty) {
+ return new String(new char[difficulty]).replace('\0', '0');
+ }
/**
* Tacks in array of transactions and returns a merkle root.
@@ -138,7 +143,6 @@ public static String getMerkleRoot(List transactions) {
try {
treeLayer.add(StringUtils.applySha256(previousTreeLayer.get(i-1) + previousTreeLayer.get(i)));
} catch (BlockchainException e) {
- // e.printStackTrace();
System.out.println( e.getMessage() );
}
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 705d2cd..43a57d4 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -1,11 +1,17 @@
package gabywald.crypto.blockchain;
+import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
/**
* Wallet of BlockChain.
@@ -15,13 +21,16 @@
*/
public class Wallet {
- public PrivateKey privateKey;
- public PublicKey publicKey;
+ public PrivateKey privateKey = null;
+ public PublicKey publicKey = null;
public Wallet() {
this.generateKeyPair();
}
+ /**
+ * Generate some KeyPair (Public and Private).
+ */
public void generateKeyPair() {
try {
// TODO learning how security works here !
@@ -33,11 +42,68 @@ public void generateKeyPair() {
keyGen.initialize(ecSpec, random);
KeyPair keyPair = keyGen.generateKeyPair();
// Set the public and private keys from the keyPair
- privateKey = keyPair.getPrivate();
- publicKey = keyPair.getPublic();
- } catch (Exception e) {
- throw new RuntimeException(e);
+ this.privateKey = keyPair.getPrivate();
+ this.publicKey = keyPair.getPublic();
+ } catch (NoSuchAlgorithmException nsae) {
+ // throw new BlockchainException("StringUtils: NoSuchAlgorithmException: " + nsae.getMessage());
+ System.out.println( "StringUtils: NoSuchAlgorithmException: " + nsae.getMessage() );
+ } catch (NoSuchProviderException nspe) {
+ // throw new BlockchainException("StringUtils: NoSuchProviderException: " + nspe.getMessage());
+ System.out.println( "StringUtils: NoSuchProviderException: " + nspe.getMessage() );
+ } catch (InvalidAlgorithmParameterException iape) {
+ // throw new BlockchainException("StringUtils: InvalidAlgorithmParameterException: " + iape.getMessage());
+ System.out.println( "StringUtils: InvalidAlgorithmParameterException: " + iape.getMessage() );
+ }
+ }
+
+ /**
+ * Returns balance and stores the UTXO's owned by this wallet in this.UTXOs
+ * @return
+ */
+ public float getBalance() {
+ float total = 0;
+ for (Map.Entry item: NoobChainFinale.UTXOs.entrySet()){
+ TransactionOutput UTXO = item.getValue();
+ if (UTXO.isMine(publicKey)) {
+ // If output belongs to me ( if coins belong to me )
+ // Add it to our list of unspent transactions.
+ NoobChainFinale.UTXOs.put(UTXO.id,UTXO);
+ total += UTXO.value ;
+ }
+ }
+ return total;
+ }
+
+ /**
+ * Generates and returns a new transaction from this wallet.
+ * @param recipient
+ * @param value
+ * @return
+ */
+ public Transaction sendFunds(PublicKey recipient, float value) {
+ // Gather balance and check funds.
+ if (this.getBalance() < value) {
+ System.out.println("#Not Enough funds to send transaction. Transaction Discarded.");
+ return null;
+ }
+ // Create array list of inputs
+ List inputs = new ArrayList();
+
+ float total = 0;
+ for (Map.Entry item: NoobChainFinale.UTXOs.entrySet()){
+ TransactionOutput UTXO = item.getValue();
+ total += UTXO.value;
+ inputs.add(new TransactionInput(UTXO.id));
+ if (total > value) { break; }
+ }
+
+ Transaction newTransaction = new Transaction(this.publicKey, recipient , value, inputs);
+ newTransaction.generateSignature(this.privateKey);
+
+ for (TransactionInput input: inputs) {
+ NoobChainFinale.UTXOs.remove(input.transactionOutputId);
}
+ return newTransaction;
}
}
From 67e8ebf977ea637206fa2ac76f53ab19b7d6927d Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Wed, 13 Oct 2021 23:27:38 +0200
Subject: [PATCH 10/12] [blockchain]Review, corrections, Unit Tests
---
.classpath | 1 +
src/main/java/NoobChainTests.java | 127 ++++++++++++
.../gabywald/crypto/blockchain/Block.java | 23 ++-
.../crypto/blockchain/BlockChain.java | 127 ++++++++++++
.../gabywald/crypto/blockchain/NoobChain.java | 64 ++----
.../crypto/blockchain/NoobChainFinale.java | 147 +++-----------
.../crypto/blockchain/NoobChainTests.java | 192 ++++++++++++++++++
.../crypto/blockchain/StringUtils.java | 2 +-
.../crypto/blockchain/Transaction.java | 72 +++++--
.../gabywald/crypto/blockchain/Wallet.java | 22 +-
10 files changed, 572 insertions(+), 205 deletions(-)
create mode 100644 src/main/java/NoobChainTests.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/BlockChain.java
create mode 100644 src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
diff --git a/.classpath b/.classpath
index 1114cb5..3138ed5 100644
--- a/.classpath
+++ b/.classpath
@@ -29,5 +29,6 @@
+
diff --git a/src/main/java/NoobChainTests.java b/src/main/java/NoobChainTests.java
new file mode 100644
index 0000000..c396855
--- /dev/null
+++ b/src/main/java/NoobChainTests.java
@@ -0,0 +1,127 @@
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.google.gson.GsonBuilder;
+
+import gabywald.crypto.blockchain.Block;
+import gabywald.crypto.blockchain.BlockChain;
+import gabywald.crypto.blockchain.StringUtils;
+import gabywald.crypto.blockchain.Transaction;
+import gabywald.crypto.blockchain.Wallet;
+
+/**
+ * Tests about BlockChain / NoobChain.
+ * @author Gabriel Chandesris (2021)
+ */
+class NoobChainTests {
+
+ /**
+ * Test : block.
+ */
+ @Test
+ void testPart01() {
+ Block genesisBlock = new Block("Hi im the first block", "0");
+ Assertions.assertNotNull( genesisBlock );
+ System.out.println("Hash for block 1 : " + genesisBlock.hash);
+ Assertions.assertNotNull( genesisBlock.hash );
+
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
+ Assertions.assertNotNull( secondBlock );
+ System.out.println("Hash for block 2 : " + secondBlock.hash);
+ Assertions.assertNotNull( secondBlock.hash );
+
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
+ Assertions.assertNotNull( thirdBlock );
+ System.out.println("Hash for block 3 : " + thirdBlock.hash);
+ Assertions.assertNotNull( thirdBlock.hash );
+ }
+
+ /**
+ * Test : blockchain
+ */
+ @Test
+ void testPart02() {
+ List blockchain = new ArrayList();
+ // Add our blocks to the blockchain List:
+ blockchain.add(new Block("Hi im the first block", "0"));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ Assertions.assertEquals(3, blockchain.size());
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
+ Assertions.assertNotNull( blockchainJson );
+ System.out.println(blockchainJson);
+ }
+
+ @Test
+ void testPart03() {
+ List blockchain = new ArrayList();
+ int difficulty = 3;
+ // Add our blocks to the blockchain List:
+ blockchain.add(new Block("Hi im the first block", "0"));
+ System.out.println("Trying to Mine block 1... ");
+ blockchain.get(0).mineBlock(difficulty);
+
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ System.out.println("Trying to Mine block 2... ");
+ blockchain.get(1).mineBlock(difficulty);
+
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ System.out.println("Trying to Mine block 3... ");
+ blockchain.get(2).mineBlock(difficulty);
+
+ Assertions.assertEquals(3, blockchain.size());
+
+ System.out.println("\nBlockchain is Valid: " + BlockChain.isChainValidV1( blockchain ));
+
+ Assertions.assertTrue( BlockChain.isChainValidV1( blockchain ) );
+
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
+
+ Assertions.assertNotNull( blockchainJson );
+
+ System.out.println("\nThe block chain: ");
+ System.out.println(blockchainJson);
+ }
+
+ @Test
+ void testPart04() {
+ // Setup Bouncey castle as a Security Provider
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ // Security.addProvider(new sun.security.provider.Sun());
+ // XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+ // Create the new wallets
+ Wallet walletA = new Wallet();
+ Wallet walletB = new Wallet();
+ Assertions.assertNotNull( walletA );
+ Assertions.assertNotNull( walletB );
+ // Test public and private keys
+ System.out.println("Private and public keys:");
+ System.out.println(StringUtils.getStringFromKey(walletA.privateKey));
+ System.out.println(StringUtils.getStringFromKey(walletA.publicKey));
+ Assertions.assertNotNull( walletA.privateKey );
+ Assertions.assertNotNull( walletA.publicKey );
+ Assertions.assertNotNull( walletB.privateKey );
+ Assertions.assertNotNull( walletB.publicKey );
+ //Create a test transaction from WalletA to walletB
+ Transaction transaction = new Transaction(walletA.publicKey, walletB.publicKey, 5, null);
+ Assertions.assertNotNull( transaction );
+ transaction.generateSignature(walletA.privateKey);
+ Assertions.assertNotNull( walletA.privateKey );
+ //Verify the signature works and verify it from the public key
+ System.out.println("Is signature verified");
+ System.out.println(transaction.verifySignature());
+ Assertions.assertTrue( transaction.verifySignature() );
+ }
+
+ @Test
+ void testPart05() {
+ fail("Not yet implemented");
+ }
+
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 59b4824..746a8ca 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
+import java.util.Map;
/**
* Block of BlockChain.
@@ -14,9 +15,9 @@ public class Block {
public String hash;
public String previousHash;
- /** our data will be a simple message. */
- private String data;
- /** as number of milliseconds since 1/1/1970. */
+ /** Our data will be a simple message. */
+ // private String data;
+ /** As number of milliseconds since 1/1/1970. */
private long timeStamp;
private int nonce;
@@ -30,7 +31,7 @@ public class Block {
* @param previousHash
*/
public Block(String data, String previousHash ) {
- this.data = data;
+ // this.data = data;
this.previousHash = previousHash;
this.timeStamp = new Date().getTime();
// Making sure we do this after we set the other values.
@@ -74,7 +75,7 @@ public void mineBlock(int difficulty) {
while ( (this.hash == null) || ( ! this.hash.substring( 0, difficulty ).equals(target)) ) {
this.nonce++;
this.hash = this.calculateHash();
- // XXX NOTE if excpetion inside calculateHash : hash will be null !
+ // XXX NOTE if exception inside calculateHash : hash will be null !
}
System.out.println("Block Mined!!! : " + this.hash);
}
@@ -82,18 +83,22 @@ public void mineBlock(int difficulty) {
/**
* Add transactions to this block.
* @param transaction
+ * @param UTXOs
+ * @param minimumTransaction
* @return
*/
- public boolean addTransaction(Transaction transaction) {
+ public boolean addTransaction( final Transaction transaction,
+ final Map UTXOs,
+ final float minimumTransaction) {
// Process transaction and check if valid, unless block is genesis block then ignore.
if (transaction == null) { return false; }
- if (previousHash != "0") {
- if (transaction.processTransaction() != true) {
+ if (this.previousHash != "0") {
+ if (transaction.processTransaction(UTXOs, minimumTransaction) != true) {
System.out.println("Transaction failed to process. Discarded.");
return false;
}
}
- transactions.add(transaction);
+ this.transactions.add(transaction);
System.out.println("Transaction Successfully added to Block");
return true;
}
diff --git a/src/main/java/gabywald/crypto/blockchain/BlockChain.java b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
new file mode 100644
index 0000000..0ff2869
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
@@ -0,0 +1,127 @@
+package gabywald.crypto.blockchain;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ *
+ * @author Gabriel Chandesris (2021)
+ */
+public abstract class BlockChain {
+
+ public static List build() {
+ return new ArrayList();
+ }
+
+ public static Boolean isChainValidV1(List blockchain) {
+ Block currentBlock;
+ Block previousBlock;
+
+ // Loop through blockchain to check hashes:
+ for (int i = 1 ; i < blockchain.size() ; i++) {
+ currentBlock = blockchain.get(i);
+ previousBlock = blockchain.get(i-1);
+ // Compare registered hash and calculated hash:
+ if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ System.out.println("Current Hashes not equal");
+ return false;
+ }
+ // Compare previous hash and registered previous hash
+ if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ System.out.println("Previous Hashes not equal");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isChainValidV2(List blockchain, Transaction genesisTransaction, int difficulty) {
+ Block currentBlock = null;
+ Block previousBlock = null;
+ String hashTarget = new String(new char[difficulty]).replace('\0', '0');
+
+ // A temporary working list of unspent transactions at a given block state.
+ HashMap tempUTXOs = new HashMap();
+ tempUTXOs.put(genesisTransaction.getOutputs().get(0).id, genesisTransaction.getOutputs().get(0));
+
+ // Loop through blockchain to check hashes:
+ for (int i = 1 ; i < blockchain.size() ; i++) {
+
+ currentBlock = blockchain.get(i);
+ previousBlock = blockchain.get(i-1);
+
+ // Compare registered hash and calculated hash:
+ if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ System.out.println("#Current Hashes not equal");
+ return false;
+ }
+
+ // Compare previous hash and registered previous hash
+ if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ System.out.println("#Previous Hashes not equal");
+ return false;
+ }
+
+ // Check if hash is solved
+ if ( ! currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
+ System.out.println("#This block hasn't been mined");
+ return false;
+ }
+
+ // Loop thru blockchains transactions:
+ TransactionOutput tempOutput;
+ for (int t = 0 ; t < currentBlock.transactions.size() ; t++) {
+ Transaction currentTransaction = currentBlock.transactions.get(t);
+
+ if ( ! currentTransaction.verifySignature()) {
+ System.out.println("#Signature on Transaction(" + t + ") is Invalid");
+ return false;
+ }
+
+ if (currentTransaction.getInputsValue() != currentTransaction.getOutputsValue()) {
+ System.out.println("#Inputs are note equal to outputs on Transaction(" + t + ")");
+ return false;
+ }
+
+ for (TransactionInput input: currentTransaction.getInputs()) {
+ tempOutput = tempUTXOs.get(input.transactionOutputId);
+
+ if (tempOutput == null) {
+ System.out.println("#Referenced input on Transaction(" + t + ") is Missing");
+ return false;
+ }
+
+ if (input.UTXO.value != tempOutput.value) {
+ System.out.println("#Referenced input Transaction(" + t + ") value is Invalid");
+ return false;
+ }
+
+ tempUTXOs.remove(input.transactionOutputId);
+ }
+
+ for (TransactionOutput output: currentTransaction.getOutputs()) {
+ tempUTXOs.put(output.id, output);
+ }
+
+ if (currentTransaction.getOutputs().get(0).reciepient != currentTransaction.getRecipient()) {
+ System.out.println("#Transaction(" + t + ") output reciepient is not who it should be");
+ return false;
+ }
+ if (currentTransaction.getOutputs().get(1).reciepient != currentTransaction.getSender()) {
+ System.out.println("#Transaction(" + t + ") output 'change' is not sender.");
+ return false;
+ }
+
+ }
+
+ }
+ System.out.println("Blockchain is valid");
+ return true;
+ }
+
+ public static boolean addBlock(final List blockchain, final Block newBlock, final int difficulty) {
+ newBlock.mineBlock(difficulty);
+ return blockchain.add(newBlock);
+ }
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
index e112a0e..cb7e90c 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChain.java
@@ -3,7 +3,6 @@
import java.security.Security;
import java.util.List;
import java.util.ArrayList;
-import java.util.HashMap;
// TODO replace GsonBuilder !! (build json from objet !)
import com.google.gson.GsonBuilder;
@@ -18,29 +17,22 @@
*/
public class NoobChain {
- public static List blockchain = new ArrayList();
- public static List blockchain2 = new ArrayList();
- public static List blockchain3 = new ArrayList();
+ private static List blockchain = new ArrayList();
+ private static List blockchain2 = new ArrayList();
- public static int difficulty = 3;
+ private static int difficulty = 3;
- public static Wallet walletA;
- public static Wallet walletB;
+ private static Wallet walletA;
+ private static Wallet walletB;
- // List of all unspent transactions.
- public static HashMap UTXOs = new HashMap();
-
- public static float minimumTransaction = 0.1f;
- public static Transaction genesisTransaction;
-
public static void main(String[] args) {
// ***** Part I
Block genesisBlock = new Block("Hi im the first block", "0");
System.out.println("Hash for block 1 : " + genesisBlock.hash);
- Block secondBlock = new Block("Yo im the second block",genesisBlock.hash);
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
System.out.println("Hash for block 2 : " + secondBlock.hash);
- Block thirdBlock = new Block("Hey im the third block",secondBlock.hash);
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
System.out.println("Hash for block 3 : " + thirdBlock.hash);
@@ -66,7 +58,7 @@ public static void main(String[] args) {
System.out.println("Trying to Mine block 3... ");
NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
- System.out.println("\nBlockchain is Valid: " + NoobChain.isChainValid());
+ System.out.println("\nBlockchain is Valid: " + BlockChain.isChainValidV1( NoobChain.blockchain2 ));
String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
System.out.println("\nThe block chain: ");
@@ -77,46 +69,24 @@ public static void main(String[] args) {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Security.addProvider(new sun.security.provider.Sun());
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
- //Create the new wallets
- walletA = new Wallet();
- walletB = new Wallet();
- //Test public and private keys
+ // Create the new wallets
+ NoobChain.walletA = new Wallet();
+ NoobChain.walletB = new Wallet();
+ // Test public and private keys
System.out.println("Private and public keys:");
- System.out.println(StringUtils.getStringFromKey(walletA.privateKey));
- System.out.println(StringUtils.getStringFromKey(walletA.publicKey));
- //Create a test transaction from WalletA to walletB
+ System.out.println(StringUtils.getStringFromKey(NoobChain.walletA.privateKey));
+ System.out.println(StringUtils.getStringFromKey(NoobChain.walletA.publicKey));
+ // Create a test transaction from WalletA to walletB
Transaction transaction = new Transaction(NoobChain.walletA.publicKey, NoobChain.walletB.publicKey, 5, null);
transaction.generateSignature(NoobChain.walletA.privateKey);
- //Verify the signature works and verify it from the public key
+ // Verify the signature works and verify it from the public key
System.out.println("Is signature verified");
- System.out.println(transaction.verifiySignature());
+ System.out.println(transaction.verifySignature());
// ***** Part V
// TODO next step of tutorials !!
}
- public static Boolean isChainValid() {
- Block currentBlock;
- Block previousBlock;
-
- // Loop through blockchain to check hashes:
- for (int i = 1 ; i < NoobChain.blockchain2.size() ; i++) {
- currentBlock = NoobChain.blockchain2.get(i);
- previousBlock = NoobChain.blockchain2.get(i-1);
- // Compare registered hash and calculated hash:
- if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
- System.out.println("Current Hashes not equal");
- return false;
- }
- // Compare previous hash and registered previous hash
- if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
- System.out.println("Previous Hashes not equal");
- return false;
- }
- }
- return true;
- }
-
/*
Hash for block 1 : 9f98b14417f65bf7f55053d6ee948de264beaf4f4effdf1be1b80adb939a56bb
Hash for block 2 : e7571024da930e1fee1dad719e0b8eeeefdf80c70a3a3739d83d9de1e23eced8
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
index 1b65dde..cbf8ef2 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
@@ -14,19 +14,19 @@
*/
public class NoobChainFinale {
- public static List blockchain = new ArrayList();
- public static Map UTXOs = new HashMap();
+ private static List blockchain = new ArrayList();
+ private static Map mapUTXOs = new HashMap();
- public static int difficulty = 3;
- public static float minimumTransaction = 0.1f;
- public static Wallet walletA;
- public static Wallet walletB;
- public static Transaction genesisTransaction;
+ private static int difficulty = 3;
+ private static float minimumTransaction = 0.1f;
+ private static Wallet walletA;
+ private static Wallet walletB;
+ private static Transaction genesisTransaction;
public static void main(String[] args) {
// Add our blocks to the blockchain List:
- // Setup Bouncey castle as a Security Provider
+ // Setup Bouncey castle as a Security Provider
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Create wallets:
@@ -39,131 +39,46 @@ public static void main(String[] args) {
// Manually sign the genesis transaction
NoobChainFinale.genesisTransaction.generateSignature(coinbase.privateKey);
// Manually set the transaction id
- NoobChainFinale.genesisTransaction.transactionId = "0";
+ NoobChainFinale.genesisTransaction.setTransactionId( "0" );
// Manually add the Transactions Output
- NoobChainFinale.genesisTransaction.outputs.add(new TransactionOutput( NoobChainFinale.genesisTransaction.reciepient,
- NoobChainFinale.genesisTransaction.value,
- NoobChainFinale.genesisTransaction.transactionId));
+ NoobChainFinale.genesisTransaction.getOutputs().add(new TransactionOutput( NoobChainFinale.genesisTransaction.getRecipient(),
+ NoobChainFinale.genesisTransaction.getValue(),
+ NoobChainFinale.genesisTransaction.getTransactionId()));
// Its important to store our first transaction in the UTXOs list.
- UTXOs.put(NoobChainFinale.genesisTransaction.outputs.get(0).id, NoobChainFinale.genesisTransaction.outputs.get(0));
+ NoobChainFinale.mapUTXOs.put(NoobChainFinale.genesisTransaction.getOutputs().get(0).id, NoobChainFinale.genesisTransaction.getOutputs().get(0));
System.out.println("Creating and Mining Genesis block... ");
Block genesis = new Block("0");
- genesis.addTransaction(NoobChainFinale.genesisTransaction);
- NoobChainFinale.addBlock(genesis);
+ genesis.addTransaction(NoobChainFinale.genesisTransaction, NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
+ BlockChain.addBlock(NoobChainFinale.blockchain, genesis, NoobChainFinale.difficulty);
// Testing
Block block1 = new Block(genesis.hash);
- System.out.println("\nWalletA's balance is: " + walletA.getBalance());
+ System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
System.out.println("\nWalletA is Attempting to send funds (40) to WalletB...");
- block1.addTransaction(walletA.sendFunds(walletB.publicKey, 40f));
- NoobChainFinale.addBlock(block1);
- System.out.println("\nWalletA's balance is: " + walletA.getBalance());
- System.out.println("WalletB's balance is: " + walletB.getBalance());
+ block1.addTransaction( NoobChainFinale.walletA.sendFunds(NoobChainFinale.walletB.publicKey, 40f, NoobChainFinale.mapUTXOs),
+ NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
+ BlockChain.addBlock(NoobChainFinale.blockchain, block1, NoobChainFinale.difficulty);
+ System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
+ System.out.println("WalletB's balance is: " + NoobChainFinale.walletB.getBalance( NoobChainFinale.mapUTXOs ));
Block block2 = new Block(block1.hash);
System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
- block2.addTransaction(walletA.sendFunds(walletB.publicKey, 1000f));
- NoobChainFinale.addBlock(block2);
- System.out.println("\nWalletA's balance is: " + walletA.getBalance());
- System.out.println("WalletB's balance is: " + walletB.getBalance());
+ block2.addTransaction( NoobChainFinale.walletA.sendFunds(NoobChainFinale.walletB.publicKey, 1000f, NoobChainFinale.mapUTXOs),
+ NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
+ BlockChain.addBlock(NoobChainFinale.blockchain, block2, NoobChainFinale.difficulty);
+ System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
+ System.out.println("WalletB's balance is: " + NoobChainFinale.walletB.getBalance( NoobChainFinale.mapUTXOs ));
Block block3 = new Block(block2.hash);
System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
- block3.addTransaction(walletB.sendFunds( walletA.publicKey, 20));
- System.out.println("\nWalletA's balance is: " + walletA.getBalance());
- System.out.println("WalletB's balance is: " + walletB.getBalance());
+ block3.addTransaction( NoobChainFinale.walletB.sendFunds( NoobChainFinale.walletA.publicKey, 20, NoobChainFinale.mapUTXOs),
+ NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
+ System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
+ System.out.println("WalletB's balance is: " + NoobChainFinale.walletB.getBalance( NoobChainFinale.mapUTXOs ));
- NoobChainFinale.isChainValid();
+ BlockChain.isChainValidV2( NoobChainFinale.blockchain, NoobChainFinale.genesisTransaction, NoobChainFinale.difficulty );
}
- public static Boolean isChainValid() {
- Block currentBlock;
- Block previousBlock;
- String hashTarget = new String(new char[difficulty]).replace('\0', '0');
-
- // A temporary working list of unspent transactions at a given block state.
- HashMap tempUTXOs = new HashMap();
- tempUTXOs.put(genesisTransaction.outputs.get(0).id, genesisTransaction.outputs.get(0));
-
- // Loop through blockchain to check hashes:
- for (int i = 1 ; i < NoobChainFinale.blockchain.size() ; i++) {
-
- currentBlock = NoobChainFinale.blockchain.get(i);
- previousBlock = NoobChainFinale.blockchain.get(i-1);
-
- // Compare registered hash and calculated hash:
- if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
- System.out.println("#Current Hashes not equal");
- return false;
- }
-
- // Compare previous hash and registered previous hash
- if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
- System.out.println("#Previous Hashes not equal");
- return false;
- }
-
- // Check if hash is solved
- if ( ! currentBlock.hash.substring( 0, NoobChainFinale.difficulty).equals(hashTarget)) {
- System.out.println("#This block hasn't been mined");
- return false;
- }
-
- // Loop thru blockchains transactions:
- TransactionOutput tempOutput;
- for (int t = 0 ; t < currentBlock.transactions.size() ; t++) {
- Transaction currentTransaction = currentBlock.transactions.get(t);
-
- if ( ! currentTransaction.verifiySignature()) {
- System.out.println("#Signature on Transaction(" + t + ") is Invalid");
- return false;
- }
-
- if (currentTransaction.getInputsValue() != currentTransaction.getOutputsValue()) {
- System.out.println("#Inputs are note equal to outputs on Transaction(" + t + ")");
- return false;
- }
-
- for (TransactionInput input: currentTransaction.inputs) {
- tempOutput = tempUTXOs.get(input.transactionOutputId);
-
- if (tempOutput == null) {
- System.out.println("#Referenced input on Transaction(" + t + ") is Missing");
- return false;
- }
-
- if (input.UTXO.value != tempOutput.value) {
- System.out.println("#Referenced input Transaction(" + t + ") value is Invalid");
- return false;
- }
-
- tempUTXOs.remove(input.transactionOutputId);
- }
-
- for (TransactionOutput output: currentTransaction.outputs) {
- tempUTXOs.put(output.id, output);
- }
-
- if (currentTransaction.outputs.get(0).reciepient != currentTransaction.reciepient) {
- System.out.println("#Transaction(" + t + ") output reciepient is not who it should be");
- return false;
- }
- if (currentTransaction.outputs.get(1).reciepient != currentTransaction.sender) {
- System.out.println("#Transaction(" + t + ") output 'change' is not sender.");
- return false;
- }
-
- }
-
- }
- System.out.println("Blockchain is valid");
- return true;
- }
-
- public static void addBlock(Block newBlock) {
- newBlock.mineBlock(difficulty);
- NoobChainFinale.blockchain.add(newBlock);
- }
}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
new file mode 100644
index 0000000..4fefa0d
--- /dev/null
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
@@ -0,0 +1,192 @@
+package gabywald.crypto.blockchain;
+
+import java.security.Security;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import com.google.gson.GsonBuilder;
+
+/**
+ * Tests about BlockChain / NoobChain.
+ * @author Gabriel Chandesris (2021)
+ */
+class NoobChainTests {
+
+ /**
+ * Test : block.
+ */
+ @Test
+ void testPart01() {
+ Block genesisBlock = new Block("Hi im the first block", "0");
+ Assertions.assertNotNull( genesisBlock );
+ System.out.println("Hash for block 1 : " + genesisBlock.hash);
+ Assertions.assertNotNull( genesisBlock.hash );
+
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
+ Assertions.assertNotNull( secondBlock );
+ System.out.println("Hash for block 2 : " + secondBlock.hash);
+ Assertions.assertNotNull( secondBlock.hash );
+
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
+ Assertions.assertNotNull( thirdBlock );
+ System.out.println("Hash for block 3 : " + thirdBlock.hash);
+ Assertions.assertNotNull( thirdBlock.hash );
+ }
+
+ /**
+ * Test : blockchain
+ */
+ @Test
+ void testPart02() {
+ List blockchain = BlockChain.build();
+ // Add our blocks to the blockchain List:
+ blockchain.add(new Block("Hi im the first block", "0"));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ Assertions.assertEquals(3, blockchain.size());
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
+ Assertions.assertNotNull( blockchainJson );
+ System.out.println(blockchainJson);
+ }
+
+ @Test
+ void testPart03() {
+ List blockchain = BlockChain.build();
+ int difficulty = 3;
+ // Add our blocks to the blockchain List:
+ blockchain.add(new Block("Hi im the first block", "0"));
+ System.out.println("Trying to Mine block 1... ");
+ blockchain.get(0).mineBlock(difficulty);
+
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ System.out.println("Trying to Mine block 2... ");
+ blockchain.get(1).mineBlock(difficulty);
+
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ System.out.println("Trying to Mine block 3... ");
+ blockchain.get(2).mineBlock(difficulty);
+
+ Assertions.assertEquals(3, blockchain.size());
+
+ System.out.println("\nBlockchain is Valid: " + BlockChain.isChainValidV1( blockchain ));
+
+ Assertions.assertTrue( BlockChain.isChainValidV1( blockchain ) );
+
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
+
+ Assertions.assertNotNull( blockchainJson );
+
+ System.out.println("\nThe block chain: ");
+ System.out.println(blockchainJson);
+ }
+
+ @Test
+ void testPart04() {
+ // Setup Bouncey castle as a Security Provider
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ // Security.addProvider(new sun.security.provider.Sun());
+ // XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
+ // Create the new wallets
+ Wallet walletA = new Wallet();
+ Wallet walletB = new Wallet();
+ Assertions.assertNotNull( walletA );
+ Assertions.assertNotNull( walletB );
+ // Test public and private keys
+ System.out.println("Private and public keys:");
+ System.out.println(StringUtils.getStringFromKey(walletA.privateKey));
+ System.out.println(StringUtils.getStringFromKey(walletA.publicKey));
+ Assertions.assertNotNull( walletA.privateKey );
+ Assertions.assertNotNull( walletA.publicKey );
+ Assertions.assertNotNull( walletB.privateKey );
+ Assertions.assertNotNull( walletB.publicKey );
+ //Create a test transaction from WalletA to walletB
+ Transaction transaction = new Transaction(walletA.publicKey, walletB.publicKey, 5, null);
+ Assertions.assertNotNull( transaction );
+ transaction.generateSignature(walletA.privateKey);
+ Assertions.assertNotNull( walletA.privateKey );
+ //Verify the signature works and verify it from the public key
+ System.out.println("Is signature verified");
+ System.out.println(transaction.verifySignature());
+ Assertions.assertTrue( transaction.verifySignature() );
+ }
+
+ @Test
+ void testPart05() {
+
+ List blockchain = BlockChain.build();
+
+ Map mapUTXOs = new HashMap();
+
+ int difficulty = 3;
+ float minimumTransaction = 0.1f;
+
+ // Setup Bouncey castle as a Security Provider
+ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+ // Create wallets:
+ Wallet walletA = new Wallet();
+ Wallet walletB = new Wallet();
+ Wallet coinbase = new Wallet();
+
+ // Create genesis transaction, which sends 100 NoobCoin to walletA:
+ Transaction genesisTransaction = new Transaction(coinbase.publicKey, walletA.publicKey, 100f, null);
+ // Manually sign the genesis transaction
+ genesisTransaction.generateSignature(coinbase.privateKey);
+ // Manually set the transaction id
+ genesisTransaction.setTransactionId( "0" );
+ // Manually add the Transactions Output
+ genesisTransaction.getOutputs().add(new TransactionOutput( genesisTransaction.getRecipient(),
+ genesisTransaction.getValue(),
+ genesisTransaction.getTransactionId()));
+
+ // Its important to store our first transaction in the UTXOs list.
+ mapUTXOs.put(genesisTransaction.getOutputs().get(0).id, genesisTransaction.getOutputs().get(0));
+
+ System.out.println("Creating and Mining Genesis block... ");
+ Block genesis = new Block("0");
+ genesis.addTransaction(genesisTransaction, mapUTXOs, minimumTransaction);
+ BlockChain.addBlock(blockchain, genesis, difficulty);
+
+ // Testing
+ Block block1 = new Block(genesis.hash);
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
+
+ Assertions.assertEquals(100, walletA.getBalance( mapUTXOs ));
+
+ System.out.println("\nWalletA is Attempting to send funds (40) to WalletB...");
+ Assertions.assertTrue(
+ block1.addTransaction( walletA.sendFunds(walletB.publicKey, 40f, mapUTXOs),
+ mapUTXOs, minimumTransaction) );
+ Assertions.assertTrue( BlockChain.addBlock(blockchain, block1, difficulty) );
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
+ System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
+
+ Assertions.assertEquals(60, walletA.getBalance( mapUTXOs ));
+ Assertions.assertEquals(40, walletB.getBalance( mapUTXOs ));
+
+ Block block2 = new Block(block1.hash);
+ System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
+ Assertions.assertTrue(
+ block2.addTransaction( walletA.sendFunds(walletB.publicKey, 1000f, mapUTXOs),
+ mapUTXOs, minimumTransaction) );
+ Assertions.assertTrue( BlockChain.addBlock(blockchain, block2, difficulty) );
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
+ System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
+
+ Block block3 = new Block(block2.hash);
+ System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
+ Assertions.assertTrue(
+ block3.addTransaction( walletB.sendFunds( walletA.publicKey, 20, mapUTXOs),
+ mapUTXOs, minimumTransaction) );
+ System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
+ System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
+
+ BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
+ Assertions.assertTrue( BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty ) );
+ }
+
+}
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 27ec9f9..12b0e4f 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -134,7 +134,7 @@ public static String getMerkleRoot(List transactions) {
int count = transactions.size();
List previousTreeLayer = new ArrayList();
for (Transaction transaction : transactions) {
- previousTreeLayer.add(transaction.transactionId);
+ previousTreeLayer.add(transaction.getTransactionId());
}
List treeLayer = previousTreeLayer;
while (count > 1) {
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index f472fc8..fdd25bd 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -6,6 +6,7 @@
import java.security.Signature;
import java.util.List;
+import java.util.Map;
import java.util.ArrayList;
import java.util.Base64;
@@ -17,24 +18,25 @@
*/
public class Transaction {
/** This is also the hash of the transaction. */
- public String transactionId;
+ private String transactionId;
/** senders address/public key. */
- public PublicKey sender;
+ private PublicKey sender;
/** Recipients address/public key. */
- public PublicKey reciepient;
- public float value;
+ private PublicKey recipient;
+ private float value;
/** This is to prevent anybody else from spending funds in our wallet. */
- public byte[] signature;
+ private byte[] signature;
- public List inputs = new ArrayList();
- public List outputs = new ArrayList();
+ private List inputs = new ArrayList();
+ private List outputs = new ArrayList();
- private static int sequence = 0; // a rough count of how many transactions have been generated.
+ /** A rough count of how many transactions have been generated. */
+ private static int sequence = 0;
// Constructor:
public Transaction(PublicKey from, PublicKey to, float value, List inputs) {
this.sender = from;
- this.reciepient = to;
+ this.recipient = to;
this.value = value;
this.inputs = inputs;
}
@@ -49,7 +51,7 @@ private String calculateHash() {
try {
return StringUtils.applySha256(
StringUtils.getStringFromKey(this.sender) +
- StringUtils.getStringFromKey(this.reciepient) +
+ StringUtils.getStringFromKey(this.recipient) +
Float.toString(value) + Transaction.sequence
);
} catch (BlockchainException e) {
@@ -111,7 +113,7 @@ public static String getStringFromKey(Key key) {
*/
public void generateSignature(PrivateKey privateKey) {
String data = StringUtils.getStringFromKey(this.sender)
- + StringUtils.getStringFromKey(this.reciepient)
+ + StringUtils.getStringFromKey(this.recipient)
+ Float.toString(this.value);
try {
this.signature = StringUtils.applyECDSASig(privateKey,data);
@@ -126,30 +128,33 @@ public void generateSignature(PrivateKey privateKey) {
* Verifies the data we signed hasn't been tampered with.
* @return
*/
- public boolean verifiySignature() {
+ public boolean verifySignature() {
String data = StringUtils.getStringFromKey(this.sender)
- + StringUtils.getStringFromKey(this.reciepient)
+ + StringUtils.getStringFromKey(this.recipient)
+ Float.toString(this.value);
return StringUtils.verifyECDSASig(this.sender, data, this.signature);
}
/**
- * Returns true if new transaction could be created.
+ * Returns true if new transaction could be created.
+ * @param UTXOs
+ * @param minimumTransaction
* @return
*/
- public boolean processTransaction() {
+ public boolean processTransaction( final Map UTXOs,
+ final float minimumTransaction) {
- if (verifiySignature() == false) {
+ if (this.verifySignature() == false) {
System.out.println("#Transaction Signature failed to verify");
return false;
}
// Gather transaction inputs (Make sure they are unspent):
- inputs.stream().forEach(ti -> ti.UTXO = NoobChain.UTXOs.get(ti.transactionOutputId) );
+ this.inputs.stream().forEach(ti -> ti.UTXO = UTXOs.get(ti.transactionOutputId) );
// Check if transaction is valid:
- if (this.getInputsValue() < NoobChain.minimumTransaction) {
- System.out.println("#Transaction Inputs to small: " + getInputsValue());
+ if (this.getInputsValue() < minimumTransaction) {
+ System.out.println("#Transaction Inputs to small: " + this.getInputsValue());
return false;
}
@@ -158,18 +163,18 @@ public boolean processTransaction() {
// - Get value of inputs then the left over change:
this.transactionId = this.calculateHash();
// - Send value to recipient
- this.outputs.add(new TransactionOutput( this.reciepient, this.value, this.transactionId));
+ this.outputs.add(new TransactionOutput( this.recipient, this.value, this.transactionId));
// - Send the left over 'change' back to sender
this.outputs.add(new TransactionOutput( this.sender, leftOver, this.transactionId));
// Add outputs to Unspent list
- this.outputs.stream().forEach(to -> NoobChain.UTXOs.put(to.id , to) );
+ this.outputs.stream().forEach(to -> UTXOs.put(to.id , to) );
// Remove transaction inputs from UTXO lists as spent:
this.inputs.stream().forEach(ti -> {
// If Transaction can't be found skip it
if ( ti.UTXO != null)
- { NoobChain.UTXOs.remove(ti.UTXO.id); }
+ { UTXOs.remove(ti.UTXO.id); }
} );
return true;
@@ -200,5 +205,28 @@ public float getOutputsValue() {
}
return total;
}
+
+
+ public void setTransactionId(String transactionId)
+ { this.transactionId = transactionId; }
+
+ public String getTransactionId()
+ { return this.transactionId; }
+
+ public PublicKey getSender()
+ { return this.sender; }
+
+ public PublicKey getRecipient()
+ { return this.recipient; }
+
+ public float getValue()
+ { return this.value; }
+
+ public List getOutputs()
+ { return this.outputs; }
+
+ public List getInputs()
+ { return this.inputs; }
+
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 43a57d4..1fa94b9 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -60,14 +60,14 @@ public void generateKeyPair() {
* Returns balance and stores the UTXO's owned by this wallet in this.UTXOs
* @return
*/
- public float getBalance() {
+ public float getBalance(final Map mapUTXOs) {
float total = 0;
- for (Map.Entry item: NoobChainFinale.UTXOs.entrySet()){
+ for (Map.Entry item : mapUTXOs.entrySet()) {
TransactionOutput UTXO = item.getValue();
- if (UTXO.isMine(publicKey)) {
+ if (UTXO.isMine(this.publicKey)) {
// If output belongs to me ( if coins belong to me )
// Add it to our list of unspent transactions.
- NoobChainFinale.UTXOs.put(UTXO.id,UTXO);
+ mapUTXOs.put(UTXO.id, UTXO);
total += UTXO.value ;
}
}
@@ -75,14 +75,15 @@ public float getBalance() {
}
/**
- * Generates and returns a new transaction from this wallet.
+ * Generates and returns a new transaction from this wallet.
* @param recipient
* @param value
+ * @param mapUTXOs
* @return
*/
- public Transaction sendFunds(PublicKey recipient, float value) {
+ public Transaction sendFunds(PublicKey recipient, float value, final Map mapUTXOs) {
// Gather balance and check funds.
- if (this.getBalance() < value) {
+ if (this.getBalance( mapUTXOs ) < value) {
System.out.println("#Not Enough funds to send transaction. Transaction Discarded.");
return null;
}
@@ -90,19 +91,20 @@ public Transaction sendFunds(PublicKey recipient, float value) {
List inputs = new ArrayList();
float total = 0;
- for (Map.Entry item: NoobChainFinale.UTXOs.entrySet()){
+ for (Map.Entry item : mapUTXOs.entrySet()) {
TransactionOutput UTXO = item.getValue();
total += UTXO.value;
inputs.add(new TransactionInput(UTXO.id));
- if (total > value) { break; }
+ if (total > value) { break; }
}
Transaction newTransaction = new Transaction(this.publicKey, recipient , value, inputs);
newTransaction.generateSignature(this.privateKey);
for (TransactionInput input: inputs) {
- NoobChainFinale.UTXOs.remove(input.transactionOutputId);
+ mapUTXOs.remove(input.transactionOutputId);
}
+
return newTransaction;
}
From a04e139557319f2050c525015928396d26d030d8 Mon Sep 17 00:00:00 2001
From: Gaby Wald <30340425+gabywald@users.noreply.github.com>
Date: Thu, 14 Oct 2021 18:23:40 +0200
Subject: [PATCH 11/12] [blockchain]Some Debug, finalizing Unit Tests,
correction
---
.../gabywald/crypto/blockchain/Block.java | 8 +++-
.../crypto/blockchain/BlockChain.java | 25 ++++++++++--
.../crypto/blockchain/NoobChainFinale.java | 29 ++++++++++++++
.../crypto/blockchain/NoobChainTests.java | 32 +++++++++++-----
.../crypto/blockchain/StringUtils.java | 14 +++----
.../crypto/blockchain/Transaction.java | 38 +++++++++++--------
.../gabywald/crypto/blockchain/Wallet.java | 7 ++--
7 files changed, 110 insertions(+), 43 deletions(-)
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 746a8ca..3e9a960 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -68,10 +68,14 @@ public String calculateHash() {
return calculatedhash;
}
+ /**
+ * Mining block
+ * @param difficulty
+ */
public void mineBlock(int difficulty) {
this.merkleRoot = StringUtils.getMerkleRoot(this.transactions);
// Create a string with difficulty * "0"
- String target = StringUtils.getDificultyString(difficulty);
+ String target = StringUtils.getDifficultyString(difficulty);
while ( (this.hash == null) || ( ! this.hash.substring( 0, difficulty ).equals(target)) ) {
this.nonce++;
this.hash = this.calculateHash();
@@ -85,7 +89,7 @@ public void mineBlock(int difficulty) {
* @param transaction
* @param UTXOs
* @param minimumTransaction
- * @return
+ * @return (boolean)
*/
public boolean addTransaction( final Transaction transaction,
final Map UTXOs,
diff --git a/src/main/java/gabywald/crypto/blockchain/BlockChain.java b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
index 0ff2869..fcc00f1 100644
--- a/src/main/java/gabywald/crypto/blockchain/BlockChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
@@ -10,13 +10,22 @@
*/
public abstract class BlockChain {
+ /**
+ * Build a list of Blocks.
+ * @return
+ */
public static List build() {
return new ArrayList();
}
- public static Boolean isChainValidV1(List blockchain) {
- Block currentBlock;
- Block previousBlock;
+ /**
+ *
+ * @param blockchain
+ * @return (boolean)
+ */
+ public static boolean isChainValidV1(List blockchain) {
+ Block currentBlock = null;
+ Block previousBlock = null;
// Loop through blockchain to check hashes:
for (int i = 1 ; i < blockchain.size() ; i++) {
@@ -36,10 +45,17 @@ public static Boolean isChainValidV1(List blockchain) {
return true;
}
+ /**
+ *
+ * @param blockchain
+ * @param genesisTransaction
+ * @param difficulty
+ * @return (boolean)
+ */
public static boolean isChainValidV2(List blockchain, Transaction genesisTransaction, int difficulty) {
Block currentBlock = null;
Block previousBlock = null;
- String hashTarget = new String(new char[difficulty]).replace('\0', '0');
+ String hashTarget = StringUtils.getDifficultyString(difficulty);
// A temporary working list of unspent transactions at a given block state.
HashMap tempUTXOs = new HashMap();
@@ -108,6 +124,7 @@ public static boolean isChainValidV2(List blockchain, Transaction genesis
System.out.println("#Transaction(" + t + ") output reciepient is not who it should be");
return false;
}
+
if (currentTransaction.getOutputs().get(1).reciepient != currentTransaction.getSender()) {
System.out.println("#Transaction(" + t + ") output 'change' is not sender.");
return false;
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
index cbf8ef2..237eaf9 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
@@ -80,5 +80,34 @@ public static void main(String[] args) {
BlockChain.isChainValidV2( NoobChainFinale.blockchain, NoobChainFinale.genesisTransaction, NoobChainFinale.difficulty );
}
+
+ /*
+Creating and Mining Genesis block...
+Transaction Successfully added to Block
+Block Mined!!! : 0000141c6c378745ae6ae56f9defa305d6bb2783e0dbba55c74764a0a8c78baa
+
+WalletA's balance is: 100.0
+
+WalletA is Attempting to send funds (40) to WalletB...
+Transaction Successfully added to Block
+Block Mined!!! : 000483240ccb2fc341fb704805ab0fe1b26b3e01d2eb2cc530ada22688dc4336
+
+WalletA's balance is: 60.0
+WalletB's balance is: 40.0
+
+WalletA Attempting to send more funds (1000) than it has...
+#Not Enough funds to send transaction. Transaction Discarded.
+Block Mined!!! : 000099416026dec23bf3f9c9d3fc368c518b3bd09e02387f71c2a654885de07b
+
+WalletA's balance is: 60.0
+WalletB's balance is: 40.0
+
+WalletB is Attempting to send funds (20) to WalletA...
+Transaction Successfully added to Block
+
+WalletA's balance is: 20.0
+WalletB's balance is: 80.0
+Blockchain is valid
+ */
}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
index 4fefa0d..1ae4884 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
@@ -134,6 +134,7 @@ void testPart05() {
// Create genesis transaction, which sends 100 NoobCoin to walletA:
Transaction genesisTransaction = new Transaction(coinbase.publicKey, walletA.publicKey, 100f, null);
+ Assertions.assertNotNull( genesisTransaction );
// Manually sign the genesis transaction
genesisTransaction.generateSignature(coinbase.privateKey);
// Manually set the transaction id
@@ -141,11 +142,10 @@ void testPart05() {
// Manually add the Transactions Output
genesisTransaction.getOutputs().add(new TransactionOutput( genesisTransaction.getRecipient(),
genesisTransaction.getValue(),
- genesisTransaction.getTransactionId()));
+ genesisTransaction.getTransactionId() ));
// Its important to store our first transaction in the UTXOs list.
mapUTXOs.put(genesisTransaction.getOutputs().get(0).id, genesisTransaction.getOutputs().get(0));
-
System.out.println("Creating and Mining Genesis block... ");
Block genesis = new Block("0");
genesis.addTransaction(genesisTransaction, mapUTXOs, minimumTransaction);
@@ -158,24 +158,33 @@ void testPart05() {
Assertions.assertEquals(100, walletA.getBalance( mapUTXOs ));
System.out.println("\nWalletA is Attempting to send funds (40) to WalletB...");
- Assertions.assertTrue(
- block1.addTransaction( walletA.sendFunds(walletB.publicKey, 40f, mapUTXOs),
- mapUTXOs, minimumTransaction) );
+ boolean bBlock1AddTransactionResult = block1.addTransaction( walletA.sendFunds(walletB.publicKey, 40f, mapUTXOs),
+ mapUTXOs, minimumTransaction) ;
+ Assertions.assertTrue( bBlock1AddTransactionResult );
Assertions.assertTrue( BlockChain.addBlock(blockchain, block1, difficulty) );
System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
Assertions.assertEquals(60, walletA.getBalance( mapUTXOs ));
Assertions.assertEquals(40, walletB.getBalance( mapUTXOs ));
+
+ boolean isChainValid = BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
+ Assertions.assertTrue( isChainValid );
Block block2 = new Block(block1.hash);
System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
- Assertions.assertTrue(
- block2.addTransaction( walletA.sendFunds(walletB.publicKey, 1000f, mapUTXOs),
- mapUTXOs, minimumTransaction) );
+ boolean bBlock2AddTransactionResult = block2.addTransaction( walletA.sendFunds(walletB.publicKey, 1000f, mapUTXOs),
+ mapUTXOs, minimumTransaction);
+ Assertions.assertFalse( bBlock2AddTransactionResult);
Assertions.assertTrue( BlockChain.addBlock(blockchain, block2, difficulty) );
System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
+
+ Assertions.assertEquals(60, walletA.getBalance( mapUTXOs ));
+ Assertions.assertEquals(40, walletB.getBalance( mapUTXOs ));
+
+ isChainValid = BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
+ Assertions.assertTrue( isChainValid );
Block block3 = new Block(block2.hash);
System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
@@ -184,9 +193,12 @@ void testPart05() {
mapUTXOs, minimumTransaction) );
System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
+
+ Assertions.assertEquals(80, walletA.getBalance( mapUTXOs ));
+ Assertions.assertEquals(20, walletB.getBalance( mapUTXOs ));
- BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
- Assertions.assertTrue( BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty ) );
+ isChainValid = BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
+ Assertions.assertTrue( isChainValid );
}
}
diff --git a/src/main/java/gabywald/crypto/blockchain/StringUtils.java b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
index 12b0e4f..5505109 100644
--- a/src/main/java/gabywald/crypto/blockchain/StringUtils.java
+++ b/src/main/java/gabywald/crypto/blockchain/StringUtils.java
@@ -22,12 +22,12 @@
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
-public class StringUtils {
+public abstract class StringUtils {
/**
* Applies Sha256 to a string and returns the result.
* @param input
- * @return
+ * @return (String)
* @throws BlockchainException
* TODO upgrade / improve this method (applySha256) to return null value if any exception inside !
*/
@@ -66,7 +66,7 @@ public static String applySha256(String input)
* Applies ECDSA Signature and returns the result ( as bytes ).
* @param privateKey
* @param input
- * @return
+ * @return (byte[])
* @throws NoSuchProviderException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
@@ -96,7 +96,7 @@ public static byte[] applyECDSASig(PrivateKey privateKey, String input)
* @param publicKey
* @param data
* @param signature
- * @return
+ * @return (boolean)
*/
public static boolean verifyECDSASig(PublicKey publicKey, String data, byte[] signature) {
try {
@@ -119,16 +119,16 @@ public static String getStringFromKey(Key key) {
/**
* Returns difficulty string target, to compare to hash. eg difficulty of 5 will return "00000"
* @param difficulty
- * @return
+ * @return (String)
*/
- public static String getDificultyString(int difficulty) {
+ public static String getDifficultyString(int difficulty) {
return new String(new char[difficulty]).replace('\0', '0');
}
/**
* Tacks in array of transactions and returns a merkle root.
* @param transactions
- * @return
+ * @return (String)
*/
public static String getMerkleRoot(List transactions) {
int count = transactions.size();
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index fdd25bd..7594fa6 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -137,12 +137,12 @@ public boolean verifySignature() {
/**
* Returns true if new transaction could be created.
- * @param UTXOs
+ * @param mapUTXOs
* @param minimumTransaction
* @return
*/
- public boolean processTransaction( final Map UTXOs,
- final float minimumTransaction) {
+ public boolean processTransaction( final Map mapUTXOs,
+ final float minimumTransaction) {
if (this.verifySignature() == false) {
System.out.println("#Transaction Signature failed to verify");
@@ -150,7 +150,10 @@ public boolean processTransaction( final Map UTXOs,
}
// Gather transaction inputs (Make sure they are unspent):
- this.inputs.stream().forEach(ti -> ti.UTXO = UTXOs.get(ti.transactionOutputId) );
+ // this.inputs.stream().forEach(ti -> ti.UTXO = UTXOs.get(ti.transactionOutputId) );
+ for (TransactionInput it : inputs) {
+ it.UTXO = mapUTXOs.get(it.transactionOutputId);
+ }
// Check if transaction is valid:
if (this.getInputsValue() < minimumTransaction) {
@@ -168,13 +171,16 @@ public boolean processTransaction( final Map UTXOs,
this.outputs.add(new TransactionOutput( this.sender, leftOver, this.transactionId));
// Add outputs to Unspent list
- this.outputs.stream().forEach(to -> UTXOs.put(to.id , to) );
+ // this.outputs.stream().forEach(to -> mapUTXOs.put(to.id , to) );
+ for (TransactionOutput o : outputs) {
+ mapUTXOs.put(o.id , o);
+ }
// Remove transaction inputs from UTXO lists as spent:
this.inputs.stream().forEach(ti -> {
// If Transaction can't be found skip it
if ( ti.UTXO != null)
- { UTXOs.remove(ti.UTXO.id); }
+ { mapUTXOs.remove(ti.UTXO.id); }
} );
return true;
@@ -205,28 +211,28 @@ public float getOutputsValue() {
}
return total;
}
-
-
+
+
public void setTransactionId(String transactionId)
- { this.transactionId = transactionId; }
+ { this.transactionId = transactionId; }
public String getTransactionId()
- { return this.transactionId; }
+ { return this.transactionId; }
public PublicKey getSender()
- { return this.sender; }
+ { return this.sender; }
public PublicKey getRecipient()
- { return this.recipient; }
+ { return this.recipient; }
public float getValue()
- { return this.value; }
+ { return this.value; }
public List getOutputs()
- { return this.outputs; }
+ { return this.outputs; }
public List getInputs()
- { return this.inputs; }
-
+ { return this.inputs; }
+
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 1fa94b9..610adaf 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -79,7 +79,7 @@ public float getBalance(final Map mapUTXOs) {
* @param recipient
* @param value
* @param mapUTXOs
- * @return
+ * @return (Transaction)
*/
public Transaction sendFunds(PublicKey recipient, float value, final Map mapUTXOs) {
// Gather balance and check funds.
@@ -101,9 +101,8 @@ public Transaction sendFunds(PublicKey recipient, float value, final Map
Date: Thu, 14 Oct 2021 19:02:37 +0200
Subject: [PATCH 12/12] [blockchain]Some More review (data access)
---
src/main/java/NoobChainTests.java | 24 ++++-----
.../gabywald/crypto/blockchain/Block.java | 24 +++++++--
.../crypto/blockchain/BlockChain.java | 28 +++++------
.../crypto/blockchain/NoobChainFinale.java | 9 ++--
...obChain.java => NoobChainIntegration.java} | 50 +++++++++----------
.../crypto/blockchain/NoobChainTests.java | 38 +++++++-------
.../crypto/blockchain/Transaction.java | 32 ++++++------
.../crypto/blockchain/TransactionInput.java | 13 ++++-
.../crypto/blockchain/TransactionOutput.java | 26 +++++++---
.../gabywald/crypto/blockchain/Wallet.java | 16 +++---
10 files changed, 149 insertions(+), 111 deletions(-)
rename src/main/java/gabywald/crypto/blockchain/{NoobChain.java => NoobChainIntegration.java} (70%)
diff --git a/src/main/java/NoobChainTests.java b/src/main/java/NoobChainTests.java
index c396855..3139ee4 100644
--- a/src/main/java/NoobChainTests.java
+++ b/src/main/java/NoobChainTests.java
@@ -28,18 +28,18 @@ class NoobChainTests {
void testPart01() {
Block genesisBlock = new Block("Hi im the first block", "0");
Assertions.assertNotNull( genesisBlock );
- System.out.println("Hash for block 1 : " + genesisBlock.hash);
- Assertions.assertNotNull( genesisBlock.hash );
+ System.out.println("Hash for block 1 : " + genesisBlock.getHash() );
+ Assertions.assertNotNull( genesisBlock.getHash() );
- Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.getHash() );
Assertions.assertNotNull( secondBlock );
- System.out.println("Hash for block 2 : " + secondBlock.hash);
- Assertions.assertNotNull( secondBlock.hash );
+ System.out.println("Hash for block 2 : " + secondBlock.getHash() );
+ Assertions.assertNotNull( secondBlock.getHash() );
- Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.getHash() );
Assertions.assertNotNull( thirdBlock );
- System.out.println("Hash for block 3 : " + thirdBlock.hash);
- Assertions.assertNotNull( thirdBlock.hash );
+ System.out.println("Hash for block 3 : " + thirdBlock.getHash() );
+ Assertions.assertNotNull( thirdBlock.getHash() );
}
/**
@@ -50,8 +50,8 @@ void testPart02() {
List blockchain = new ArrayList();
// Add our blocks to the blockchain List:
blockchain.add(new Block("Hi im the first block", "0"));
- blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
- blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).getHash() ));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).getHash() ));
Assertions.assertEquals(3, blockchain.size());
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
Assertions.assertNotNull( blockchainJson );
@@ -67,11 +67,11 @@ void testPart03() {
System.out.println("Trying to Mine block 1... ");
blockchain.get(0).mineBlock(difficulty);
- blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).getHash() ));
System.out.println("Trying to Mine block 2... ");
blockchain.get(1).mineBlock(difficulty);
- blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).getHash() ));
System.out.println("Trying to Mine block 3... ");
blockchain.get(2).mineBlock(difficulty);
diff --git a/src/main/java/gabywald/crypto/blockchain/Block.java b/src/main/java/gabywald/crypto/blockchain/Block.java
index 3e9a960..71dee6e 100644
--- a/src/main/java/gabywald/crypto/blockchain/Block.java
+++ b/src/main/java/gabywald/crypto/blockchain/Block.java
@@ -13,17 +13,17 @@
*/
public class Block {
- public String hash;
- public String previousHash;
+ private String hash;
+ private String previousHash;
/** Our data will be a simple message. */
// private String data;
/** As number of milliseconds since 1/1/1970. */
private long timeStamp;
private int nonce;
- public String merkleRoot;
- /** Our data will be a simple message. */
- public List transactions = new ArrayList();
+ private String merkleRoot;
+
+ private List transactions = new ArrayList();
/**
* Block Constructor.
@@ -106,4 +106,18 @@ public boolean addTransaction( final Transaction transaction,
System.out.println("Transaction Successfully added to Block");
return true;
}
+
+ public String getHash()
+ { return this.hash; }
+
+ public String getPreviousHash()
+ { return this.previousHash; }
+
+ public String getMerkleRoot()
+ { return this.merkleRoot; }
+
+ public List getTransactions()
+ { return this.transactions; }
+
+
}
diff --git a/src/main/java/gabywald/crypto/blockchain/BlockChain.java b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
index fcc00f1..0166905 100644
--- a/src/main/java/gabywald/crypto/blockchain/BlockChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/BlockChain.java
@@ -32,12 +32,12 @@ public static boolean isChainValidV1(List blockchain) {
currentBlock = blockchain.get(i);
previousBlock = blockchain.get(i-1);
// Compare registered hash and calculated hash:
- if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ if ( ! currentBlock.getHash().equals(currentBlock.calculateHash()) ) {
System.out.println("Current Hashes not equal");
return false;
}
// Compare previous hash and registered previous hash
- if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ if ( ! previousBlock.getHash().equals(currentBlock.getPreviousHash() ) ) {
System.out.println("Previous Hashes not equal");
return false;
}
@@ -59,7 +59,7 @@ public static boolean isChainValidV2(List blockchain, Transaction genesis
// A temporary working list of unspent transactions at a given block state.
HashMap tempUTXOs = new HashMap();
- tempUTXOs.put(genesisTransaction.getOutputs().get(0).id, genesisTransaction.getOutputs().get(0));
+ tempUTXOs.put(genesisTransaction.getOutputs().get(0).getId(), genesisTransaction.getOutputs().get(0));
// Loop through blockchain to check hashes:
for (int i = 1 ; i < blockchain.size() ; i++) {
@@ -68,27 +68,27 @@ public static boolean isChainValidV2(List blockchain, Transaction genesis
previousBlock = blockchain.get(i-1);
// Compare registered hash and calculated hash:
- if ( ! currentBlock.hash.equals(currentBlock.calculateHash()) ) {
+ if ( ! currentBlock.getHash().equals(currentBlock.calculateHash()) ) {
System.out.println("#Current Hashes not equal");
return false;
}
// Compare previous hash and registered previous hash
- if ( ! previousBlock.hash.equals(currentBlock.previousHash) ) {
+ if ( ! previousBlock.getHash().equals(currentBlock.getPreviousHash() ) ) {
System.out.println("#Previous Hashes not equal");
return false;
}
// Check if hash is solved
- if ( ! currentBlock.hash.substring( 0, difficulty).equals(hashTarget)) {
+ if ( ! currentBlock.getHash().substring( 0, difficulty).equals(hashTarget)) {
System.out.println("#This block hasn't been mined");
return false;
}
// Loop thru blockchains transactions:
TransactionOutput tempOutput;
- for (int t = 0 ; t < currentBlock.transactions.size() ; t++) {
- Transaction currentTransaction = currentBlock.transactions.get(t);
+ for (int t = 0 ; t < currentBlock.getTransactions().size() ; t++) {
+ Transaction currentTransaction = currentBlock.getTransactions().get(t);
if ( ! currentTransaction.verifySignature()) {
System.out.println("#Signature on Transaction(" + t + ") is Invalid");
@@ -101,31 +101,31 @@ public static boolean isChainValidV2(List blockchain, Transaction genesis
}
for (TransactionInput input: currentTransaction.getInputs()) {
- tempOutput = tempUTXOs.get(input.transactionOutputId);
+ tempOutput = tempUTXOs.get(input.getTransactionOutputId() );
if (tempOutput == null) {
System.out.println("#Referenced input on Transaction(" + t + ") is Missing");
return false;
}
- if (input.UTXO.value != tempOutput.value) {
+ if (input.getTransactionOutput().getValue() != tempOutput.getValue()) {
System.out.println("#Referenced input Transaction(" + t + ") value is Invalid");
return false;
}
- tempUTXOs.remove(input.transactionOutputId);
+ tempUTXOs.remove(input.getTransactionOutputId() );
}
for (TransactionOutput output: currentTransaction.getOutputs()) {
- tempUTXOs.put(output.id, output);
+ tempUTXOs.put(output.getId(), output);
}
- if (currentTransaction.getOutputs().get(0).reciepient != currentTransaction.getRecipient()) {
+ if (currentTransaction.getOutputs().get(0).getRecipient() != currentTransaction.getRecipient()) {
System.out.println("#Transaction(" + t + ") output reciepient is not who it should be");
return false;
}
- if (currentTransaction.getOutputs().get(1).reciepient != currentTransaction.getSender()) {
+ if (currentTransaction.getOutputs().get(1).getRecipient() != currentTransaction.getSender()) {
System.out.println("#Transaction(" + t + ") output 'change' is not sender.");
return false;
}
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
index 237eaf9..2502fd3 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainFinale.java
@@ -46,7 +46,8 @@ public static void main(String[] args) {
NoobChainFinale.genesisTransaction.getTransactionId()));
// Its important to store our first transaction in the UTXOs list.
- NoobChainFinale.mapUTXOs.put(NoobChainFinale.genesisTransaction.getOutputs().get(0).id, NoobChainFinale.genesisTransaction.getOutputs().get(0));
+ NoobChainFinale.mapUTXOs.put( NoobChainFinale.genesisTransaction.getOutputs().get(0).getId(),
+ NoobChainFinale.genesisTransaction.getOutputs().get(0));
System.out.println("Creating and Mining Genesis block... ");
Block genesis = new Block("0");
@@ -54,7 +55,7 @@ public static void main(String[] args) {
BlockChain.addBlock(NoobChainFinale.blockchain, genesis, NoobChainFinale.difficulty);
// Testing
- Block block1 = new Block(genesis.hash);
+ Block block1 = new Block(genesis.getHash() );
System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
System.out.println("\nWalletA is Attempting to send funds (40) to WalletB...");
block1.addTransaction( NoobChainFinale.walletA.sendFunds(NoobChainFinale.walletB.publicKey, 40f, NoobChainFinale.mapUTXOs),
@@ -63,7 +64,7 @@ public static void main(String[] args) {
System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
System.out.println("WalletB's balance is: " + NoobChainFinale.walletB.getBalance( NoobChainFinale.mapUTXOs ));
- Block block2 = new Block(block1.hash);
+ Block block2 = new Block(block1.getHash() );
System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
block2.addTransaction( NoobChainFinale.walletA.sendFunds(NoobChainFinale.walletB.publicKey, 1000f, NoobChainFinale.mapUTXOs),
NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
@@ -71,7 +72,7 @@ public static void main(String[] args) {
System.out.println("\nWalletA's balance is: " + NoobChainFinale.walletA.getBalance( NoobChainFinale.mapUTXOs ));
System.out.println("WalletB's balance is: " + NoobChainFinale.walletB.getBalance( NoobChainFinale.mapUTXOs ));
- Block block3 = new Block(block2.hash);
+ Block block3 = new Block(block2.getHash() );
System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
block3.addTransaction( NoobChainFinale.walletB.sendFunds( NoobChainFinale.walletA.publicKey, 20, NoobChainFinale.mapUTXOs),
NoobChainFinale.mapUTXOs, NoobChainFinale.minimumTransaction);
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChain.java b/src/main/java/gabywald/crypto/blockchain/NoobChainIntegration.java
similarity index 70%
rename from src/main/java/gabywald/crypto/blockchain/NoobChain.java
rename to src/main/java/gabywald/crypto/blockchain/NoobChainIntegration.java
index cb7e90c..8a7709f 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChain.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainIntegration.java
@@ -15,7 +15,7 @@
*
https://github.com/CryptoKass/NoobChain-Tutorial-Part-2
* @author Gabriel Chandesris (2021)
*/
-public class NoobChain {
+public class NoobChainIntegration {
private static List blockchain = new ArrayList();
private static List blockchain2 = new ArrayList();
@@ -29,38 +29,38 @@ public static void main(String[] args) {
// ***** Part I
Block genesisBlock = new Block("Hi im the first block", "0");
- System.out.println("Hash for block 1 : " + genesisBlock.hash);
- Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
- System.out.println("Hash for block 2 : " + secondBlock.hash);
- Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
- System.out.println("Hash for block 3 : " + thirdBlock.hash);
+ System.out.println("Hash for block 1 : " + genesisBlock.getHash());
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.getHash());
+ System.out.println("Hash for block 2 : " + secondBlock.getHash());
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.getHash());
+ System.out.println("Hash for block 3 : " + thirdBlock.getHash());
// ***** Part II
// Add our blocks to the blockchain List:
- NoobChain.blockchain.add(new Block("Hi im the first block", "0"));
- NoobChain.blockchain.add(new Block("Yo im the second block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
- NoobChain.blockchain.add(new Block("Hey im the third block", NoobChain.blockchain.get(NoobChain.blockchain.size()-1).hash));
- String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain);
+ NoobChainIntegration.blockchain.add(new Block("Hi im the first block", "0"));
+ NoobChainIntegration.blockchain.add(new Block("Yo im the second block", NoobChainIntegration.blockchain.get(NoobChainIntegration.blockchain.size()-1).getHash() ));
+ NoobChainIntegration.blockchain.add(new Block("Hey im the third block", NoobChainIntegration.blockchain.get(NoobChainIntegration.blockchain.size()-1).getHash() ));
+ String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChainIntegration.blockchain);
System.out.println(blockchainJson);
// ***** Part III
// Add our blocks to the blockchain List:
- NoobChain.blockchain2.add(new Block("Hi im the first block", "0"));
+ NoobChainIntegration.blockchain2.add(new Block("Hi im the first block", "0"));
System.out.println("Trying to Mine block 1... ");
- NoobChain.blockchain2.get(0).mineBlock(NoobChain.difficulty);
+ NoobChainIntegration.blockchain2.get(0).mineBlock(NoobChainIntegration.difficulty);
- NoobChain.blockchain2.add(new Block("Yo im the second block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ NoobChainIntegration.blockchain2.add(new Block("Yo im the second block", NoobChainIntegration.blockchain2.get(NoobChainIntegration.blockchain2.size()-1).getHash() ));
System.out.println("Trying to Mine block 2... ");
- NoobChain.blockchain2.get(1).mineBlock(NoobChain.difficulty);
+ NoobChainIntegration.blockchain2.get(1).mineBlock(NoobChainIntegration.difficulty);
- NoobChain.blockchain2.add(new Block("Hey im the third block", NoobChain.blockchain2.get(NoobChain.blockchain2.size()-1).hash));
+ NoobChainIntegration.blockchain2.add(new Block("Hey im the third block", NoobChainIntegration.blockchain2.get(NoobChainIntegration.blockchain2.size()-1).getHash() ));
System.out.println("Trying to Mine block 3... ");
- NoobChain.blockchain2.get(2).mineBlock(NoobChain.difficulty);
+ NoobChainIntegration.blockchain2.get(2).mineBlock(NoobChainIntegration.difficulty);
- System.out.println("\nBlockchain is Valid: " + BlockChain.isChainValidV1( NoobChain.blockchain2 ));
+ System.out.println("\nBlockchain is Valid: " + BlockChain.isChainValidV1( NoobChainIntegration.blockchain2 ));
- String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChain.blockchain2);
+ String blockchain2Json = new GsonBuilder().setPrettyPrinting().create().toJson(NoobChainIntegration.blockchain2);
System.out.println("\nThe block chain: ");
System.out.println(blockchain2Json);
@@ -70,21 +70,21 @@ public static void main(String[] args) {
// Security.addProvider(new sun.security.provider.Sun());
// XXX NOTE see https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html
// Create the new wallets
- NoobChain.walletA = new Wallet();
- NoobChain.walletB = new Wallet();
+ NoobChainIntegration.walletA = new Wallet();
+ NoobChainIntegration.walletB = new Wallet();
// Test public and private keys
System.out.println("Private and public keys:");
- System.out.println(StringUtils.getStringFromKey(NoobChain.walletA.privateKey));
- System.out.println(StringUtils.getStringFromKey(NoobChain.walletA.publicKey));
+ System.out.println(StringUtils.getStringFromKey(NoobChainIntegration.walletA.privateKey));
+ System.out.println(StringUtils.getStringFromKey(NoobChainIntegration.walletA.publicKey));
// Create a test transaction from WalletA to walletB
- Transaction transaction = new Transaction(NoobChain.walletA.publicKey, NoobChain.walletB.publicKey, 5, null);
- transaction.generateSignature(NoobChain.walletA.privateKey);
+ Transaction transaction = new Transaction(NoobChainIntegration.walletA.publicKey, NoobChainIntegration.walletB.publicKey, 5, null);
+ transaction.generateSignature(NoobChainIntegration.walletA.privateKey);
// Verify the signature works and verify it from the public key
System.out.println("Is signature verified");
System.out.println(transaction.verifySignature());
// ***** Part V
- // TODO next step of tutorials !!
+ // XXX NOTE see NoobChainFinale and NoobChainTests !!
}
/*
diff --git a/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
index 1ae4884..2281eb9 100644
--- a/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
+++ b/src/main/java/gabywald/crypto/blockchain/NoobChainTests.java
@@ -23,18 +23,18 @@ class NoobChainTests {
void testPart01() {
Block genesisBlock = new Block("Hi im the first block", "0");
Assertions.assertNotNull( genesisBlock );
- System.out.println("Hash for block 1 : " + genesisBlock.hash);
- Assertions.assertNotNull( genesisBlock.hash );
+ System.out.println("Hash for block 1 : " + genesisBlock.getHash() );
+ Assertions.assertNotNull( genesisBlock.getHash() );
- Block secondBlock = new Block("Yo im the second block", genesisBlock.hash);
+ Block secondBlock = new Block("Yo im the second block", genesisBlock.getHash() );
Assertions.assertNotNull( secondBlock );
- System.out.println("Hash for block 2 : " + secondBlock.hash);
- Assertions.assertNotNull( secondBlock.hash );
+ System.out.println("Hash for block 2 : " + secondBlock.getHash() );
+ Assertions.assertNotNull( secondBlock.getHash() );
- Block thirdBlock = new Block("Hey im the third block", secondBlock.hash);
+ Block thirdBlock = new Block("Hey im the third block", secondBlock.getHash() );
Assertions.assertNotNull( thirdBlock );
- System.out.println("Hash for block 3 : " + thirdBlock.hash);
- Assertions.assertNotNull( thirdBlock.hash );
+ System.out.println("Hash for block 3 : " + thirdBlock.getHash() );
+ Assertions.assertNotNull( thirdBlock.getHash() );
}
/**
@@ -45,8 +45,8 @@ void testPart02() {
List blockchain = BlockChain.build();
// Add our blocks to the blockchain List:
blockchain.add(new Block("Hi im the first block", "0"));
- blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
- blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).getHash() ));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).getHash() ));
Assertions.assertEquals(3, blockchain.size());
String blockchainJson = new GsonBuilder().setPrettyPrinting().create().toJson(blockchain);
Assertions.assertNotNull( blockchainJson );
@@ -62,11 +62,11 @@ void testPart03() {
System.out.println("Trying to Mine block 1... ");
blockchain.get(0).mineBlock(difficulty);
- blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Yo im the second block", blockchain.get(blockchain.size()-1).getHash() ));
System.out.println("Trying to Mine block 2... ");
blockchain.get(1).mineBlock(difficulty);
- blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).hash));
+ blockchain.add(new Block("Hey im the third block", blockchain.get(blockchain.size()-1).getHash() ));
System.out.println("Trying to Mine block 3... ");
blockchain.get(2).mineBlock(difficulty);
@@ -145,14 +145,14 @@ void testPart05() {
genesisTransaction.getTransactionId() ));
// Its important to store our first transaction in the UTXOs list.
- mapUTXOs.put(genesisTransaction.getOutputs().get(0).id, genesisTransaction.getOutputs().get(0));
+ mapUTXOs.put(genesisTransaction.getOutputs().get(0).getId(), genesisTransaction.getOutputs().get(0));
System.out.println("Creating and Mining Genesis block... ");
Block genesis = new Block("0");
genesis.addTransaction(genesisTransaction, mapUTXOs, minimumTransaction);
BlockChain.addBlock(blockchain, genesis, difficulty);
// Testing
- Block block1 = new Block(genesis.hash);
+ Block block1 = new Block(genesis.getHash() );
System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
Assertions.assertEquals(100, walletA.getBalance( mapUTXOs ));
@@ -171,7 +171,7 @@ void testPart05() {
boolean isChainValid = BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
Assertions.assertTrue( isChainValid );
- Block block2 = new Block(block1.hash);
+ Block block2 = new Block(block1.getHash() );
System.out.println("\nWalletA Attempting to send more funds (1000) than it has...");
boolean bBlock2AddTransactionResult = block2.addTransaction( walletA.sendFunds(walletB.publicKey, 1000f, mapUTXOs),
mapUTXOs, minimumTransaction);
@@ -186,11 +186,11 @@ void testPart05() {
isChainValid = BlockChain.isChainValidV2( blockchain, genesisTransaction, difficulty );
Assertions.assertTrue( isChainValid );
- Block block3 = new Block(block2.hash);
+ Block block3 = new Block(block2.getHash() );
System.out.println("\nWalletB is Attempting to send funds (20) to WalletA...");
- Assertions.assertTrue(
- block3.addTransaction( walletB.sendFunds( walletA.publicKey, 20, mapUTXOs),
- mapUTXOs, minimumTransaction) );
+ boolean bBlock3AddTransactionResult = block3.addTransaction( walletB.sendFunds( walletA.publicKey, 20, mapUTXOs),
+ mapUTXOs, minimumTransaction);
+ Assertions.assertTrue( bBlock3AddTransactionResult );
System.out.println("\nWalletA's balance is: " + walletA.getBalance( mapUTXOs ));
System.out.println("WalletB's balance is: " + walletB.getBalance( mapUTXOs ));
diff --git a/src/main/java/gabywald/crypto/blockchain/Transaction.java b/src/main/java/gabywald/crypto/blockchain/Transaction.java
index 7594fa6..86f7096 100644
--- a/src/main/java/gabywald/crypto/blockchain/Transaction.java
+++ b/src/main/java/gabywald/crypto/blockchain/Transaction.java
@@ -142,7 +142,7 @@ public boolean verifySignature() {
* @return
*/
public boolean processTransaction( final Map mapUTXOs,
- final float minimumTransaction) {
+ final float minimumTransaction) {
if (this.verifySignature() == false) {
System.out.println("#Transaction Signature failed to verify");
@@ -152,7 +152,7 @@ public boolean processTransaction( final Map mapUTXOs
// Gather transaction inputs (Make sure they are unspent):
// this.inputs.stream().forEach(ti -> ti.UTXO = UTXOs.get(ti.transactionOutputId) );
for (TransactionInput it : inputs) {
- it.UTXO = mapUTXOs.get(it.transactionOutputId);
+ it.setTransactionOutput( mapUTXOs.get(it.getTransactionOutputId() ) );
}
// Check if transaction is valid:
@@ -172,15 +172,15 @@ public boolean processTransaction( final Map mapUTXOs
// Add outputs to Unspent list
// this.outputs.stream().forEach(to -> mapUTXOs.put(to.id , to) );
- for (TransactionOutput o : outputs) {
- mapUTXOs.put(o.id , o);
+ for (TransactionOutput to : outputs) {
+ mapUTXOs.put(to.getId() , to);
}
// Remove transaction inputs from UTXO lists as spent:
this.inputs.stream().forEach(ti -> {
// If Transaction can't be found skip it
- if ( ti.UTXO != null)
- { mapUTXOs.remove(ti.UTXO.id); }
+ if ( ti.getTransactionOutput() != null)
+ { mapUTXOs.remove(ti.getTransactionOutput().getId()); }
} );
return true;
@@ -194,8 +194,8 @@ public float getInputsValue() {
float total = 0;
for (TransactionInput ti : inputs) {
// If Transaction can't be found skip it
- if ( ti.UTXO == null) { continue; }
- total += ti.UTXO.value;
+ if ( ti.getTransactionOutput() == null) { continue; }
+ total += ti.getTransactionOutput().getValue();
}
return total;
}
@@ -207,7 +207,7 @@ public float getInputsValue() {
public float getOutputsValue() {
float total = 0;
for (TransactionOutput to : outputs) {
- total += to.value;
+ total += to.getValue();
}
return total;
}
@@ -215,24 +215,24 @@ public float getOutputsValue() {
public void setTransactionId(String transactionId)
- { this.transactionId = transactionId; }
+ { this.transactionId = transactionId; }
public String getTransactionId()
- { return this.transactionId; }
+ { return this.transactionId; }
public PublicKey getSender()
- { return this.sender; }
+ { return this.sender; }
public PublicKey getRecipient()
- { return this.recipient; }
+ { return this.recipient; }
public float getValue()
- { return this.value; }
+ { return this.value; }
public List getOutputs()
- { return this.outputs; }
+ { return this.outputs; }
public List getInputs()
- { return this.inputs; }
+ { return this.inputs; }
}
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionInput.java b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
index 269c0be..d95d24e 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionInput.java
@@ -8,11 +8,20 @@
*/
public class TransactionInput {
/** Reference to TransactionOutputs -> transactionId */
- public String transactionOutputId;
+ private String transactionOutputId = null;
/** Contains the Unspent transaction output */
- public TransactionOutput UTXO;
+ private TransactionOutput to = null;
public TransactionInput(String transactionOutputId) {
this.transactionOutputId = transactionOutputId;
}
+
+ public String getTransactionOutputId()
+ { return this.transactionOutputId; }
+
+ public TransactionOutput getTransactionOutput()
+ { return this.to; }
+
+ void setTransactionOutput(TransactionOutput to)
+ { this.to = to; }
}
diff --git a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
index 02271b6..d345b03 100644
--- a/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
+++ b/src/main/java/gabywald/crypto/blockchain/TransactionOutput.java
@@ -9,13 +9,13 @@
* @author Gabriel Chandesris (2021)
*/
public class TransactionOutput {
- public String id;
+ private String id;
/** Also known as the new owner of these coins. */
- public PublicKey reciepient;
+ private PublicKey recipient;
/** The amount of coins they own */
- public float value;
+ private float value;
/** The id of the transaction this output was created in */
- public String parentTransactionId;
+ private String parentTransactionId;
/**
* Constructor
@@ -24,7 +24,7 @@ public class TransactionOutput {
* @param parentTransactionId
*/
public TransactionOutput(PublicKey reciepient, float value, String parentTransactionId) {
- this.reciepient = reciepient;
+ this.recipient = reciepient;
this.value = value;
this.parentTransactionId = parentTransactionId;
try {
@@ -44,8 +44,22 @@ public TransactionOutput(PublicKey reciepient, float value, String parentTransac
* @return
*/
public boolean isMine(PublicKey publicKey) {
- return this.reciepient.equals(publicKey);
+ return this.recipient.equals(publicKey);
// return (publicKey == this.reciepient);
}
+
+ public String getId()
+ { return this.id; }
+
+ public PublicKey getRecipient()
+ { return this.recipient; }
+
+ public float getValue()
+ { return this.value; }
+
+ public String getParentTransactionId()
+ { return this.parentTransactionId; }
+
+
}
diff --git a/src/main/java/gabywald/crypto/blockchain/Wallet.java b/src/main/java/gabywald/crypto/blockchain/Wallet.java
index 610adaf..4c0f6e3 100644
--- a/src/main/java/gabywald/crypto/blockchain/Wallet.java
+++ b/src/main/java/gabywald/crypto/blockchain/Wallet.java
@@ -63,12 +63,12 @@ public void generateKeyPair() {
public float getBalance(final Map mapUTXOs) {
float total = 0;
for (Map.Entry item : mapUTXOs.entrySet()) {
- TransactionOutput UTXO = item.getValue();
- if (UTXO.isMine(this.publicKey)) {
+ TransactionOutput to = item.getValue();
+ if (to.isMine(this.publicKey)) {
// If output belongs to me ( if coins belong to me )
// Add it to our list of unspent transactions.
- mapUTXOs.put(UTXO.id, UTXO);
- total += UTXO.value ;
+ mapUTXOs.put(to.getId(), to);
+ total += to.getValue() ;
}
}
return total;
@@ -92,9 +92,9 @@ public Transaction sendFunds(PublicKey recipient, float value, final Map item : mapUTXOs.entrySet()) {
- TransactionOutput UTXO = item.getValue();
- total += UTXO.value;
- inputs.add(new TransactionInput(UTXO.id));
+ TransactionOutput to = item.getValue();
+ total += to.getValue();
+ inputs.add(new TransactionInput(to.getId()));
if (total > value) { break; }
}
@@ -102,7 +102,7 @@ public Transaction sendFunds(PublicKey recipient, float value, final Map