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

Commit

Permalink
5# Initial Commit
Browse files Browse the repository at this point in the history
wallet.py
    class Wallet is no more a client.
	it create a client from class WClient to connect nodes and send data to nodes
general
    function new_job corrected
added:
    to classes Block Transaction function dict()
class Blockchain .transactions
    from now on storing tx in type of dicts using tx.dict() method
	bcs: storing in python class objects, raise problems when sending over nodes or clients
  • Loading branch information
tolgaerdonmez committed Aug 17, 2019
1 parent 4602658 commit 11374c1
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 83 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ tcoin_base/__pycache__/
venv/
utils/
deneme*
*.pem
*.pem
_*
18 changes: 18 additions & 0 deletions tcoin_base/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import datetime
import time
import pickle
import json

def timeit(method):
def timed(*args, **kw):
Expand Down Expand Up @@ -35,6 +36,10 @@ def __str__(self):
string = f"index: {self.index}\n hash: {self.hash}\n previous_hash: {self.prev_hash}\n transactions: {str(self.transactions)}\n nodes: {str(self.nodes)}\n proof: {self.proof}\n miner: {self.miner}"
return string

def dict(self):
dict = {'index':self.index, 'timestamp':self.timestamp, 'miner':self.miner, 'hash':self.hash, 'prev_hash': self.prev_hash, 'proof':self.proof, 'nodes':list(self.nodes), 'transactions':self.transactions}
return dict

DIFFICULTY = '0000'

class Blockchain():
Expand Down Expand Up @@ -94,6 +99,8 @@ def create_block(self, miner):
self.save_blockchain()

def last_block(self):
if len(self.chain) == 0:
return None
return self.chain[-1]

# @timeit
Expand Down Expand Up @@ -151,3 +158,14 @@ def __str__(self):
string += str(block) + '\n'
return string

def dict(self):
dict = {'chain':[],'length':len(self.chain)}
for block in self.chain:
dict_tx = []
for tx in block.transactions:
print(tx)
dict_tx.append(tx.dict())
block.transactions = dict_tx
dict['chain'].append(block.dict())
print(dict)
return dict
24 changes: 12 additions & 12 deletions tcoin_base/node.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .blockchain import Blockchain, Block
from .transaction import Transaction
from .wallet import WALLET_CHAIN, NEW_TX
from .wallet import Wallet, WALLET_CHAIN, NEW_TX
import socket
import select
import threading
Expand All @@ -15,7 +15,7 @@
NEW_BLOCK_MSG = 'NEW_TCOIN_BLOCK'
GET_CHAIN = 'GET_CHAIN'
SEND_CHAIN_INTERVAL = 10
HEADER_LENGTH = 100
HEADER_LENGTH = 1000

class NodeClient(socket.socket):

Expand Down Expand Up @@ -58,13 +58,14 @@ def __init__(self, ip, port, is_miner = False):
super().__init__(socket.AF_INET,socket.SOCK_STREAM)
self.bind((self.IP, self.PORT))
self.listen()

# __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 Down Expand Up @@ -101,7 +102,7 @@ def get_data(self, socket):
node_msg = pickle.loads(node_msg)
if type(node_msg) == type([]):
msg_list.append(node_msg)
if node_msg[0] == WALLET_CHAIN:
if node_msg[0] == WALLET_CHAIN or node_msg[0] == NEW_TX:
break
if len(msg_list) > 0:
return msg_list
Expand Down Expand Up @@ -149,14 +150,17 @@ def communucate_nodes(self):
pickled_chain = pickle.dumps(self.blockchain.chain)
data = f"{len(pickled_chain):<{HEADER_LENGTH}}".encode() + pickled_chain
node_client.send(data)
if self.blockchain.last_block() != None : print(self.blockchain.last_block().hash)
print('chain sent!')

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)

print(Transaction.from_dict(new_tx).sig)
self.blockchain.create_block(self.wallet.pu_ser.decode())
print(Blockchain.check_chain(self.blockchain.chain))

node_client.close()

def pop_nodes(self,nodes):
Expand Down Expand Up @@ -193,12 +197,8 @@ def __connect_nodes(self):
self.pop_nodes(excep_nodes)
self.blockchain.current_nodes.add((self.IP,self.PORT))

def new_job(self, target, args = None, daemon = False):
t = threading.Thread(target=target)
# t = Process(target=target)
def new_job(self, target, args = (), daemon = False):
t = threading.Thread(target=target, args = args)
self.threads[target] = t
if args != None:
t.args = args
t.daemon = daemon
t.start()

12 changes: 11 additions & 1 deletion tcoin_base/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,14 @@ def gather(self):
return [self.input,self.output]

def __str__(self):
return f"Sender: {self.sender[30:40].decode()}... \n Receiver: {self.receiver[30:40].decode()}... \n Amount: {self.output} Tx fee: {self.tx_fee}"
return f"Sender: {self.sender[30:40]}... \n Receiver: {self.receiver[30:40]}... \n Amount: {self.output} Tx fee: {self.tx_fee}"

def dict(self):
dict = {'sender':self.sender,'receiver':self.receiver,'input':self.input,'output':self.output,'tx_fee':self.tx_fee,'sig':self.sig}
return dict

@staticmethod
def from_dict(dict):
tx = Transaction(sender = dict['sender'],receiver = dict['receiver'], input = dict['input'], output = dict['output'])
tx.sig = dict['sig']
return tx
125 changes: 56 additions & 69 deletions tcoin_base/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import threading
import time
import sys
import errno
import errno, json
# rsa.key.PrivateKey._save_pkcs1_pem() => saves key like -----BEGIN RSA PRIVATE KEY-----
# rsa.key.PrivateKey._load_pkcs1_pem(data) => loads key from like -----BEGIN RSA PRIVATE KEY-----
WALLET_CHAIN = 'WALLET_CHAIN'
NEW_TX = 'NEW_TX'
HEADER_LENGTH = 100
HEADER_LENGTH = 1000

class OneClient(socket.socket):
class WClient(socket.socket):

def __init__(self, conn_addr):
super().__init__(socket.AF_INET,socket.SOCK_STREAM)
Expand All @@ -39,7 +39,15 @@ def connect_blockchain(self):
length = int(header.decode())
data = self.recv(length)
chain = pickle.loads(data)
# with open('s.json','w') as f:
# json.dump(chain.dict(),f,indent=4)
check = Blockchain.check_chain(chain)
if len(chain) == 0:
pass
else:
for block in chain:
print(block.hash)
print(len(chain))
if check:
return chain
else:
Expand All @@ -53,11 +61,32 @@ def connect_blockchain(self):
continue
self.close()

@staticmethod
def connect(node_addr):
one_client = WClient(node_addr)
is_connected = one_client.connect_blockchain()

if is_connected != False and type(is_connected) == type(list()):
print('Connected to Blockchain ! Ready to go !')
chain = is_connected
return chain
else:
print('Try to connect another blockchain node...')
sys.exit()

@staticmethod
def send_tx(node_addr, tx_data):
one_client = WClient(node_addr)
one_client.send(tx_data)
one_client.close()

class Wallet(socket.socket):

def __init__(self, node_addr = tuple(), pr = None, pu = None):
# __init__ Wallet
self.__BITS = 2048
self.node_addr = node_addr
print('Connecting to TCOIN BLOCKCHAIN...')
# if loaded
if pr != None:
self.public, self.private = pu, pr
Expand All @@ -68,39 +97,26 @@ def __init__(self, node_addr = tuple(), pr = None, pu = None):

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

self.chain = None
one_client = OneClient(node_addr)
is_connected = one_client.connect_blockchain()

if is_connected:
self.chain = is_connected
print('Connected to Blockchain ! Ready to go !')
else:
print('Try to connect another blockchain node...')
sys.exit()

# __init__ socket
print('Connecting to TCOIN BLOCKCHAIN...')
# creating a client for connecting blockchain
super().__init__(socket.AF_INET,socket.SOCK_STREAM)
if len(node_addr) > 0:
self.connect(node_addr)
print('connected')
self.setblocking(False)
# connect to blockchain if node_addr is given
if len(self.node_addr) != 0:
self.connect_blockchain()

def connect_blockchain(self):
self.chain = WClient.connect(self.node_addr)

def calculate_coins(self):
total = 0
plus = []
minus = []
plus = 0
minus = 0
for block in self.chain:
for tx in block.transactions:
if tx.sender == self.pu_ser:
minus.append(tx.input)
if tx.receiver == self.pu_ser:
plus.append(tx.output)
if tx.miner == self.pu_ser:
plus.append(tx.tx_fee)
total = sum(plus) - sum(minus)
for tx_dict in block.transactions:
tx = Transaction.from_dict(tx_dict)
if tx.sender == self.pu_ser.decode():
minus += tx.input
if tx.receiver == self.pu_ser.decode():
plus += tx.output
total = plus - minus
print(plus,minus)
return total

def sign(self, tx):
Expand All @@ -113,20 +129,22 @@ def sign(self, tx):

def send_tx(self, receiver_pu, amount, tx_fee):
new_tx = Transaction(
sender = self.pu_ser,
receiver = receiver_pu,
sender = self.pu_ser.decode(),
receiver = receiver_pu.decode(),
input = amount + tx_fee,
output = amount
)
sig, signed = self.sign(new_tx.gather())
if signed:
new_tx.sig = sig
new_tx = new_tx.dict()
pickled_tx = pickle.dumps(new_tx)
tx_data = [NEW_TX, pickled_tx]
tx_data = pickle.dumps(tx_data)
data = f"{len(tx_data):<{HEADER_LENGTH}}".encode() + tx_data
try:
self.send(data)
# creating a new WClient and sending new tx
WClient.send_tx(self.node_addr, data)
print('sending tx...')
return True
except:
Expand All @@ -146,39 +164,8 @@ def save_wallet_pem(self, file_path = './'):
except:
return False

def communucate_blockchain(self):
message = [WALLET_CHAIN]
message = pickle.dumps(message)
message = f"{len(message):<{HEADER_LENGTH}}".encode() + message
self.send(message)
while True:
try:
while True:
# receive things
header = self.recv(HEADER_LENGTH)
if not len(header):
print("Connection closed by the blockchain node")
sys.exit()
length = int(header.decode())
data = self.recv(length)
chain = pickle.loads(data)
check = Blockchain.check_chain(chain)
if check:
self.chain = chain
return True
else:
return False
except IOError as e:
if e.errno != errno.EAGAIN or e.errno != errno.EWOULDBLOCK:
print('Read Error !',str(e))
return False
else:
continue

def new_job(self, target, args = None, daemon = False):
t = threading.Thread(target=target)
if args != None:
t.args = args
def new_job(self, target, args = (), daemon = False):
t = threading.Thread(target=target, args = args)
t.daemon = daemon
t.start()

Expand All @@ -193,7 +180,7 @@ def verify(data, sig, public_key):

# loads private key from .pem file
@staticmethod
def load_wallet_pem(node_addr, file_path = './'):
def load_wallet_pem(node_addr = tuple(), file_path = './'):
try:
with open(file_path + 'pr_key.pem','rb') as pem_key:
private_key = rsa.pem.load_pem(pem_key.read(),'RSA PRIVATE KEY')
Expand Down

0 comments on commit 11374c1

Please sign in to comment.