Question

In: Computer Science

“Griffin Blockchain” SUMMARY This project will involve the creation of a Blockchain miner that does all...

“Griffin Blockchain”

  1. SUMMARY

This project will involve the creation of a Blockchain miner that does all the following:

  • Receives transactions from user or remote node.
  • Sends transactions to a remote node.
  • Manages incoming remote node messages using a Queue.
  • Generates a Merkle Tree and an eventual Merkle Root as part of Transaction processing.
  • Creates Blockchain Blocks using Proof of Work algorithm.

For this project, you will create the main functionality inside of an existing code base called BlockchainBasics. The BlockchainBasics code that you will begin with is provided along with this document.

BlockchainBasics, once completed, will allow you to run two instances of this app on two different ports that pass transactions to each other and mine blocks.

This app doesn’t save the blocks into a blockchain, but the central functionality you code into this app will be able to be plugged in directly into a larger Blockchain application (the code for this will be provided in the coming weeks) that fully manages a Blockchain, connects to multiple networked nodes, and allows you to trade items on the network.

However, you will only be turning in the BlockchainBasics code as specified at the end of this doc.

This project will involve the following:

- Socket programming

- Queue

- Multithreading

- Hashing: SHA-256

- Merkle Trees

- Blockchain Proof of Work

  1. DETAILS
  1. Download BlockchainBasics.zip
  1. This includes the following classes:
    1. BlockchainBasics.java
    2. Miner.java
    3. Block.java
    4. MerkleNode.java
    5. BlockchainUtil.java
    6. P2PServer.java
    7. P2PMessageQueue.java
    8. P2PMessage.java
    9. P2PUtil.java
  1. You only add code where you see this:

####################

### ADD CODE HERE ###

####################

  1. CLASSES where you add code:
  1. Miner
  1. doProofOfWork method: The logic behind this will be reviewed in class.
    1. This method should first create a string that has as many zeros in it as oBlock.getDifficulty() equals.
      1. Hint: use a while loop here that keeps looping while the length of this string you’re creating is less than the target difficulty length.
  1. Then, this method should have another while loop that keeps looping until a valid nonce is found.
    1. There needs to be an if --- else in this while loop.
  1. If bAbortPoW (an instance variable you’ll see at the top of the class) equals true, then this means another miner solved the block and this miner received it, so you need to:
    1. Set bAbortPoW back to false.
    2. Print out something to the user like:

"[miner] Aborted mining block, probably because another confirmed block received."

  1. Return false so the method ends.
  1. Else perform another attempt at a valid nonce:
    1. The nonce should start at 0 before the while loop and increment each loop.
    2. A valid nonce, after it’s added to the block’s properties and the block is hashed, should result in a hash that has as many leading zeros as the string you created above (use String’s startsWith method for this check).
      1. So remember that on oBlock you have to call:
        1. Set nonce.
        2. Compute hash.
        3. Set hash to whatever came back from compute hash.
      2. Then check if hash on oBlock now begins with your leading zeroes string you created above.
        1. If it does, then return true.
  1. Block
  1. computeMerkleRoot:
  1. Choose which approach you want to take:
    1. The 90% approach is much easier and is based on what we’ve done in class but your max score for the project can only reach 90%.
    2. The 100% approach is much trickier, and you must figure out on your own.
  1. 90% Project Score Logic: This logic needs to account for possibly 2 or 4 items in lstItems that are passed in.
    1. This means your code should have 2 or 4 Merkle Tree leaves depending on how many items are passed in.
  2. 100% Project Score Logic: You can only get 90% on this project if everything else is done perfectly. To get 100%, you must make this method flexible to accept any power of 2 items. So lstItems could be 2,4,8,16,32, etc. and your code would be able to compute the Merkle Root.
  1. NOTE: There is a main method at the bottom of this class that you can use to test 2 and 4 items simply by right clicking on the tab for this class and selecting “Run Block.main()”
  1. populateMerkleNode:
    1. This method will work just as we did in class… set the left and right nodes and then call generateHash in the BlockchainUtil class and set the node’s hash.
  1. BlockchainUtil
  1. generateHash:
    1. This method generates a SHA-256 hash of the string passed in.
    2. Code for this was reviewed in class and doesn’t need to be changed.
  1. P2PMessageQueue
  1. enqueue:
    1. This adds a node to the queue.
    2. Code will be reviewed in class.
  1. dequeue:
    1. This removes and returns a node from the queue.
    2. Code will be reviewed in class.
  1. hasNodes:
    1. This returns true or false depending on if any nodes exist in queue.
    2. Code will be reviewed in class.
  1. P2PUtil
  1. connectForOneMessage:
    1. This method will connect to a given server via Socket for a one-time sending of a message to that server and it will return the reply from the server and disconnect.
    2. Code for the Socket communication will be reviewed in class.
  1. Testing Your Code
    1. You need to run two instances of this app so that they can communicate with each other.
      1. One app can be run from your IDE like you normally do.
      2. The other app must be ran from a PowerShell window or other command line tool as explained below.
  1. Running a separate instance of your app:
    1. Jar file generation
      1. You first need to build your code into a JAR file.
      2. Instructions are included with the project online and will be reviewed in class.
    2. Running your JAR file
      1. Navigate to your JAR file in file explorer.
        1. Shortcut if using IntelliJ:
          1. Find it in your left side file explorer in your IntelliJ IDE:
            1. …out > artifacts > BlockchainBasics_jar > BlockchainBasics.jar
          2. Right click on it and pic “Show in Explorer.”
      2. Make sure that no file is highlighted by LEFT clicking in right space.
      3. SHIFT + RIGHT click in white space as shown in class to get extra menu item of “Open PowerShell Window here”
      4. In PowerShell or other command line tool, type the following to run:

java -jar BlockchainBasics.jar

  1. Then make sure a different port is chosen for your IDE instance and your command line instance:
    1. For instance, choose 8800 for one and 8888 or the other.

Solutions

Expert Solution

Solution:

Givendata:

This project will involve the creation of a Blockchain miner that does all the following:

  • Receives transactions from user or remote node.
  • Sends transactions to a remote node.
  • Manages incoming remote node messages using a Queue.
  • Generates a Merkle Tree and an eventual Merkle Root as part of Transaction processing.
  • Creates Blockchain Blocks using Proof of Work algorithm.

For this project, you will create the main functionality inside of an existing code base called BlockchainBasics. The BlockchainBasics code that you will begin with is provided along with this document.

Answer:

Program Files

Block.java

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/**
* This holds the values for a Block in the Blockchain, and it has methods to
* compute the Merkle Root and generate a hash.
*/
public class Block {

private String sMerkleRoot;
private int iDifficulty = 5; // Mining seconds in testing 5: 6,10,15,17,20,32 | testing 6: 12,289,218
private String sNonce;
private String sMinerUsername;
private String sHash;

/**
* This computes the Merkle Root. It either accepts 2 or 4 items, or if made to
* be dynamic, then accepts any multiple of 2 (2,4,8.16.32,etc.) items.
*
* @param lstItems
* @return
*/
public synchronized String computeMerkleRoot(ArrayList<String> lstItems) {

BlockchainUtil oUtil = new BlockchainUtil();

String left;
String right;

Queue<String> qCompute = new LinkedList<String>();

for (int i = 0; i < lstItems.size(); i++) {
left = oUtil.generateHash(lstItems.get(i));
qCompute.add(left);
}

while (qCompute.size() > 1) {
left = qCompute.remove();
right = qCompute.remove();
qCompute.add(oUtil.generateHash(left + right));
}

return qCompute.remove();

}

/**
* This method populates a Merkle node's left, right, and hash variables.
*
* @param oNode
* @param oLeftNode
* @param oRightNode
*/
private void populateMerkleNode(MerkleNode oNode, MerkleNode oLeftNode, MerkleNode oRightNode) {

oNode.sHash = new BlockchainUtil().generateHash(oLeftNode.sHash + oRightNode.sHash);

}

// Hash this block, and hash will also be next block's previous hash.

/**
* This generates the hash for this block by combining the properties and
* hashing them.
*
* @return
*/
public String computeHash() {

return new BlockchainUtil().generateHash(sMerkleRoot + iDifficulty + sMinerUsername + sNonce);
}

public int getDifficulty() {
return iDifficulty;
}

public String getNonce() {
return sNonce;
}

public void setNonce(String nonce) {
this.sNonce = nonce;
}

public void setMinerUsername(String sMinerUsername) {
this.sMinerUsername = sMinerUsername;
}

public String getHash() {
return sHash;
}

public void setHash(String h) {
this.sHash = h;
}

public synchronized void setMerkleRoot(String merkleRoot) {
this.sMerkleRoot = merkleRoot;
}

/**
* Run this to test your merkle tree logic.
*
* @param args
*/
public static void main(String[] args) {

ArrayList<String> lstItems = new ArrayList<>();
Block oBlock = new Block();
String sMerkleRoot;

// These merkle root hashes based on "t1","t2" for two items, and then "t3","t4"
// added for four items.
String sExpectedMerkleRoot_2Items = "3269f5f93615478d3d2b4a32023126ff1bf47ebc54c2c96651d2ac72e1c5e235";
String sExpectedMerkleRoot_4Items = "e08f7b0331197112ff8aa7acdb4ecab1cfb9497cbfb84fb6d54f1cfdb0579d69";

lstItems.add("t1");
lstItems.add("t2");

// *** BEGIN TEST 2 ITEMS ***

sMerkleRoot = oBlock.computeMerkleRoot(lstItems);

if (sMerkleRoot.equals(sExpectedMerkleRoot_2Items)) {

System.out.println("Merkle root method for 2 items worked!");
}

else {
System.out.println("Merkle root method for 2 items failed!");
System.out.println("Expected: " + sExpectedMerkleRoot_2Items);
System.out.println("Received: " + sMerkleRoot);

}

// *** BEGIN TEST 4 ITEMS ***

lstItems.add("t3");
lstItems.add("t4");
sMerkleRoot = oBlock.computeMerkleRoot(lstItems);

if (sMerkleRoot.equals(sExpectedMerkleRoot_4Items)) {

System.out.println("Merkle root method for 4 items worked!");
}

else {
System.out.println("Merkle root method for 4 items failed!");
System.out.println("Expected: " + sExpectedMerkleRoot_4Items);
System.out.println("Received: " + sMerkleRoot);

}
}
}

BlockChainBasics.java

/**
* This class manages the main thread, kicks off the Blockchain management classes, and controls the UI interaction.
*/
public class BlockchainBasics {

public static String sRemoteMinerIP = null;
public static int iRemoteMinerPort = 0;

/**
* This method manages the UI interaction and spawns off the Miner and P2PServer threads.
* @param args
*/
public static void main(String[] args){

BlockchainUtil u = new BlockchainUtil();
// Kick off miner.
String sUsername = u.promptUser("Username for this miner? ");
Miner oMiner = new Miner();
oMiner.sUsername = sUsername;
Thread oMinerThread = new Thread(oMiner);
oMinerThread.start();

// Sleep here so that miner thread can get up and running completely.
u.sleep(500);

// Start server after getting port from user.
String sPort = u.promptUser("What port do you want to start server on? ");
int iPort = Integer.parseInt(sPort);
P2PServer oServer = new P2PServer(iPort);
Thread oServerThread = new Thread(oServer);
oServerThread.start();


// Sleep here so that server thread can get up and running completely.
u.sleep(500);

String sSend = u.promptUser("Send transactions to another miner (y,n)? ");

if(sSend.equals("y")){
sRemoteMinerIP = u.promptUser("Miner's IP address? " );
String sTempPort = u.promptUser("Miner's Port? ");
iRemoteMinerPort = Integer.parseInt(sTempPort);
}
// Looping Menu: create & send TX OR create only.
while(true){

String sTransaction = u.promptUser("Enter Transaction: ");

if(sSend.equals("y")) {
String sReply = P2PUtil.connectForOneMessage(sRemoteMinerIP, iRemoteMinerPort, sTransaction);
u.p("[main] Reply from server: " + sReply);
}
Miner.lstTransactionPool.add(sTransaction);
}
}
}

BlockChainUtil.java

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Scanner;

/**
* This class has utility methods used by the Blockchain logic.
*/
public class BlockchainUtil {

/**
* This method produces an SHA-256 hash of the string input.
* @param sOriginal
* @return
*/
public static synchronized String generateHash(String sOriginal){

try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] btEncodedhash = digest.digest(sOriginal.getBytes(StandardCharsets.UTF_8));

StringBuilder sb = new StringBuilder();

for (int i = 0; i < btEncodedhash.length; i++) {
sb.append(Integer.toString((btEncodedhash[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
} catch (Exception ex) {

System.out.println("Error generating hash: " + ex.getMessage());
return null;
}
}


/**
* This method can either use Scanner or JOptionPane approaches to get user input.
* @param sQuestion
* @return
*/
public String promptUser(String sQuestion){

// Using input dialog:
//return JOptionPane.showInputDialog(sQuestion);

// Using Scanner:
System.out.print(sQuestion);
Scanner oCommandInput = new Scanner(System.in);

return oCommandInput.nextLine();
}


/**
* This method allows user to avoid extra typing and efficient code, especially if this class variable is one letter
* such as u, thus:
* u.p("hello");
* @param sMessage
*/
public void p(String sMessage){
System.out.println(sMessage);
}


/**
* This is used by any thread that needs to sleep to allow updating of static variables or to alleviate
* CPU usage on continuous looping.
* @param lMillis
*/
public void sleep(long lMillis){

try{
Thread.sleep(lMillis);
}
catch(Exception ex){
// do nothing.
}
}
}
MerkelNode.java

/**
* This class simply holds a single Merkle Node's values.
*/
public class MerkleNode {


String sHash;
MerkleNode oLeft;
MerkleNode oRight;
}
Miner.java

import java.util.ArrayList;

/**
* This class runs on separate thread and manages the transaction queue and
* Block mining.
*/
public class Miner implements Runnable {

public static volatile P2PMessageQueue oIncomingMessageQueue = new P2PMessageQueue();

public static volatile boolean bAbortPoW = false;
public static volatile ArrayList<String> lstTransactionPool = new ArrayList<>();
int iBlockTxSize = 4;
public String sUsername;

/**
* PoW is where miner keeps trying incrementing nonce until hash begins with as
* many 0s as the difficulty specifies.
*
* @param oBlock
* @return
*/
public boolean doProofOfWork(Block oBlock) {

String sLeadingZero = "0";

for (int i = 1; i < oBlock.getDifficulty(); i++) {
sLeadingZero += "0";
}
  
oBlock.setNonce("0");
int temp;

while (oBlock.computeHash().startsWith(sLeadingZero) != true) {
if (bAbortPoW) {
bAbortPoW = false;
System.out.println("[miner] Aborted mining block, probably because another confirmed block received.");
return false;
} else {
temp = Integer.parseInt(oBlock.getNonce()) + 1;
oBlock.setNonce(Integer.toString(temp));
oBlock.setHash(oBlock.computeHash());

}

}
return true;
}

/**
* This thread monitors incoming messages, monitors the transaction queue, and
* mines Block if enough transactions collected. Called as part of Runnable
* interface and shouldn't be called directly by code.
*/
public void run() {

BlockchainUtil u = new BlockchainUtil();

u.p("Miner thread started.");

// *****************************
// *** Eternal Mining Loop *****
// Because miner always checking for next block to immediately work on.
while (true) {

u.sleep(500);

while (oIncomingMessageQueue.hasNodes()) {
P2PMessage oMessage = oIncomingMessageQueue.dequeue();
lstTransactionPool.add(oMessage.getMessage());
}

// Check if transaction pool full and lock if it is.
if (lstTransactionPool.size() >= iBlockTxSize) {

Block oBlock = new Block();
oBlock.setMinerUsername(sUsername);
oBlock.computeHash();
String sMerkleRoot = oBlock.computeMerkleRoot(lstTransactionPool);
oBlock.setMerkleRoot(sMerkleRoot);
boolean bMined = doProofOfWork(oBlock);

if (bMined) {

// Notify connected node.
if (BlockchainBasics.sRemoteMinerIP != null) {
P2PUtil.connectForOneMessage(BlockchainBasics.sRemoteMinerIP, BlockchainBasics.iRemoteMinerPort,
"mined");
}

u.p("");
u.p("***********");
u.p("BLOCK MINED");
u.p("nonce: " + oBlock.getNonce());
u.p("hash: " + oBlock.getHash());
u.p("");
u.p("Transactions:");
for (int x = 0; x < lstTransactionPool.size(); x++) {
u.p("Tx " + x + ": " + lstTransactionPool.get(x));
}
u.p("***********");
} else {
u.p("[miner] Mining block failed.");
}

// Clear tx pool.
lstTransactionPool.clear();
}
}
}
}
P2PMessage.java

/**
* This class holds incoming messages to this node.
*/
public class P2PMessage {

private String sMessage;

// Used for queue.
public P2PMessage next = null;

public void setMessage(String sMessage){

this.sMessage = sMessage;
}

public String getMessage(){

return sMessage;
}
}

P2PMessageQueue.java

/**
* This Queue maintains the queue of messages coming from connected clients.
*/
public class P2PMessageQueue {

private P2PMessage head = null;
private P2PMessage tail = null;


/**
* This method allows adding a message object to the existing queue.
* @param oMessage
*/
public synchronized void enqueue(P2PMessage oMessage){

if (head == null) {
head = oMessage;
tail = head;
  
}
else {
P2PMessage temp = oMessage;
tail.next = temp;
tail = temp;
}
}


/**
* This method allows removing a message object from the existing queue.
* @return
*/
public synchronized P2PMessage dequeue(){

if (head == null) {
return null;
}
else {
P2PMessage temp = head;
head = head.next;
return temp;
}
}


public boolean hasNodes(){

if (head != null)
return true;
return false;
}
}

P2PServer.java

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;


/**
* This class is a separate thread that listens for messages from connecting clients and adds messages to queue.
*/
public class P2PServer implements Runnable {


private int thisServerPort;

/**
* This constructor forces port to be passed in that is necessary for startup of ServerSocket.
* @param iPort
*/
public P2PServer(int iPort){
thisServerPort = iPort;
}


/**
* This thread listens for connecting clients and receives messages to add to Blockchain's transaction queue.
*/
public void run() {

BlockchainUtil u = new BlockchainUtil();


try (ServerSocket oServerSocket = new ServerSocket(thisServerPort)) {

System.out.println("Server is listening on port " + thisServerPort);

while(true) {
Socket oSocket = oServerSocket.accept();
u.p("[server]: New client connected: " + oSocket.getRemoteSocketAddress());

InputStream input = oSocket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));

OutputStream output = oSocket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);

// Get one time message from client.
String sReceivedMessage = reader.readLine();

u.p("[server]: Server received message: " + sReceivedMessage);

if (sReceivedMessage.startsWith("mined")) {

u.p("[server]: Block has been mined by other node.");
Miner.bAbortPoW = true;

writer.println("Server received: " + sReceivedMessage);
writer.flush();
}
else {

P2PMessage oMessage = new P2PMessage();
oMessage.setMessage(sReceivedMessage);
Miner.oIncomingMessageQueue.enqueue(oMessage);

writer.println("Server queued: " + sReceivedMessage);
writer.flush();
}
}
}
catch (IOException ex) {
u.p("[server]: Server exception: " + ex.getMessage());
ex.printStackTrace();
}
}
}
P2PUtil.java

import java.io.*;
import java.net.InetSocketAddress;
import java.net.Socket;


/**
* This class holds any utility methods needed for P2P networking communication.
*/
public class P2PUtil {


/**
* Allows a one time socket call to a server, gets reply, and then closes connection.
* @param sIP
* @param iPort
* @param sMessage
* @return
*/
public static String connectForOneMessage(String sIP, int iPort, String sMessage){

try (Socket socket = new Socket()) {
// Connect to server and try up to 5 seconds
socket.connect(new InetSocketAddress(sIP, iPort), 5000);

OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);

// Send message
writer.println(sMessage);
writer.flush();

InputStream input = socket.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));

String returnString = reader.readLine();

socket.close();

return returnString;

} catch (IOException ex) {
System.out.println("[CLIENT]: Client exception: " + ex.getMessage());
ex.printStackTrace();
}
return null;
}
}

output

Merkle root method for 2 items worked!
Merkle root method for 4 items worked!

PLEASE GIVEME THUMBUP...........


Related Solutions

Data Analytics Accounting Define Blockchain. Describe the three important facets of Blockchain. How does Blockchain impact...
Data Analytics Accounting Define Blockchain. Describe the three important facets of Blockchain. How does Blockchain impact Audit?
a) Describe value creation on platforms. How does such value creation differ from value creation in...
a) Describe value creation on platforms. How does such value creation differ from value creation in traditional organisations? (500 words) b) Use a platform of your own choice to illustrate how value creation occurs on digital platforms. (300 words)
The creation of summary information is used in businesses aspart of the organization's dashboards and...
The creation of summary information is used in businesses as part of the organization's dashboards and key performance indicators (KPIs). Describe the types of data that are summarized for KPI dashboards in the business management industry, including discussion of which forms of visualization best represent the data. Provide examples to support your ideas.
The creation of summary information is used in businesses as part of the organization's dashboards and...
The creation of summary information is used in businesses as part of the organization's dashboards and key performance indicators (KPIs). Describe the types of data that are summarized for KPI dashboards in the healthcare industry, including discussion of which forms of visualization best represent the data. Provide examples to support your ideas.
4) a) Describe value creation on platforms. How does such value creation differ from value creation...
4) a) Describe value creation on platforms. How does such value creation differ from value creation in traditional organisations? b) Use a platform of your own choice to illustrate how value creation occurs on digital platforms.
1 Describe value creation on platforms. How does such value creation differ from value creation in...
1 Describe value creation on platforms. How does such value creation differ from value creation in traditional organisations? 2 Use a platform of your own choice to illustrate how value creation occurs on digital platforms
Nosocomial infections involve all the following except
Nosocomial infections involve all the following except Multiple Choice medical and surgical asepsis help lower their occurrence. Escherichia coli and staphylococci are common infectious agents. they often involve the patient's urinary tract and surgical incisions. they are only transmitted by medical personnel.
a) Talk about Bitcoins, how does it work in terms of blockchain. and talk about the...
a) Talk about Bitcoins, how does it work in terms of blockchain. and talk about the cons and pros of bitcoins.
all financial transactions involve intermediaries. True or False?
all financial transactions involve intermediaries. True or False?
What is the type of diversification does each acquisition involve?
What is the type of diversification does each acquisition involve?
ADVERTISEMENT
ADVERTISEMENT
ADVERTISEMENT