def run(self): parser = argparse.ArgumentParser() parser.add_argument("command", help="type of operation: add <data> or show") parser.add_argument("--data", help="block data") args = parser.parse_args() blockchain = Blockchain() if args.data: if args.command == "add": blockchain.add_block(args.data) print("Done") if args.command == "show": iterator = blockchain.iterator() while True: block = iterator.next() print("previous_hash : " + block['previous_hash']) print("current_hash : " + block['hash']) print("data : " + block['data']) print("timestamp : " + block['timestamp']) print("nounce : " + str(block['nounce'])) print('\n') if block['previous_hash'] == "0": break
def test_is_valid_chain__valid_chain(self): other_chain = Blockchain() other_chain.add_block(other_chain.generate_new_block('new-block')) other_chain.add_block( other_chain.generate_new_block('other-new-block')) self.assertTrue(self.blockchain.is_valid_chain(other_chain.blocks))
def replace_chain(self): other_chain = Blockchain() other_chain.add_block(other_chain.generate_new_block('new-block')) new_latest_block = other_chain.add_block( other_chain.generate_new_block('other-new-block')) self.blockchain.replace_chain(other_chain.blocks) self.assertEqual(new_latest_block, self.blockchain.latest_block) self.assertEqual(3, self.blockchain.length)
def main(): chain = Blockchain() n = int(input('Enter the number of blocks to be created: ')) for x in range(n): data = str(input('Enter data for block {}: '.format(x + 1))) chain.add_block(data) chain.print_blockchain()
def main(): bc = Blockchain() bc.add_block('foo') bc.add_block('bar') bc.add_block('baz') bc.add_block('qux') for block in bc.chain: print(block)
def compute_wallet(): files = os.listdir(path + '/blockchain_wallets') files.sort() for name in files: with open(path + '/blockchain_wallets/' + name, "r") as content: print('Wallets of {}:'.format(name)) chains = read_chain(content.read()) chain = Blockchain() for block in chains: chain.add_block(block) print('{}\n'.format(chain.wallets))
def test_add_new_block(self, mock_date): mock_date.now.return_value = datetime.fromtimestamp(1515193204) bc = Blockchain() bc.add_block("TEST DATA 1", 0, 0) added_block = bc.blockchain[1] self.assertEqual( "ac34557f94c70cc7faff7d25f59907dac174e2d7d776bd60f069f682f26f7626", added_block.previous_hash) self.assertEqual(1, added_block.index) self.assertEqual("TEST DATA 1", added_block.data) self.assertEqual( "836f04540c1972054224a4c476386664d2b5c65d57fbf04033ff5385c3886faa", added_block.hash)
async def test_blockchain_received__append(self): other_blockchain = Blockchain() other_blockchain.add_block( other_blockchain.generate_new_block('new-block')) ws = await self.client.ws_connect('/ws') ws.send_str( convert_dumps({ 'type': MessageTypes.RESPONSE_BLOCKCHAIN, 'data': other_blockchain.dict() })) async for msg in ws: self.assertEqual(other_blockchain.latest_block, self.server.blockchain.latest_block) return ws.close()
def detect_incorrect(chain_directory): chains_list, filenames = block_reader.read_chains_directory( chain_directory) print("chain : status, block, transaction, amount, sender balance") for i in range(len(chains_list)): chain = chains_list[i] filename = filenames[i] block_chain = Blockchain() good = True for block in chain: added = block_chain.add_block(block) if not added: good = False if block.is_proof_ready(): print("{} : incorrect, {}, {}, {}, {}".format( filename[:-5], block.header.index, block.invalid_transactions[0][0].index, block.invalid_transactions[0][0].amount, block.invalid_transactions[0][1])) else: print("{}, Not Proved, {}".format(filename[:-5], block.header.index)) break # when there is an invalid block, no need to continue checking other blocks if good: print(filename[:-5] + ": correct")
def compute_wallets(chain_directory): chains_list, filenames = block_reader.read_chains_directory( chain_directory) block_chains = [] for chain in chains_list: block_chain = Blockchain() for block in chain: block_chain.add_block(block) block_chains.append(block_chain) for i in range(len(block_chains)): block_chain = block_chains[i] filename = filenames[i] print("------------User Balances-------------") print(filename) print(block_chain.wallets)
class Node(): def __init__(self): self.blockchain = Blockchain() self.current_block = self.blockchain.create_block() self.start_time = time.time() self.stop_flag = False def scan_tx(self): while True: if self.stop_flag: break elapse = time.time() - self.start_time if elapse > BOLCK_TIME: # generate a new block self.start_time = time.time() self.blockchain.add_block(self.current_block) new_block_log(self.current_block, self.blockchain.state) self.current_block = self.blockchain.create_block() if self.blockchain.tx_pool: tx = self.blockchain.tx_pool.popleft() from_account = self.blockchain.state.get_account( tx.from_address) tx.nonce = from_account.get_nonce() tx.hash = tx.hash_tx() # verify tx if from_account.get_balance() < tx.amount: print("invalid tx: balance not enough") else: self.current_block.add_transaction(tx) self.blockchain.state.change_state(tx) else: time.sleep(0.3) def run(self): self.thread = threading.Thread(target=self.scan_tx) self.thread.start() def stop(self): self.stop_flag = True self.thread.join()
class Node: def __init__(self): self.blockchain = Blockchain() self.memPool = [] def create_block(self): """ Creation d'un bloc avec tx de memPool """ if len(self.blockchain.blocks) != 0: self.new_block = Block( getHashBlock(self.blockchain.get_topBlock())) else: self.new_block = Block('00') for tx in self.memPool: self.new_block.transactionFiles.append(tx) self.clear_memPool() def add_fileTx(self, tx_pf): """ Ajout d'une tx dans memPool """ self.memPool.append(tx_pf) def clear_memPool(self): """ vide memPool """ self.memPool = [] def mine(self): """ Minage, renvoie bloc finalise et pret a envoyer dans bc """ if self.new_block: self.new_block.validateSelf() def add_blockToBlockchain(self): """ Ajoute un bloc a la bc """ self.blockchain.add_block(self.new_block) def process(self): """ shortcut pour exec process crea + minage + ajout dans bc """ self.create_block() self.mine() self.add_blockToBlockchain()
def test_broadcasting_block(): timestamp = datetime.utcfromtimestamp(0) node_id = uuid4() w1 = Wallet(test=True) w2 = Wallet(test=True) chain1 = Blockchain(w1.address, node_id, difficulty=1, is_test=True) chain2 = Blockchain(w2.address, node_id, difficulty=1, is_test=True) chain2.chain = chain1.chain assert chain1.chain == chain2.chain details = Details( sender=w1.address, recipient=w2.address, nonce=0, amount=0.5, timestamp=timestamp, public_key=w1.public_key.hex(), ) transaction_1 = w1.sign_transaction(details) assert Verification.verify_chain(chain1.chain) b = chain1.mine_block() result, _ = chain2.add_block(b) assert result assert Verification.verify_chain(chain1.chain) assert Verification.verify_chain(chain2.chain) chain1.add_transaction(transaction_1, is_receiving=True) chain1.mine_block() chain2.add_block(chain1.last_block) assert Verification.verify_chain(chain1.chain) assert Verification.verify_chain(chain2.chain) assert chain1.chain == chain2.chain
def create_chain_from_dump(chain_dump): blockchain = Blockchain() for idx, block_data in enumerate(chain_dump): block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"]) proof = block_data['hash'] if idx > 0: added = blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered!!") else: # the block is a genesis block, no verification needed blockchain.chain.append(block) return blockchain
def verificar_agregar_block(): block_data = request.get_json() block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"], block_data["nonce"]) prueba = block_data['hash'] adicional = Blockchain.add_block(block, prueba) if not adicional: return "El bloque fue descartado por el nodo", 400 return "Bloque agregado a la cadena", 201
class MinerNode: blockchain: Blockchain public_key: str private_key: str def __init__(self): self.blockchain = Blockchain() (pub, priv) = rsa.newkeys(512) self.public_key = pub self.private_key = priv def sign(self, block: Block): block.miner_signature = rsa.sign(block.miner_signature_bytes(), self.private_key, 'SHA-256') def add_block(self, transaction: Transaction): new_block = self.blockchain.create_new_block(transaction) self.sign(new_block) self.blockchain.add_block(new_block) def display(self): self.blockchain.display() def increment_fifteen(self): print("Incrementing transaction 15 amount by 10.") self.blockchain.increment_fifteen() def is_chain_valid(self) -> bool: return self.blockchain.is_chain_valid() def print_customer_three(self, customer_three: Customer): print("Print Customer 3 Transactions:") self.blockchain.print_customer_three(customer_three) def print_merchant_two(self, merchant_two: Merchant): print("Print Merchant 2 Transactions:") self.blockchain.print_merchant_two(merchant_two)
def create_chain_from_dump(chain_dump): generated_blockchain = Blockchain() generated_blockchain.create_genesis_block() for idx, block_data in enumerate(chain_dump): if idx == 0: continue # skip genesis block block = Block(block_data["key"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"], block_data["nonce"]) proof = block_data['hash'] added = generated_blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered!!") return generated_blockchain
def crear_chain_desde_papelera(chain_papelera): generar_blockchain = Blockchain() generar_blockchain.create_genesis_block() for idx, block_data in enumerate(chain_papelera): if idx == 0: continue # omitir el bloque genesis block = Block(block_data["index"], block_data["transactions"], block_data["timestamp"], block_data["previous_hash"], block_data["nonce"]) prueba = block_data['hash'] adicional = generar_blockchain.add_block(block, prueba) if not adicional: raise Exception("la papelera de la cade esta manipulada !") return generar_blockchain
def create_chain_from_dump(chain_dump): gen_blockchain = Blockchain() gen_blockchain.create_gen() for idx, block_data in enumerate(chain_dump): if idx == 0: continue block = Block(block_data['index'], block_data['trans'], block_data['time'], block_data['prev_hash'], block_data['nonce']) proof = block_data['hash'] added = gen_blockchain.add_block(block, proof) if not added: raise Exception("The chain dump is tampered.") return gen_blockchain
def incorrect_block(): files = os.listdir(path + '/blockchain_incorrect/') files.sort() for name in files: with open(path + '/blockchain_incorrect/' + name, 'r') as content: chains = read_chain(content.read()) chain = Blockchain() valid = True for block in chains: if block.is_proof_ready(): if check_transactions(chain, block, name): chain.add_block(block) else: valid = False break else: print( '{} is incorrect: block index is {}, this block has not been proved!' .format(name, block.header.index)) valid = False break if valid: print('{} is correct!'.format(name))
def create_chain_from_dump(dump): """ Construct chain from json dump. """ new_blockchain = Blockchain() for idx, data in enumerate(dump): if idx == 0: continue block = Block(data['index'], data['transactions'], data['timestamp'], data['pred_hash'], data['nonce']) proof = data['hash'] added = new_blockchain.add_block(block, proof) if not added: raise Exception('The chain dump was tampered!') return new_blockchain
class Server(object): def __init__(self): self.app = Sanic() self.blockchain = Blockchain() self.sockets = [] self.app.add_route(self.blocks, '/blocks', methods=['GET']) self.app.add_route(self.mine_block, '/mineBlock', methods=['POST']) self.app.add_route(self.peers, '/peers', methods=['GET']) self.app.add_route(self.add_peer, '/addPeer', methods=['POST']) self.app.add_websocket_route(self.p2p_handler, '/') async def blocks(self, request): return json(self.blockchain.blocks) async def mine_block(self, request): try: newBlock = self.blockchain.generate_next_block(request.json["data"]) except KeyError as e: return json({"status": False, "message": "pass value in data key"}) self.blockchain.add_block(newBlock) await self.broadcast(self.response_latest_msg()) return json(newBlock) async def peers(self, request): peers = map(lambda x: "{}:{}".format(x.remote_address[0], x.remote_address[1]) , self.sockets) return json(peers) async def add_peer(self, request): import asyncio asyncio.ensure_future(self.connect_to_peers([request.json["peer"]]), loop=asyncio.get_event_loop()) return json({"status": True}) async def connect_to_peers(self, newPeers): for peer in newPeers: logger.info(peer) try: ws = await websockets.connect(peer) await self.init_connection(ws) except Exception as e: logger.info(str(e)) # initP2PServer WebSocket server async def p2p_handler(self, request, ws): logger.info('listening websocket p2p port on: %d' % port) try: await self.init_connection(ws) except (ConnectionClosed): await self.connection_closed(ws) async def connection_closed(self, ws): logger.critical("connection failed to peer") self.sockets.remove(ws) async def init_connection(self, ws): self.sockets.append(ws) await ws.send(JSON.dumps(self.query_chain_length_msg())) while True: await self.init_message_handler(ws) async def init_message_handler(self, ws): data = await ws.recv() message = JSON.loads(data) logger.info('Received message: {}'.format(data)) await { QUERY_LATEST: self.send_latest_msg, QUERY_ALL: self.send_chain_msg, RESPONSE_BLOCKCHAIN: self.handle_blockchain_response }[message["type"]](ws, message) async def send_latest_msg(self, ws, *args): await ws.send(JSON.dumps(self.response_latest_msg())) async def send_chain_msg(self, ws, *args): await ws.send(JSON.dumps(self.response_chain_msg())) def response_chain_msg(self): return { 'type': RESPONSE_BLOCKCHAIN, 'data': JSON.dumps([block.dict() for block in self.blockchain.blocks]) } def response_latest_msg(self): return { 'type': RESPONSE_BLOCKCHAIN, 'data': JSON.dumps([self.blockchain.get_latest_block().dict()]) } async def handle_blockchain_response(self, ws, message): received_blocks = sorted(JSON.loads(message["data"]), key=lambda k: k['index']) logger.info(received_blocks) latest_block_received = received_blocks[-1] latest_block_held = self.blockchain.get_latest_block() if latest_block_received["index"] > latest_block_held.index: logger.info('blockchain possibly behind. We got: ' + str(latest_block_held.index) + ' Peer got: ' + str(latest_block_received["index"])) if latest_block_held.hash == latest_block_received["previous_hash"]: logger.info("We can append the received block to our chain") self.blockchain.blocks.append(Block(**latest_block_received)) await self.broadcast(self.response_latest_msg()) elif len(received_blocks) == 1: logger.info("We have to query the chain from our peer") await self.broadcast(self.query_all_msg()) else: logger.info("Received blockchain is longer than current blockchain") await self.replace_chain(received_blocks) else: logger.info('received blockchain is not longer than current blockchain. Do nothing') async def replace_chain(self, newBlocks): try: if self.blockchain.is_valid_chain(newBlocks) and len(newBlocks) > len(self.blockchain.blocks): logger.info('Received blockchain is valid. Replacing current blockchain with ' 'received blockchain') self.blockchain.blocks = [Block(**block) for block in newBlocks] await self.broadcast(self.response_latest_msg()) else: logger.info('Received blockchain invalid') except Exception as e: logger.info("Error in replace chain" + str(e)) def query_chain_length_msg(self): return {'type': QUERY_LATEST} def query_all_msg(self): return {'type': QUERY_ALL} async def broadcast(self, message): for socket in self.sockets: logger.info(socket) await socket.send(JSON.dumps(message))
from blockchain import Blockchain transaction1 = {"Sender": "Arman", "Receiver": "Hale", "Amount": 100} transaction2 = {"Sender": "Hale", "Receiver": "Ozgur", "Amount": 200} transaction3 = {"Sender": "Ozgur", "Receiver": "Arman", "Amount": 300} new_blockchain = Blockchain() new_blockchain.add_block(transaction1) new_blockchain.add_block(transaction2) new_blockchain.add_block(transaction3) new_blockchain.print_blocks()
def test_add_block(self): chain = Blockchain() chain.add_block(self.get_block("some message")) self.assertEqual(1, len(chain.blocks)) self.assertEqual("some message", chain.blocks[-1].messages[0].data)
from blockchain import Blockchain block_one_transactions = {"sender":"Alice", "receiver": "Bob", "amount":"50"} block_two_transactions = {"sender": "Bob", "receiver":"Cole", "amount":"25"} block_three_transactions = {"sender":"Alice", "receiver":"Cole", "amount":"35"} fake_transactions = {"sender": "Bob", "receiver":"Cole, Alice", "amount":"25"} local_blockchain = Blockchain() local_blockchain.print_blocks() local_blockchain.add_block(block_one_transactions) local_blockchain.add_block(block_two_transactions) local_blockchain.add_block(block_three_transactions) local_blockchain.print_blocks() local_blockchain.chain[2].transactions = fake_transactions local_blockchain.validate_chain()
class BlockchainNode(object): #socket timeout in seconds CONNECTION_LISTEN_TIMEOUT = 5 # the number of timesouts that need to occur before we ask our peers about # the blockchain SYNC_BLOCKCHAIN_TIMEOUTS = 10 def __init__(self, port, peers): self.serverhostname = None self.serverport = None self.id = None self.serversock = self.__init_server_socket(port) self.blockchain = Blockchain(self.id) self.peers = {} # map of message types to handlder functions self.handlers = { BlockchainMessage.PEER_INIT: self.__handle_peer_init_msg, BlockchainMessage.PEER_REMV: self.__handle_peer_remv_msg, BlockchainMessage.GET_BLOCKCHAIN: self.__handle_get_blockchain_msg, BlockchainMessage.FULL_BLOCKCHAIN: self.__handle_full_blockchain_msg, BlockchainMessage.NEW_BLOCK: self.__handle_new_block_msg, BlockchainMessage.GET_LATEST_BLOCK: self.__handle_get_latest_block_msg, BlockchainMessage.LATEST_BLOCK: self.__handle_latest_block_msg, BlockchainMessage.GET_MAGIC_NUM: self.__handle_get_magic_num_msg, BlockchainMessage.NEW_MAGIC_NUM: self.__handle_new_magic_num_msg } self.shutdown = False self.sync_count = 0 self.lock = threading.RLock() # fire up the node self.start(peers) # starts the blockchainnode's main server listening loop, and spawing the # mining thread as well # params: # -possiblepeers: a list of peers to establish on startup (these are passed # in from the command line) def start(self, possiblepeers): if len(possiblepeers) > 0: logging.info("establishing peers from passed in list") self.peers = self.__establish_peers(possiblepeers) else: self.blockchain.set_magic_number() logging.info("BLOCKCHAIN NODE STARTED - %s:%d" %\ (self.serverhostname, self.serverport)) while not self.shutdown: try: logging.debug("listening for peer connections") clientsock, clientaddr = self.serversock.accept() clientsock.settimeout(None) peerconn_thread = threading.Thread(target = \ self.__handlepeerconnectandrecv, args = [ clientsock ]) peerconn_thread.start() except socket.timeout: self.__maintain_bc_and_mine() self.lock.acquire() self.sync_count = (self.sync_count + 1) % 10 self.lock.release() continue except KeyboardInterrupt: logging.debug("ctrl+c pressed") self.shutdown = True continue logging.debug("peer connection listening loop ending") logging.debug("closing server socket") self.serversock.close() logging.info("notifying peers to remove me from their peer list") self.__broadcast_to_peers(BlockchainMessage.PEER_REMV) # initializes the server socket for the blockchainnode # params: # -port: the port on which the server socket should listen # -queue_size: the number of connections that will be queued # (not socket.accept()'ed) before refusing connections def __init_server_socket(self, port, queue_size=5): logging.debug("initializing server socket") # IPv4 (AF_INET) TCP (SOCK_STREAM) socket sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # allow for the socket to be reclaimed before it's TIMEWAIT # period is finished sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(("", port)) sock.settimeout(self.CONNECTION_LISTEN_TIMEOUT) addrinfo = socket.getaddrinfo("", port, socket.AF_INET, socket.SOCK_STREAM) sockinfo = addrinfo[0] self.serverhostname = sockinfo[4][0] self.serverport = sockinfo[4][1] self.id = self.serverhostname + ":" + str(self.serverport) sock.listen(queue_size) return sock # called when the socket times out in the main loop - this checks the blockchain # sends out any messages when information is needed and attempts to mine a block def __maintain_bc_and_mine(self): self.lock.acquire() logging.debug("number of peers: %d" % len(self.peers)) logging.debug("sync count = %d" % self.sync_count) if self.blockchain.magic_num == None: self.__broadcast_to_peers(BlockchainMessage.GET_MAGIC_NUM) else: if len(self.blockchain.blocks) == 0 and len(self.peers) > 0: logging.debug( "blockchain is empty but I have peers - request the blockchain" ) self.__broadcast_to_peers(BlockchainMessage.GET_BLOCKCHAIN) elif self.sync_count == 9: logging.debug("10 timeeouts - request the latest block") self.__broadcast_to_peers(BlockchainMessage.GET_LATEST_BLOCK) logging.debug("current blockchain length %d" % len(self.blockchain.blocks)) logging.debug("current blockchain: %s" % self.blockchain.blocks) newblock = self.blockchain.mine_block() if newblock != None: logging.info("new block mined:%s" % newblock) self.__broadcast_to_peers(BlockchainMessage.NEW_BLOCK, newblock) self.lock.release() # handles an incoming connection from another blockchainnode # params: # -clientsock: the client socket extracted from the accepted connection def __handlepeerconnectandrecv(self, clientsock): host, port = clientsock.getpeername() logging.info("handling peer connection from: %s:%d" % (host, port)) try: raw_msg = clientsock.recv(1024) length = struct.unpack_from("!I", raw_msg[:4])[0] bytes_recvd = len(raw_msg[4:]) logging.debug("length: %s, bytes_recvd: %d" % (length, bytes_recvd)) while bytes_recvd < length: chunk = clientsock.recv(1024) raw_msg += chunk bytes_recvd += len(chunk) logging.debug("length: %s, bytes_recvd: %d" % (length, bytes_recvd)) msg = pickle.loads(raw_msg[4:]) logging.info("received message: %s", repr(msg)) if msg.msg_type == BlockchainMessage.PEER_INIT or \ msg.msg_type == BlockchainMessage.PEER_REMV: self.handlers[msg.msg_type](msg) else: peerid = msg.senderid self.lock.acquire() peer = None if self.peers.has_key(peerid): peer = self.peers[peerid] self.lock.release() if self.handlers.has_key(msg.msg_type): self.handlers[msg.msg_type](peer, msg) else: logging.info("received unknown message type: " \ "%s - doing nothing" % (str(msg.msg_type))) else: logging.info( "peerid not an established peer - doing nothing") self.lock.release() except Exception: logging.error( "An exception occured handling connection/receving message") raise finally: logging.debug("cleaning up client socket") clientsock.close() # handles the PEER_INIT message type # params: # -message: the messsage to process def __handle_peer_init_msg(self, message): logging.debug("processing PEER_INIT message") peer = self.__peer_from_peerid(message.senderid) if not self.peers.has_key(peer.id): logging.info("storing: %s as established peer" % repr(peer)) self.lock.acquire() self.peers[peer.id] = peer self.lock.release() else: logging.debug("already established this peer: %s, ignoring" % repr(peer)) # handles PEER_REMV message type # params: # -message: the message to process def __handle_peer_remv_msg(self, message): peeridtoremove = message.senderid self.lock.acquire() if self.peers.has_key(peeridtoremove): logging.info("removing peer: %s" % (self.peers[peeridtoremove])) del self.peers[peeridtoremove] else: logging.debug( "received PEER_REMV from peer not in my list - ignoring") self.lock.release() # handles GET_BLOCKCHAIN message type # params: # -peer: the peer who sent the message # -message: the message to process def __handle_get_blockchain_msg(self, peer, message): logging.info("handling GET_BLOCKCHAIN message") self.lock.acquire() if len(self.blockchain.blocks) > 0: peer.send_msg(self.id, BlockchainMessage.FULL_BLOCKCHAIN, self.blockchain.blocks) else: logging.debug("my blockchain is empty - ignoring message") self.lock.release() # handles FULL_BLOCKCHAIN message type # params: # -peer: the peer who sent the message # -message: the message to process def __handle_full_blockchain_msg(self, peer, message): logging.info("handling FULL_BLOCKCHAIN message") listofblocks = message.data self.lock.acquire() self.blockchain.examine_peer_blockchain(listofblocks) self.lock.release() # handles NEW_BLOCK message type # params: # -peer: the peer who sent the message # -message: the message to process def __handle_new_block_msg(self, peer, message): logging.info("handling NEW_BLOCK message") newblock = message.data self.lock.acquire() if self.blockchain.validate_newblock(newblock): logging.info("new block is valid - adding") self.blockchain.add_block(newblock) else: logging.info( "new block received is not valid - request block chain from peers" ) self.__broadcast_to_peers(BlockchainMessage.GET_BLOCKCHAIN) self.lock.release() #handles GET_LATEST_BLOCK message type #params: # -peer: the peer who sent the message # -message: the message to process def __handle_get_latest_block_msg(self, peer, message): logging.info("handling GET_LATEST_BLOCK message") self.lock.acquire() latest_block = self.blockchain.get_latest_block() if latest_block == None: logging.debug("no latest block to send - ignoring") else: peer.send_msg(self.id, BlockchainMessage.LATEST_BLOCK, latest_block) self.lock.release() #handles LATEST_BLOCK message type #params: # -peer: the peer who sent the message # -message: the message to process def __handle_latest_block_msg(self, peer, message): logging.info("handling LATEST_BLOCK message") peer_latest_block = message.data self.lock.acquire() if self.blockchain.latest_block_matches(peer_latest_block): logging.info("latest block matches - I'm up to date") else: logging.info( "my latest block didn't match peers latest - requesting the blockchain" ) self.__broadcast_to_peers(BlockchainMessage.GET_BLOCKCHAIN) self.lock.release() # handles GET_MAGIC_NUM message type # params: # -peer: the peer who sent the message # -message: the message to process def __handle_get_magic_num_msg(self, peer, message): logging.info("handling GET_MAGIC_NUM message") self.lock.acquire() if self.blockchain.magic_num != None: peer.send_msg(self.id, BlockchainMessage.NEW_MAGIC_NUM, self.blockchain.magic_num) else: logging.debug("my magic num isn't set - ignoring message") self.lock.release() # handles NEW_MAGIC_NUM message type # params: # -peer: the peer who sent the message # -message: the message to process def __handle_new_magic_num_msg(self, peer, message): logging.info("handling NEW_MAGIC_NUM message") magic_num = message.data self.lock.acquire() self.blockchain.set_magic_number(magic_num) self.lock.release() # attemps to establish a connection and store references to peers # params: # -peerlist: command line supplied list of peers, each peer is in the # form <host>:<port> # returns: # -a dictionary of id's to BlockchainPeer objects def __establish_peers(self, peerlist): established_peers = {} for peer in peerlist: peer = self.__peer_from_peerid(peer) if peer != None: try: peer.send_msg(self.id, BlockchainMessage.PEER_INIT) established_peers[peer.id] = peer except socket.error as e: logging.error( "socket error sending message to potential peer: %s" % e) logging.info( "check the validity of peers passed in from the command line" ) sys.exit(1) else: raise AttributeError( "invalid peer format, expecting host:port") return established_peers # creates a BlockchainPeer object from an id (ip:port) # params: # -peerid: the string peerid to be converted to a BlockchainPeer object # returns: # -a BlockchainPeer object if peerid is valid, otherwise None def __peer_from_peerid(self, peerid): if string.count(peerid, ":") == 1: peer_split = string.split(peerid, ":", 1) peer_host = peer_split[0] peer_port = int(peer_split[1]) return BlockchainPeer(peer_host, peer_port) return None # sends a message to all known peers # params: # -msg_type: the type of message to send # -data: the data to include in the message def __broadcast_to_peers(self, msg_type, data=None): self.lock.acquire() for peer in self.peers.values(): peer.send_msg(self.id, msg_type, data) self.lock.release()
class Server(object): def __init__(self, loop, initial_peers=None): self.blockchain = Blockchain() self.peer_connections = [] self.session = None self.app = web.Application(loop=loop) self.loop = loop if initial_peers: self.connect_to_peers(initial_peers) self.app.router.add_get('/blocks', self.blocks) self.app.router.add_post('/mineBlock', self.mine_block) self.app.router.add_post('/addPeer', self.add_peer) self.app.router.add_get('/ws', self.ws_handler) async def connect_to_peers(self, peers: List[str]): if not self.session: self.session = aiohttp.ClientSession(loop=self.loop) for peer in peers: connection = await self.session.ws_connect(peer) self.peer_connections.append(connection) async def broadcast(self, msg: str): for peer_connection in self.peer_connections: print('broadcast') print(msg) await peer_connection.send_str(msg) async def blocks(self, request): return web.Response(text=self.blockchain.json(), content_type='application/json') async def mine_block(self, request): data = convert_loads((await request.read()).decode('utf-8'))['data'] new_block = self.blockchain.generate_new_block(data) self.blockchain.add_block(new_block) await self.broadcast(self.get_response_latest_msg()) print('block added ', new_block.json()) return web.Response(text=new_block.json(), content_type='application/json') async def add_peer(self, request): peer = convert_loads((await request.read()).decode('utf-8'))['peer'] await self.connect_to_peers([peer]) return web.Response(text='', content_type='application/json') async def handle_query_all(self, ws): ws.send_str( convert_dumps({ 'type': MessageTypes.RESPONSE_BLOCKCHAIN, 'data': self.blockchain.dict() })) async def handle_query_latest(self, ws): ws.send_str( convert_dumps({ 'type': MessageTypes.RESPONSE_BLOCKCHAIN, 'data': self.blockchain.latest_block.dict() })) async def handle_response_blockchain(self, ws, msg): received_blocks = convert_loads(msg.data)['data'] latest_block_received = received_blocks[-1] if latest_block_received['index'] > self.blockchain.latest_block.index: print('blockchain possibly behind. We got: {} Peer got: {}'.format( self.blockchain.length, len(received_blocks))) if self.blockchain.latest_block.hash == latest_block_received[ 'previous_hash']: print('We can append received block to our chain') self.blockchain.add_block(Block(**latest_block_received)) await self.broadcast(self.get_response_latest_msg()) elif len(received_blocks) == 1: print('We have to query the chain from our peer') await self.broadcast(self.get_query_all_msg()) else: print('Received blockchain is longer than current blockchain') self.blockchain.replace_chain(received_blocks) await self.broadcast(self.get_response_latest_msg()) await ws.send_str(msg.data) else: await ws.send_str(msg.data) def get_response_latest_msg(self) -> str: return convert_dumps({ 'type': MessageTypes.RESPONSE_BLOCKCHAIN, 'data': [self.blockchain.latest_block.dict()] }) def get_query_all_msg(self) -> str: return convert_dumps({'type': MessageTypes.QUERY_ALL}) async def ws_handler(self, request): ws = web.WebSocketResponse() await ws.prepare(request) async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = convert_loads(msg.data) if 'type' not in data: raise ValueError('Wrong message format') if data['type'] == MessageTypes.QUERY_LATEST: await self.handle_query_latest(ws) elif data['type'] == MessageTypes.QUERY_ALL: await self.handle_query_all(ws) elif data['type'] == MessageTypes.RESPONSE_BLOCKCHAIN: await self.handle_response_blockchain(ws, msg) else: raise ValueError('Unknown message type') elif msg.type == aiohttp.WSMsgType.ERROR: print('ws connection closed with exception ', ws.exception()) return ws
from blockchain import Blockchain new_transactions = [{'amount': '30', 'sender':'alice', 'receiver':'bob'}, {'amount': '55', 'sender':'bob', 'receiver':'alice'}] my_blockchain = Blockchain() my_blockchain.add_block(new_transactions) my_blockchain.print_blocks() my_blockchain.chain[1].transactions = "fake_transactions" my_blockchain.validate_chain()
B2.add_message(Message("Fourth message")) B2.add_message(Message("Fifth message", "Eve", "Steve")) B2.seal() B3 = Block() B3.add_message(Message("Sixth message")) B3.add_message(Message("Seventh Son of a Seventh Son is Iron Maiden's best album", "Me", "Everyone")) B3.seal() B4 = Block() B4.add_message(Message("Eighth message", "Bob", "Charlie")) B4.add_message(Message("Ninth message", "Charlie", "Daniels")) B4.add_message(Message("Tenth message", "Charlie", "Brown")) chain = Blockchain() chain.add_block(B1) chain.add_block(B2) chain.add_block(B3) chain.add_block(B4) print("Validating blockchain...") chain.validate() # all messages and inter-message links are valid, and all blocks and inter-block links are valid print("Serializing...") pickle.dump(chain, open('chain.p', 'wb')) print("Deserializing and validating...") chain2 = pickle.load(open('chain.p', 'rb')) chain2.validate() print("Serializing for tampering...")
import random import time from blockchain import Block, Blockchain, Transaction USERS = ['Alice', 'James', 'Smith', 'David', 'Adams', 'Isaac', 'Lewis'] SLEEP_TIME = 0 if __name__ == '__main__': chain = Blockchain() for _ in range(random.randint(1, 5)): block = Block() for _ in range(random.randint(1, 3)): sender, receiver = random.sample(USERS, k=2) transaction = Transaction(sender=sender, receiver=receiver, value=random.randint(10, 100)) block.add_transaction(transaction) time.sleep(SLEEP_TIME) chain.add_block(block) print(chain) time.sleep(SLEEP_TIME)
from block import Block from blockchain import Blockchain from config import * import random import json bc = Blockchain() bc.add_block(Block(index=1, data_dict={'token': random.randint(0, 1000)})) bc.add_block(Block(index=2, data_dict={'token': random.randint(0, 1000)})) bc.add_block(Block(index=3, data_dict={'token': random.randint(0, 1000)})) print("Is valid blockchain -> " + str(bc.chain_validator())) for c in bc.chain: print(c.info())
class TestBlockchain(unittest.TestCase): def setUp(self): self.bc = Blockchain() self.bc2 = Blockchain() def test_starts_with_genesis_block(self): self.assertEqual(self.bc.chain[0].block_hash, Block.genesis().block_hash) def test_add_new_block(self): data = 'foo' self.bc.add_block(data) self.assertEqual(self.bc.chain[-1].data, data) def test_validates_a_valid_chain(self): self.bc2.add_block('foo') self.assertTrue(self.bc.is_vaild_chain(self.bc2.chain)) self.assertTrue(self.bc.is_vaild_chain_from_json(self.bc2.to_json())) def test_bad_genesis_block_is_invalid(self): self.bc2.chain[0].data = 'bad data' self.assertFalse(self.bc.is_vaild_chain(self.bc2.chain)) self.assertFalse(self.bc.is_vaild_chain_from_json(self.bc2.to_json())) def test_bad_block_is_invalid(self): self.bc2.add_block('foo') self.bc2.chain[1].data = 'bad data' self.assertFalse(self.bc.is_vaild_chain(self.bc2.chain)) self.assertFalse(self.bc.is_vaild_chain_from_json(self.bc2.to_json())) def test_replace_the_chain_with_a_valid_chain(self): self.bc2.add_block('bar') self.bc.replace_chain(self.bc2.chain) self.assertEqual(self.bc.chain, self.bc2.chain) def test_replace_the_chain_with_a_valid_chain_json(self): self.bc2.add_block('bar') self.bc.replace_chain_from_json(self.bc2.to_json()) self.assertEqual(self.bc.to_json(), self.bc2.to_json()) def test_not_replace_with_less_chain(self): self.bc.add_block('foo') self.bc.replace_chain(self.bc2.chain) self.assertNotEqual(self.bc.chain, self.bc2.chain) def test_not_replace_with_less_chain_json(self): self.bc.add_block('foo') self.bc.replace_chain_from_json(self.bc2.to_json()) self.assertNotEqual(self.bc.to_json(), self.bc2.to_json())