diff --git a/app.py b/app.py new file mode 100644 index 0000000..0baa8b2 --- /dev/null +++ b/app.py @@ -0,0 +1,24 @@ +import time +from flask import Flask, render_template +from network_integration import run + +app = Flask(__name__) + +""" +- List transactions that are currently not in a block. +- List blocks + +""" + + +@app.route('/') +def accueil(): + my_blockchain, network = run() + + chain = my_blockchain.chain + current_transactions = my_blockchain.current_transactions + return render_template('index.html', chain=chain, current_transactions=current_transactions) + + +if __name__ == '__main__': + app.run(port=3333, debug=True) diff --git a/block.py b/block.py index 2da5d69..e456490 100644 --- a/block.py +++ b/block.py @@ -72,10 +72,11 @@ def proof_of_work(last_block): @staticmethod def valid_block(block_to_validate, previous_block): + print('validating', block_to_validate.index, 'with prev_block', previous_block.index) previous_block_hash = Block.hash(previous_block) if block_to_validate.previous_hash != previous_block_hash: - print('block_to_validate.previous_hash != previous_block_hash') + print('block_to_validate.previous_hash != previous_block_hash', block_to_validate.previous_hash, '!=', previous_block_hash) return False # Check that the Proof of Work is correct @@ -84,6 +85,7 @@ def valid_block(block_to_validate, previous_block): block_to_validate.nonce, ' prev_nonce=', previous_block.nonce) return False + print('Block valid') return True def check_sender_stock(self, tx, nb): diff --git a/blockchain.py b/blockchain.py index 9f50417..293fc22 100644 --- a/blockchain.py +++ b/blockchain.py @@ -63,7 +63,7 @@ def chain_for_network(self): return jsonpickle.encode(self.chain) def check_sender_stock(self, tx): - #check sur le block en cours + # check sur le block en cours i = 1 nb = 0 while 1 > nb and i <= len(self.current_transactions): @@ -74,8 +74,8 @@ def check_sender_stock(self, tx): nb = nb + 1 i = i + 1 - #check sur les anciens blocs - if len(self.chain) >= 1 : + # check sur les anciens blocs + if len(self.chain) >= 1: current_block = self.last_block i = current_block.index while 1 > nb and i >= 0: @@ -94,9 +94,9 @@ def submit_transaction(self, transaction): # from the network, is a str that contains a json. if isinstance(transaction, str): transaction = jsonpickle.decode(transaction) - print('I received a new Transaction', transaction) + print('I received a new Transaction', transaction, transaction.time) else: - print("I'm sending a new Transaction", transaction) + print("I'm sending a new Transaction", transaction, transaction.time) if transaction in self.current_transactions: print('I received an transaction, but I already know it, so I ignore it.') @@ -106,18 +106,26 @@ def submit_transaction(self, transaction): raise ValueError( 'transaction parameter should be a Transaction instance.') - transaction_verification = transaction.verify_signature() and self.check_sender_stock(transaction) + is_signature_valid = transaction.verify_signature() + is_stock_valid = self.check_sender_stock(transaction) - if transaction_verification: - print("Transaction signature is valid") + if not is_signature_valid: + print("Transaction signature is invalid") + + if not is_stock_valid: + print("Transaction is impossible because stock invalid") + + if is_stock_valid and is_signature_valid: self.current_transactions.append(transaction) self.network.broadcast_transaction(jsonpickle.encode(transaction)) + # Should I mine? - # if len(self.current_transactions) == NB_TRANSACTIONS_MAX: - # self.mine() + if len(self.current_transactions) == NB_TRANSACTIONS_MAX: + self.mine() + return len(self.chain) - print("Transaction signature is invalid") + print("Transaction is invalid") return False def create_block(self, nonce, previous_hash): @@ -129,26 +137,30 @@ def create_block(self, nonce, previous_hash): """ # Why we have this OR condition? Seems useless. - block = Block(nonce, self.current_transactions, len(self.chain), - previous_hash or Block.hash(self.chain[-1])) + block = Block(nonce, self.current_transactions, len(self.chain), + previous_hash or Block.hash(self.chain[-1])) # Reset the current list of transactions self.current_transactions = [] - self.chain.append(block) - self.network.broadcast_block(jsonpickle.encode(block)) + self.submit_block(block) return block def submit_block(self, block): - print('handling block: ', block) if isinstance(block, str): block = jsonpickle.decode(block) + print("I received a new Block", block, "prev hash:", block.previous_hash) if not isinstance(block, Block): raise ValueError('block should be an instance of Block') + # If I already have the block, I ignore the received one. + if block.index == self.last_block.index: + print("I received a block, but I already have it, so I ignore it.") + return False + """ Add a Block in the Blockchain if the Block signature is valid. """ @@ -159,6 +171,12 @@ def submit_block(self, block): self.chain.append(block) + # Idk If I have to do this, but... :) + self.current_transactions = [] + + print("I'm sending a block", block) + self.network.broadcast_block(jsonpickle.encode(block)) + return True def valid_chain(self, chain): @@ -168,8 +186,6 @@ def valid_chain(self, chain): :return: True if valid, False if not """ - chain = jsonpickle.decode(chain) - previous_block = chain[0] current_index = 1 @@ -187,6 +203,24 @@ def valid_chain(self, chain): return True + def initialize_chain(self, chain_from_network): + """ + When I'm a new Node on the Network, I have to initialize my chain. + To do this, I ask the network the chain and initialize mine with this chain. + We should to something like a concensus (the largest chain win), but it's not done yet. + """ + chain = jsonpickle.decode(chain_from_network) + + # I keep my chain because its larger. + if len(chain) < len(self.chain): + False + + if self.valid_chain(chain): + print("Initialize chain: I'm taking the chain:", chain) + self.chain = chain + else: + print('Intialize chain impossible because the chain is not valid.') + def mine(self): """ Take the last Block, mine it and add it to the Blockchain. @@ -212,9 +246,11 @@ def mine(self): response = { 'message': "New Block Forged", 'index': block.index, - 'transactions': block.transactions, + # 'transactions': block.transactions, 'nonce': block.nonce, - 'previous_hash': block.previous_hash, + # 'previous_hash': block.previous_hash, } + print(response) + return response diff --git a/items_hash/8aa8fba8101433c129dc31b72b9b9cc519c1bd318cc4eb6ec62ad7c6cbacce1f.png b/items_hash/8aa8fba8101433c129dc31b72b9b9cc519c1bd318cc4eb6ec62ad7c6cbacce1f.png new file mode 100644 index 0000000..8bf133e Binary files /dev/null and b/items_hash/8aa8fba8101433c129dc31b72b9b9cc519c1bd318cc4eb6ec62ad7c6cbacce1f.png differ diff --git a/apple.png b/items_hash/a3fcfed88aebd3ecbc53f93b78685b9c6bd96b717893a161897abbe42f58bef9.png similarity index 100% rename from apple.png rename to items_hash/a3fcfed88aebd3ecbc53f93b78685b9c6bd96b717893a161897abbe42f58bef9.png diff --git a/items_hash/d12506e3e77f4243271a3461b0ccba92d5ed24857f319befc8f90b29f57b185f.png b/items_hash/d12506e3e77f4243271a3461b0ccba92d5ed24857f319befc8f90b29f57b185f.png new file mode 100644 index 0000000..4d49c5a Binary files /dev/null and b/items_hash/d12506e3e77f4243271a3461b0ccba92d5ed24857f319befc8f90b29f57b185f.png differ diff --git a/network/network.py b/network/network.py index 353c442..c80bd26 100644 --- a/network/network.py +++ b/network/network.py @@ -6,16 +6,18 @@ class Network: - def __init__(self): - self.node = Node("192.168.1.82", True) - self.nodes = [] + def __init__(self, test=False): self.blockchain = None - # Thread management - self._running = True - self.t1 = threading.Thread(target=self.receiv) - self.t1.start() - self._broadcast_ping() + if test == False: + self.node = Node("192.168.43.183", True) + + self.nodes = [Node("192.168.43.59"), Node("192.168.43.161"), Node("192.168.43.32")] + # Thread management + self._running = True + self.t1 = threading.Thread(target=self.receiv) + self.t1.start() + self._broadcast_ping() def stop(self): self._running = False @@ -35,16 +37,16 @@ def broadcast_ask_chain(self): # Done for nodeList in self.nodes: self.node.send("-c ", nodeList, "") - def _broadcast_ping(self): #Not use - nodeBroadcast = Node("192.168.1.62") + def _broadcast_ping(self): # Done myNodeToSend = jsonpickle.encode(self.node) - self.node.send("-p ", nodeBroadcast, myNodeToSend) + for nodeList in self.nodes: + self.node.send("-p ", nodeList, myNodeToSend) def receiv(self): print("ready to receiv") while self._running is True: - data, addr = self.node.my_socket.recvfrom(4096) + data, addr = self.node.my_socket.recvfrom(65536) cureNode = addr @@ -52,7 +54,8 @@ def receiv(self): if myData[:3] == "-c ": # Done # Retourne le JSON de la chaine - self.node.send("-ac", cureNode, self.blockchain.chain_for_network) + self.node.send("-ac", cureNode, + self.blockchain.chain_for_network) elif myData[:3] == "-n ": # Done print("I received a Node") @@ -89,7 +92,7 @@ def receiv(self): notFind = False elif myData[:3] == "-ac": # En suspend - some = None + self.blockchain.initialize_chain(myData[3:len(myData)]) elif myData[:3] == "-ap": # Done nodeReceiv = jsonpickle.decode(myData[3:len(myData)]) @@ -103,5 +106,6 @@ def receiv(self): if notFind: print("Connecting to a new Node: ", nodeReceiv.host) + self.node.send("-c ", Node(addr[0]), "") self.nodes.append(nodeReceiv) notFind = False diff --git a/network_integration.py b/network_integration.py index 5727988..17a665e 100644 --- a/network_integration.py +++ b/network_integration.py @@ -1,21 +1,36 @@ from blockchain_factory import blockchain_factory from wallet import Wallet from transaction import Transaction +from init_transactions import hashImg import time -bc, network = blockchain_factory() +def run(): + appleHash = hashImg('./items/apple.png') -time.sleep(5) + bc, network = blockchain_factory() -wallet = Wallet() -wallet2 = Wallet(1024, True) -transaction = Transaction(wallet.address, wallet2.address, "bonjour") -transaction2 = Transaction(wallet.address, wallet2.address, "bonjour2") -transaction3 = Transaction(wallet.address, wallet2.address, "bonjour3") + time.sleep(5) -transaction.sign(wallet) + wallet = Wallet(testDatas=True) + wallet2 = Wallet(testDatas=True) -bc.submit_transaction(transaction) -bc.submit_transaction(transaction2) -bc.submit_transaction(transaction3) \ No newline at end of file + transaction = Transaction(wallet.address, wallet2.address, appleHash) + transaction2 = Transaction(wallet.address, wallet2.address, appleHash) + transaction3 = Transaction(wallet.address, wallet2.address, appleHash) + + transaction.sign(wallet) + transaction2.sign(wallet) + transaction3.sign(wallet) + + bc.submit_transaction(transaction) + bc.submit_transaction(transaction2) + bc.submit_transaction(transaction3) + + print("Les transaction : ", bc.current_transactions) + + return bc, network + + +if __name__ == '__main__': + run() diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..bd3256b --- /dev/null +++ b/templates/index.html @@ -0,0 +1,78 @@ + + + + + + + + + My blockchain + + + +
+ + + {% for block in chain %} + + + + + + + {% endfor %} + + + {% for block in chain %} + + + + + + + + + {% endfor %} + +
Creation timePrevious hashNumber of transactionstransactions
{{ block.timestamp }}{{ block.previous_hash }} + {{ block.transactions | length }} + {% for transaction in block.transactions %} + {{ transaction.value }} - {{ transaction }} + {% endfor %} +
+ + + +
+
+ + + + + diff --git a/test_blockchain.py b/test_blockchain.py index 79549ff..38a0f80 100644 --- a/test_blockchain.py +++ b/test_blockchain.py @@ -1,16 +1,25 @@ +from init_datas import creator_address from blockchain import Blockchain from wallet import Wallet from client import Client from init_transactions import hashImg from transaction import Transaction +from block import Block, HASH_GENESIS_BLOCK +from network.network import Network -from init_datas import creator_address +network = Network(test=True) -blockchain = Blockchain() + +blockchain = Blockchain(network) wallet = Wallet() guy_wallet = Wallet(1024, True) + +def test_genesis_block(): + assert Block.hash(blockchain.chain[0]) == HASH_GENESIS_BLOCK + + def test_submit_transaction(): transaction = Client.generate_transaction( wallet, guy_wallet.address, 10) @@ -43,11 +52,12 @@ def test_chain_for_network(): def test_valid_chain(): - s = blockchain.chain_for_network + s = blockchain.chain valid = blockchain.valid_chain(s) assert valid == True + def test_check_sender_stock(): testWallet = Wallet(testDatas=True) appleHash = hashImg('./items/apple.png') diff --git a/test_transaction.py b/test_transaction.py index ce41f46..ca230dc 100644 --- a/test_transaction.py +++ b/test_transaction.py @@ -1,5 +1,6 @@ from transaction import Transaction + def test_equality(): sender = '@sender_addr' receiv = '@receiv_addr' @@ -13,8 +14,10 @@ def test_equality(): print(t1, t2) t3 = Transaction(sender, receiv, 55) - assert t1 == t2 + # because we have timestamp uniq id + assert t1 != t2 assert t1 != t3 + assert t1 == t1 assert t1 in transactions assert not t3 in transactions