Skip to content
This repository was archived by the owner on Apr 14, 2021. It is now read-only.

Commit

Permalink
7# Initial Commit
Browse files Browse the repository at this point in the history
now transaction fee, and miner bonus is being sent to miners :)
for example: after 5 new transaction, new block is being mined. and then sent to other nodes

improvements to test files
  • Loading branch information
tolgaerdonmez committed Aug 26, 2019
1 parent 71c0afa commit 2c2082d
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 56 deletions.
13 changes: 12 additions & 1 deletion tcoin_base/blockchain.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .transaction import Transaction
import hashlib
import datetime
import time
Expand Down Expand Up @@ -44,7 +45,8 @@ def dict(self):
# def from_dict(self):
# b = Block()

DIFFICULTY = '0000'
DIFFICULTY = '00'
MINER_BONUS = 10

class Blockchain():

Expand Down Expand Up @@ -88,6 +90,15 @@ def create_block(self, miner):

nodes = self.current_nodes.copy()
transactions = self.current_transactions.copy()

tx_fee = Transaction.calc_fee(transactions)
if tx_fee:
tx_fee = Transaction(sender = None, receiver = miner, input = tx_fee, output = tx_fee) # creating tx for miners tx_fee
transactions.append(tx_fee.dict())

miner_bonus = Transaction(sender = None, receiver = miner, input = MINER_BONUS, output = MINER_BONUS) # creating tx for miner bonus
transactions.append(miner_bonus.dict())

new_block = Block(
index = len(self.chain) + 1,
previous_hash = prev_hash,
Expand Down
102 changes: 67 additions & 35 deletions tcoin_base/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@

JOIN_MSG = 'JOIN_TCOIN_BLOCKCHAIN'
JOIN_INTERVAL = 5
NEW_BLOCK_MSG = 'NEW_TCOIN_BLOCK'
NEW_BLOCK = 'NEW_TCOIN_BLOCK'
GET_CHAIN = 'GET_CHAIN'
SEND_CHAIN_INTERVAL = 10
SEND_CHAIN_INTERVAL = 25
HEADER_LENGTH = 1000

class NodeClient(socket.socket):
Expand All @@ -23,9 +23,10 @@ def __init__(self):
super().__init__(socket.AF_INET,socket.SOCK_STREAM)

def connect_node(self, conn_addr, node_addr):
super().connect(conn_addr)
# self.setblocking(True)
try:
super().connect(conn_addr)
# self.setblocking(True)

join_msg = [JOIN_MSG,node_addr]
join_msg = pickle.dumps(join_msg)
msg = f"{len(join_msg):<{HEADER_LENGTH}}".encode() + join_msg
Expand All @@ -35,9 +36,9 @@ def connect_node(self, conn_addr, node_addr):
return False

def send_chain(self, node_addr, conn_addr, chain):
super().connect(conn_addr)

try:
super().connect(conn_addr)

pickled_chain = pickle.dumps(chain)
chain_msg = [GET_CHAIN,node_addr,pickled_chain]
chain_msg = pickle.dumps(chain_msg)
Expand All @@ -47,6 +48,18 @@ def send_chain(self, node_addr, conn_addr, chain):
except:
return False

def send_block(self, node_addr, conn_addr, block):
try:
super().connect(conn_addr)

pickled_block = pickle.dumps(block)
chain_msg = [NEW_BLOCK, node_addr, pickled_block]
chain_msg = pickle.dumps(chain_msg)
msg = f"{len(chain_msg):<{HEADER_LENGTH}}".encode() + chain_msg
self.send(msg)
except:
pass

class Node(socket.socket):

def __init__(self, ip, port, is_miner = False):
Expand All @@ -60,11 +73,9 @@ def __init__(self, ip, port, is_miner = False):

# __init__ Node
self.threads = {}
self.is_miner = is_miner
self.sending_chain = False
self.incoming_clients = LifoQueue()

self.wallet = Wallet.load_wallet_pem(file_path='./2')
# loading if already a blockchain exists
loaded_chain = Blockchain.load_blockchain((self.IP,self.PORT))
if loaded_chain:
Expand All @@ -73,24 +84,30 @@ def __init__(self, ip, port, is_miner = False):
# creating new blockchain
self.blockchain = Blockchain(self)

self.is_miner = is_miner
if self.is_miner:
self.wallet = Wallet.optioned_create_wallet()

# INIT METHODS
if self.blockchain.loaded:
self.__connect_nodes()

# Starting threads
self.new_job(target=self.get_clients)
self.new_job(target=self.communucate_nodes)
# self.new_job(target=self.send_chain)
# if self.is_miner:
# self.new_job(target=self.mine_block)
self.new_job(target=self.send_chain)
if self.is_miner:
self.new_job(target=self.mine_block)

def mine_block(self):
while True:
self.blockchain.create_block((self.IP,self.PORT))
print('\n\nNew Block Created')
# print(self.blockchain.last_block(),'\n\n')
time.sleep(1)

if len(self.blockchain.current_transactions) <= 5:
continue
self.blockchain.create_block(self.wallet.pu_ser)
for node in self.blockchain.current_nodes:
client = NodeClient()
client.send_block(node_addr = (self.IP,self.PORT), conn_addr = node, block = self.blockchain.last_block())

def get_data(self, socket):
msg_list = []
while True:
Expand Down Expand Up @@ -135,6 +152,16 @@ def communucate_nodes(self):
# if node is online => add to node list
self.blockchain.current_nodes.add(tuple(node_addr))
print(f"New node connected to blockchain!\n Node Address: {node_addr[0]}:{node_addr[1]}")
elif msg_header == NEW_BLOCK:
for msg in node_msg:
new_block = msg[2]
new_block = pickle.loads(new_block)
chain = self.blockchain.chain.copy()
chain.append(new_block)
check = Blockchain.check_chain(chain)
if check:
print('New Block received!')
self.blockchain.chain.append(new_block)
# GET_CHAIN gets chain around a period of time from other nodes for replacing
elif msg_header == GET_CHAIN:
for msg in node_msg:
Expand All @@ -156,8 +183,13 @@ def communucate_nodes(self):
elif msg_header == NEW_TX:
for msg in node_msg:
new_tx = pickle.loads(msg[1])
self.blockchain.current_transactions.append(new_tx)
print('New TX !')
tx = Transaction.from_dict(new_tx)
verify = Wallet.verify(tx)
if verify:
self.blockchain.current_transactions.append(new_tx)
print('New TX !')
else:
print('Invalid transaction !')

node_client.close()

Expand All @@ -166,22 +198,22 @@ def pop_nodes(self,nodes):
self.blockchain.current_nodes.remove(node)

def send_chain(self):
# while True:
# time.sleep(SEND_CHAIN_INTERVAL)
# if len(self.blockchain.current_nodes) - 1 == 0:
# continue
excep_nodes = []
all_nodes = self.blockchain.current_nodes
for (ip,port) in all_nodes:
if (ip,port) != (self.IP,self.PORT):
try:
client = NodeClient()
client.send_chain(node_addr = (self.IP,self.PORT), conn_addr = (ip,port),chain = self.blockchain.chain)
print('sending chain to: ', ip, port)
client.close()
except:
excep_nodes.append((ip,port)) # this is gonna stay for a while, but actually it is smthg we do not need to happen (losing nodes)
self.pop_nodes(excep_nodes)
while True:
time.sleep(SEND_CHAIN_INTERVAL)
if len(self.blockchain.current_nodes) - 1 == 0:
continue
excep_nodes = []
all_nodes = self.blockchain.current_nodes
for (ip,port) in all_nodes:
if (ip,port) != (self.IP,self.PORT):
try:
client = NodeClient()
client.send_chain(node_addr = (self.IP,self.PORT), conn_addr = (ip,port),chain = self.blockchain.chain)
print('sending chain to: ', ip, port)
client.close()
except:
excep_nodes.append((ip,port)) # this is gonna stay for a while, but actually it is smthg we do not need to happen (losing nodes)
self.pop_nodes(excep_nodes)

def __connect_nodes(self):
excep_nodes = []
Expand Down
16 changes: 15 additions & 1 deletion tcoin_base/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,18 @@ def dict(self):
def from_dict(dict):
tx = Transaction(sender = dict['sender'],receiver = dict['receiver'], input = dict['input'], output = dict['output'])
tx.sig = dict['sig']
return tx
return tx

@staticmethod
def calc_fee(transactions):
sum = 0
if len(transactions) > 0:
for tx in transactions:
if type(tx) == type(dict()):
sum += tx['tx_fee']
else:
sum += tx.tx_fee
return sum
else:
return False

35 changes: 28 additions & 7 deletions tcoin_base/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def send_tx(node_addr, tx_data):
one_client.send(tx_data)
one_client.close()

class Wallet(socket.socket):
class Wallet():

def __init__(self, node_addr = tuple(), pr = None, pu = None):
# __init__ Wallet
Expand All @@ -95,7 +95,7 @@ def __init__(self, node_addr = tuple(), pr = None, pu = None):
self.public, self.private = rsa.newkeys(self.__BITS)
print('Your Wallet has been created')

self.pu_ser = rsa.pem.save_pem(self.public._save_pkcs1_pem(),'RSA PUBLIC KEY')
self.pu_ser = (rsa.pem.save_pem(self.public._save_pkcs1_pem(),'RSA PUBLIC KEY')).decode()

# connect to blockchain if node_addr is given
if len(self.node_addr) != 0:
Expand All @@ -111,9 +111,9 @@ def calculate_coins(self):
for block in self.chain:
for tx_dict in block.transactions:
tx = Transaction.from_dict(tx_dict)
if tx.sender == self.pu_ser.decode():
if tx.sender == self.pu_ser:
minus += tx.input
if tx.receiver == self.pu_ser.decode():
if tx.receiver == self.pu_ser:
plus += tx.output
total = plus - minus
print(plus,minus)
Expand All @@ -129,8 +129,8 @@ def sign(self, tx):

def send_tx(self, receiver_pu, amount, tx_fee):
new_tx = Transaction(
sender = self.pu_ser.decode(),
receiver = receiver_pu.decode(),
sender = self.pu_ser,
receiver = receiver_pu,
input = amount + tx_fee,
output = amount
)
Expand Down Expand Up @@ -170,7 +170,12 @@ def new_job(self, target, args = (), daemon = False):
t.start()

@staticmethod
def verify(data, sig, public_key):
def verify(tx):
# tx obj of class Transaction
public_key = rsa.pem.load_pem(tx.sender,'RSA PUBLIC KEY')
public_key = rsa.PublicKey.load_pkcs1(public_key)
sig = tx.sig
data = str(tx.gather()).encode()
# rsa.verify returns the data encryption type it's sha256 for us
try:
rsa.verify(data, sig, public_key)
Expand All @@ -189,3 +194,19 @@ def load_wallet_pem(node_addr = tuple(), file_path = './'):
return False
public_key = rsa.key.PublicKey(private_key.n, private_key.e)
return Wallet(node_addr = node_addr,pr = private_key, pu = public_key)

@staticmethod
def optioned_create_wallet(node_addr = tuple()):
path = input('Path to create or load wallet: ')
if path == '':
path = './'
try_load = Wallet.load_wallet_pem(file_path=path)
if try_load: # if a wallet is loaded, return it
if node_addr:
try_load.node_addr = node_addr
try_load.connect_blockchain()
return try_load
else:
new_wallet = Wallet(node_addr = node_addr)
new_wallet.save_wallet_pem(file_path=path)
return new_wallet
7 changes: 5 additions & 2 deletions test_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def cmd():
if cmd == 'check':
print(Blockchain.check_chain(n1.blockchain.chain))
if cmd == 'mine':
n1.blockchain.create_block(n1.wallet.pu_ser.decode())
n1.blockchain.create_block(n1.wallet.pu_ser)
if cmd == 'chain':
print(len(n1.blockchain.chain))
if cmd == 'nodes':
Expand All @@ -39,7 +39,10 @@ def cmd():
if cmd == 'send':
n1.send_chain()
if cmd == 'tx':
print(n1.blockchain.current_transactions)
print(len(n1.blockchain.current_transactions))
if cmd == 'calc':
n1.wallet.chain = n1.blockchain.chain
print(n1.wallet.calculate_coins())
# for i in range(10):
# n1.blockchain.create_block(n1.wallet.pu_ser.decode())

Expand Down
28 changes: 18 additions & 10 deletions test_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,44 @@
IP = "127.0.0.1"
PORT = int(input('Port: '))
# w = input('wallet: ')
w = None

# def open_wallet():
# global w
w = Wallet.load_wallet_pem(node_addr=(IP, PORT), file_path='./')

w2 = Wallet.load_wallet_pem(file_path='./2')

# w = Wallet.load_wallet_pem(node_addr=(IP, PORT), file_path='./' + w)
# w = Wallet(node_addr=(IP, PORT))
w = Wallet.optioned_create_wallet((IP, PORT))
# w2 = Wallet.load_wallet_pem(file_path='./2')
cur_recv = None
def new_job(target, args = (), daemon = False):
t = threading.Thread(target=target, args = args)
t.daemon = daemon
t.start()

def cmd():
global w
global cur_recv

while True:
cmd = input('command:')
if cmd == 'quit':
sys.exit()
if cmd == 'tx':
# new_job(target=w.send_tx,args=(w2.pu_ser,50,0),daemon=True)
w.send_tx(w2.pu_ser,50,0)
pu = cur_recv.pu_ser
w.send_tx(pu,50,7)
if cmd == 'calc':
print(w.calculate_coins())
if cmd == 'my_tx':
for block in w.chain:
for tx in block.transactions:
if tx['receiver'] == w.pu_ser.decode():
if tx['receiver'] == w.pu_ser:
print(tx['input'],tx['output'])
if cmd == 'reconn':
w.connect_blockchain()

if cmd == 'pu':
print(w.pu_ser)
if cmd == 'save':
p = input('Save to: ')
w.save_wallet_pem(file_path='./' + p)
if cmd == 'load_recv':
p = input('load from: ')
cur_recv = Wallet.load_wallet_pem(file_path='./' + p)
new_job(cmd)

0 comments on commit 2c2082d

Please sign in to comment.