You are on page 1of 7

import socket

import threading
import time
import datetime
import sys
import pickle
import json
from block import Block

def writeToLog(logEntry):
file = open("log.txt", "a")
#write the log out to a file
file.write('\n')
file.write(logEntry)
file.close()

# block strings need to be of the form:


# "block;blockNum;trans|sender|receiver|amount;timestamp;signature1|signature2"
def parseBlock(block_str):
blockValues = block_str.split(";")
blockNum = blockValues[1]

transaction_str = blockValues[2]
trans_temp = transaction_str.split("|")
sender = trans_temp[1]
receiver = trans_temp[2]
amount = trans_temp[3]
trans_L = [sender,receiver,amount]

timestamp = blockValues[3]

signatures_str = blockValues[4]
signatures_L = signatures_str.split("|")

newblock = Block(blockNum,trans_L,timestamp,signatures_L)
return newblock

def parseTransaction(transaction_str):
values = transaction_str.split("|")
sender = values[1]
receiver = values[2]
amount = values[3]
transaction_L = [sender,receiver,amount]
return transaction_L

def createTransaction():
spender = input("Who is spending?: ")
receiver = input("Who is receiving?: ")
amount = input("What is the amount?: ")
transaction = "trans|%s|%s|%s" % (spender,receiver,amount)
return transaction

# return a value from 0-3 designating which node will create next block
def getTurn():
return len(blockchain)%4

def blockToString(block):
blockNum = block.blockNumber
timestamp = block.timestamp
trans_L = block.transactions
trans_str = "trans|%s|%s|%s"%(trans_L[0],trans_L[1],trans_L[2])
sigs_L = block.signatures
sigs_str = ''
count = 0
for sig in sigs_L:
count +=1
sigs_str = sigs_str+sig
if count != len(sigs_L):
sigs_str = sigs_str+"|"
blockString = "block;%s;%s;%s;%s"%(blockNum,trans_str,timestamp,sigs_str)
return blockString

def serverThread():
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if nodeName == 'node1':
serversocket.bind((ip_dict.get('node1'), 5000))
elif nodeName == 'node2':
serversocket.bind((ip_dict.get('node2'), 5000))
elif nodeName == 'node3':
serversocket.bind((ip_dict.get('node3'), 5000))
elif nodeName == 'node4':
serversocket.bind((ip_dict.get('node4'), 5000))
serversocket.listen(5) # server socket maximum 5 connections

global newBlock
nodeTurn = ''

while True:
connection, address = serversocket.accept()
buf = connection.recv(4096)

currentTurn = getTurn()
if currentTurn == 0:
nodeTurn = 'node1'
elif currentTurn == 1:
nodeTurn = 'node2'
elif currentTurn == 2:
nodeTurn = 'node3'
elif currentTurn == 3:
nodeTurn = 'node4'

if len(buf) > 0:
msg = pickle.loads(buf)
msgValues = msg.split(";")
msgType = msgValues[0]
msg_trans_type = msgType
if len(msgType) > 9 and msgType != 'block':
msgValues = msgType.split("|")
msgType = msgValues[0]

if msgType == 'ACK':
print("ACK received %s" % (msg))
elif msgType == 'prntChain':
printBlockchain()
elif msgType == 'prntLdg':
printLedger()
elif msgType == 'yes': #block was accepted
thisNodeTurn = turn_dict.get(nodeName)
currentTurn = getTurn()
if thisNodeTurn == currentTurn:
prevBlock = blockchain[-1]
#Only add the block to the chain once
if prevBlock.blockNumber != newBlock.blockNumber:
blockchain.append(newBlock)
tmpBlockString = blockToString(newBlock)
writeToLog(" | ")
writeToLog(" V ")
writeToLog(tmpBlockString)
#Update the ledger
sender = newBlock.transactions[0]
receiver = newBlock.transactions[1]
amount = newBlock.transactions[2]
amount = int(amount)
ledger_dict[sender] -= amount
ledger_dict[receiver] += amount

elif msgType == 'block':


receivedBlock = parseBlock(msg)
#check the block for double spending
sender = receivedBlock.transactions[0]
receiver = receivedBlock.transactions[1]
amount = receivedBlock.transactions[2]
amount = int(amount)
senderBal = ledger_dict.get(sender)
if amount <= senderBal:
# serverSendMsgToAll("yes")
myStake = stake_dict.get(nodeName)
myStake = int(myStake)
if amount < myStake:
print("Transaction approved with adequate stake")
receivedBlock.signBlock(nodeName)
else:
print("Transaction looks good, but I dont have enough
stake.")
print("I will wait for the block to be sent back to me. ")
blockchain.append(receivedBlock)
tmpBlockString = blockToString(receivedBlock)
writeToLog(" | ")
writeToLog(" V ")
writeToLog(tmpBlockString)
#Update the ledger
ledger_dict[sender] -= amount
ledger_dict[receiver] += amount
#ledger_dict[nodeName] += 10 # reward for signing the block
if nodeTurn == 'node1' and nodeName != 'node1':
ledger_dict['node1'] += 30
elif nodeTurn == 'node2' and nodeName != 'node2':
ledger_dict['node2'] += 30
elif nodeTurn == 'node3' and nodeName != 'node3':
ledger_dict['node3'] += 30
elif nodeTurn == 'node4' and nodeName != 'node4':
ledger_dict['node4'] += 30
else:
print("Double spending found. Voting NO")
serverSendMsgToAll("no")
elif msgType == 'trans':
trans_L = parseTransaction(msg_trans_type)
sender = trans_L[0]
receiver = trans_L[1]
amount = trans_L[2]
amount = int(amount)
senderBal = ledger_dict.get(sender)

thisNodeTurn = turn_dict.get(nodeName)
currentTurn = getTurn()
if thisNodeTurn == currentTurn:
print("My turn to create a block!")
if amount <= senderBal:
print("Transaction approved")
#create a block
previousBlock = blockchain[-1]
tmpBlockNum = int(previousBlock.blockNumber)
newBlockNumber = tmpBlockNum+1
signatures = []
newBlock = Block(newBlockNumber,
trans_L,
datetime.datetime.now(),
signatures)
tempBlockList = [newBlock]
#Sign the block
newBlock.signBlock(nodeName)
ledger_dict[nodeName] +=10 #Reward for signing block
blockchain.append(newBlock)
tmpBlockString = blockToString(newBlock)
writeToLog(" | ")
writeToLog(" V ")
writeToLog(tmpBlockString)
ledger_dict[sender] -= amount
ledger_dict[receiver] += amount
ledger_dict[nodeName] += 20 # Reward for creating block
blockString = blockToString(newBlock)
print(blockString)
serverSendMsgToAll(blockString)
else:
print("Double Spending event found. Transaction will not be
processed.")

else:
print("Read [%s] from buffer" % (msg))
#check if its a good transaction
# if its a bad transaction do nothing
# if its a good transaction, create a block > sign block
# a. create a block
# b. sign the block
# c. prepare the block for sending
# d. send the block to the other nodes
serverSendMsgToAll("ACK")
# End Server thread

# def prepareBlock(block):
#

def serverSendMsgToAll(msg):
clientsocket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

if nodeName == 'node1':
clientsocket1.connect((ip_dict.get('node2'), 5000))
clientsocket2.connect((ip_dict.get('node3'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node2':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node3'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node3':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node2'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node4':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node2'), 5000))
clientsocket3.connect((ip_dict.get('node3'), 5000))

p = pickle.dumps(msg)
clientsocket1.send(p)
clientsocket2.send(p)
clientsocket3.send(p)

def clientSendToAll(transaction):
clientsocket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket4 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node2'), 5000))
clientsocket3.connect((ip_dict.get('node3'), 5000))
clientsocket4.connect((ip_dict.get('node4'), 5000))

p = pickle.dumps(transaction)
clientsocket1.send(p)
clientsocket2.send(p)
clientsocket3.send(p)
clientsocket4.send(p)

#Client Thread
def clientThread():
clientsocket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket3 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

if nodeName == 'node1':
clientsocket1.connect((ip_dict.get('node2'), 5000))
clientsocket2.connect((ip_dict.get('node3'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node2':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node3'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node3':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node2'), 5000))
clientsocket3.connect((ip_dict.get('node4'), 5000))
elif nodeName == 'node4':
clientsocket1.connect((ip_dict.get('node1'), 5000))
clientsocket2.connect((ip_dict.get('node2'), 5000))
clientsocket3.connect((ip_dict.get('node3'), 5000))

def printBlockchain():
print()
count = 0
blockchain_length = len(blockchain)
for block in blockchain:
count += 1
print("***************************************")
print("Block Number: %s" % (block.blockNumber))
print("Block Transactions: %s" % (block.transactions))
print("Block Timestamp: %s" % (block.timestamp))
print("Block Signatures: %s" % (block.signatures))
print("***************************************")
if count != blockchain_length:
print(" | ")
print(" | ")
print(" V ")
print()

def printLedger():
print(json.dumps(ledger_dict, indent=1))

if __name__ == "__main__":
threads = []
nodeName = sys.argv[1]

ip_dict = {
'node1': '10.142.0.10',
'node2': '10.142.0.11',
'node3': '10.142.0.12',
'node4': '10.142.0.13',
}

ledger_dict = {
'node1': 0,
'node2': 0,
'node3': 0,
'node4': 0,
'Parker': 100,
'Mike': 100,
'Jeff': 100,
'Bentley': 100,
'Alice': 100,
'Bob': 100
}

stake_dict = {
'node1': 10,
'node2': 20,
'node3': 50,
'node4': 80
}

turn_dict = {
'node1': 0,
'node2': 1,
'node3': 2,
'node4': 3
}

#make sure the log is clear.


with open('log.txt', 'w'):
pass

init_transactions = []
init_signatures = []
genesisBlock = Block(0, init_transactions,
datetime.datetime.now(),
init_signatures)

blockchain = [genesisBlock] # List to store our blockchain


timestamp = datetime.datetime.now()
writeToLog("GENESIS BLOCK:0:[]:%s:[]"%(timestamp))

if nodeName != 'client':
serverThread = threading.Thread(target=serverThread)
threads.append(serverThread)
clientThread = threading.Thread(target=clientThread)
threads.append(clientThread)
serverThread.start()
time.sleep(3) # let the server thread have time to start on all nodes
clientThread.start()
else:
while True:
print()
print("Enter integer selection (q to quit)")
print("Create Transaction 1:")
print("View Blockchain 2:")
print("View Ledger 3: ")
n = input("Please enter selection: ")

if n is '1':
print()
transaction = createTransaction()
print(transaction)
clientSendToAll(transaction)
elif n is '2':
clientSendToAll("prntChain")
elif n is '3':
clientSendToAll("prntLdg")
elif n is 'q':
break