def test_adding_messages_links_them_correctly(self): msg1 = Message("first") msg2 = Message("second") block = Block() block.add_message(msg1) block.add_message(msg2) self.assertEqual(msg2.prev_hash, msg1.hash)
def validate_block(self, block: Block) -> bool: """Validate a new block. Conditions: - the block has proof of work - the block is either the genesis block or it has the previous blocks header - the block does not contain the same utxo spent twice - there is at most one coinbase tx and it is valid - the block does not spend more than the utxo it claims - the block only spends output in the UTXO set for which it has the public key """ if not block.header.has_proof_of_work(): return False if len(self.blockchain ) > 0 and not block.header.prev_block_hash == hash( self.blockchain[-1]): return False if not block.no_internal_double_spend( ) or not block.one_valid_coinbase(): return False if not self.UTXO_set.no_overspend( block) or not self.UTXO_set.only_spendable_input(block): return False return True
def transaction(): form=TransactionForm() # current_user.balance=10000 # db.session.commit() if form.validate_on_submit(): The_one=User.query.filter_by(username=form.receiver.data).first() The_two=User.query.filter_by(username=form.sender.data).first() if current_user.balance>=int(form.amount.data) and int(form.amount.data)>0 and current_user.balance>=0 and The_one!=None and The_two!=None and The_two.username==current_user.username : amount=form.amount.data data=str(form.sender.data)+str(form.receiver.data) block=Block(number=amount,data=data) blockchain=Blockchain() blockchain.mine_block(block) block_=Block_(amount=amount,data=data,hash=block.hash(),nonce=block.nonce,previous_hash=block.previous_hash) db.session.add(block_) db.session.commit() flash("Your transaction is Successfull!") for ock in Block_.query.all(): if ock.id!=1: ock.previous_hash=a db.session.commit() a=ock.hash current_user.balance-=int(form.amount.data) The_one.balance+=int(form.amount.data) # for testing purpose current_user.balance=10000 db.session.commit() else: flash('Transaction not granted') return render_template('transaction.html',form=form)
def test_is_valid_new_block_correctness(self): timestamp = str(round(time.time() * 1000)) previous_block = self.chain.get_latest_block() correct_block = Block( 1, self.chain.calculate_hash(1, previous_block.hash, timestamp, "The correct block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The correct block") incorrect_index = Block( 2, self.chain.calculate_hash(2, previous_block.hash, timestamp, "The incorrect block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The incorrect block") incorrect_hash = Block( 1, self.chain.calculate_hash( 1, hashlib.sha256('hi'.encode('utf-8')).hexdigest(), timestamp, "The correct block"), self.chain.get_latest_block().hash, int(round(time.time() * 1000)), "The correct block") self.assertTrue( self.chain.is_valid_new_block(correct_block, self.chain.get_latest_block())) self.assertFalse( self.chain.is_valid_new_block(incorrect_index, self.chain.get_latest_block())) self.assertFalse( self.chain.is_valid_new_block(incorrect_hash, self.chain.get_latest_block()))
def __3lv_blckchn_part_handler(self,hightest_msg,body_id): reply = None peer = None if hightest_msg['id'] == 1: # ask for number of blocks and last hash peer = hightest_msg['data']['from'] self.extra('[%s][%s] %s -- BLCKCHN 1 -- %s'%(time.ctime(),body_id,peer,msg)) reply = { 'part':conf.BLCKCHN_PART_ID, 'id':2, 'data':{ 'from':self.my_name, 'count':self.blockchain.count(), 'hash':self.blockchain.last_hash(), } } elif hightest_msg['id'] == 2: # we get number of blocks (count) and last hash (hash) peer = hightest_msg['data']['from'] self.extra('[%s][%s] %s -- BLCKCHN 2 -- %s'%(time.ctime(),body_id,peer,msg)) count = hightest_msg['data']['count'] last_hash = hightest_msg['data']['last_hash'] if count > self.blockchain.count(): reply = { # ask for blocks 'part':conf.BLCKCHN_PART_ID, 'id':3 , 'data':{ 'from':self.my_name, 'max':self.blockchain.count(), 'min':count, } } elif hightest_msg['id'] == 3: # we get request for blocks from (min) till (max) peer = hightest_msg['data']['from'] self.extra('[%s][%s] %s -- BLCKCHN 3 -- %s'%(time.ctime(),body_id,peer,msg)) _min = hightest_msg['data']['min'] _max = hightest_msg['data']['max'] blocks = [] for i in range(_min,_max): blocks.append(self.blockchain.blocks[i]._export()) reply = { # ask for blocks 'part':conf.BLCKCHN_PART_ID, 'id':4, 'data':{ 'from':self.my_name, 'blocks':blocks } } elif hightest_msg['id'] == 4: # we get list of blocks peer = hightest_msg['data']['from'] self.extra('[%s][%s] %s -- BLCKCHN 4 -- %s'%(time.ctime(),body_id,peer,msg)) blocks = hightest_msg['data']['blocks'] try: for i in blocks: blck = Block() blck._import(i) self.blockchain.add_block(blck) except Exception as e: self.log('ERROR : incoming blocks damaged %s'%e) if self.reply != None: self.__send_3lv_(peer,reply)
def test_add_block_invalid(self): block = Block(self.blockchain.latest_block.index, self.blockchain.latest_block.hash, datetime.utcnow().timestamp(), 'new-block', None) block.hash = Blockchain.calculate_hash_for_block(block) self.blockchain.add_block(block) self.assertNotEqual(block, self.blockchain.latest_block)
def create_genesis_block(self): """ A function to generate genesis block and appends it to the chain. The block has index 0, previous_hash as 0, and a valid hash. """ genesis_block = Block(0, [], time.time(), "0") genesis_block.hash = genesis_block.compute_hash() self.chain.append(genesis_block)
def main(): parser = argparse.ArgumentParser( description="Tool for extracting transactions from " "ICON blockchain using filter criterias. " "Transactions of different filtercriteria will " "be written to seperate .csv files.") parser.add_argument('--leveldb', metavar='path', type=str, nargs=1, help='Path to your local node\'s leveldb.') parser.add_argument('--first-block', metavar='start', type=int, nargs=1, help='First block to extract transactions from') parser.add_argument('--last-block', metavar='end', type=int, nargs=1, help='Last block to extract transactions from') parser.add_argument( '--filter', choices=["delegation", "claimiscore", "staking", 'iconbet'], type=str, nargs='+', help='Transactions to extract from the blockchain') parser.add_argument('--output', metavar='path', type=str, nargs=1, default="./output/", help='Output folder') parser.add_argument( '--syncronize', action='store_true', help= "Syncronize previously written csv files up to current block height") args = parser.parse_args() print(args) filter_criteria = {} for criteria in args.filter: filter_criteria[criteria] = True ## TODO ## Create csv files --> list of fileobjects? # Loop through all blocks and extract transactions according to filter criteria blocks = range(args.first - block, args.last - block + 1) counter = 0 for block in blocks: block = Block(block) filtered_transactions = block.filter_transactions( block.transaction_list, **filter_criteria)
def create_block(self, transactions: list[Transaction]) -> Block: """Create a new block from a list of transactions.""" cb_tx: Transaction = self.create_coinbase_tx(self.address.pubkey, 50) if len(self.address.headers) == 0: assert (len(transactions) == 0 ) # no possible non-coinbase transactions in genesis block return Block([cb_tx]) return Block([cb_tx] + transactions, hash(self.address.headers[-1]))
def mine_block(self): # if no blocks, create the genesis block if len(self.blockchain.blocks) == 0: self.blockchain.create_genesis_block() logger.info('Genesis block created!') return True else: # calculate what the next diffculty should be new_block_difficulty = self.blockchain.compute_next_difficulty() # add all transactions from the transaction pool to this block tx_list = [] for tx in self.transaction_pool: tx_list.append(tx) # create the block block_candidate = Block() # STEP1 - block_candidate is the new block we're mining! lets fill its fields with # the correct values. # create the coinbase transaction, awards BLOCK_REWARD coins to ourselves (the miner) coinbase_tx = Transaction(from_pubkey='COINBASE', to_pubkey=self.address(), amount=BLOCK_REWARD) # sign the coinbase transaction self.sign_transaction(coinbase_tx) # add it to the list of transactions for this block block_candidate.transactions.append(coinbase_tx) logger.info('Mining block %d ... [difficulty=%d] [target=%s]' % (block_candidate.height, block_candidate.difficulty, block_candidate.difficulty_to_target())) # find the correct nonce for this block, this takes a while to calculate, hopefully BLOCK_TIME_IN_SECONDS self.find_nonce(block_candidate) # if find_nonce terminated because we received a new block discard the block if self.new_block_received: logger.info('Skipped block %d' % block_candidate.height) # reset the flag self.new_block_received = False # well, we did not mine anything return False else: # try adding the block to our current blockchain using add_block if not self.blockchain.add_block(block_candidate): # add_block failed! something was not right in the new block logger.error('Mined block %d discarded!' % block_candidate.height) return False else: # clear the transaction pool. Those transactions are now safely in a block in the blockchain self.transaction_pool = [] logger.info('Block %d mined!' % block_candidate.height) # mining successful! return True
def get_blocks(self, *args): L = [] for arg in args: b = Block() b.add_message(Message(arg)) L.append(b) for i, block in enumerate(L): block.link(L[i-1]) if i > 0 else None block.seal() return L
def block_serializer(data): block = Block(index=data['index']) for transaction in data['transactions']: block.add_transaction(sender=transaction['sender'], receiver=transaction['receiver'], amount=transaction['amount'], timestamp=transaction['timestamp'], thash=transaction['hash']) block.hash = data['hash'] return block
def mineBlock(self, t1, t2): prevHash = None depth = 0 if (len(self.blockchain) > 0): prevHash = self.calcPrevHash(self.blockchain[len(self.blockchain) - 1]) depth = len(self.blockchain) b = Block(t1, t2, prevHash, depth) b.mine() return b
def test_create_block(self): index = 0 nonce = 0 previous_hash = 'New York' timestamp = '1944-03-16' transactions = ['Andrew Tanenbaum'] b = Block() block_dummy = b.create_new(index,previous_hash,timestamp,transactions) return block_dummy
def _try_to_mine(self): fee = float(BankSettings.objects.all()[0].fee) valid_transactions = [] for tid, not_mined_transaction in self.shell.blockchain.not_mined_transactions.items(): if (len(valid_transactions) < self.shell.block_size - 1 and not_mined_transaction.is_valid(self.shell.blockchain.all_utxos, self.shell.blockchain.minimum_transaction, fee)): valid_transactions.append(not_mined_transaction) if len(valid_transactions) < self.shell.block_size - 1: return block = Block(self.shell.blockchain.last_block_hash()) value = float(BankSettings.objects.all()[0].reward) + fee * (self.shell.block_size - 1) coinbase = Transaction('', self.bank.wallet.get_keys()[0], value=value, inputs=[]) block.add_transaction(transaction=coinbase, all_utxos=self.shell.blockchain.all_utxos, minimum_transaction=self.shell.blockchain.minimum_transaction, fee=fee, should_check=True, is_coinbase=True) self.shell.blockchain.append_transaction(coinbase) for valid_transaction in valid_transactions: block.add_transaction(valid_transaction, self.shell.blockchain.all_utxos, self.shell.blockchain.minimum_transaction, fee=fee, should_check=True) block.mine(BankSettings.objects.all()[0].difficulty) print('block mined: {}.'.format(block.calculate_hash())) self.shell.blockchain.append_block(block)
def append_new_block(self, mine=True): block = Block(self.last_block_hash()) if mine: block.mine(self.difficulty) print("Block mined: " + block.hash) self.append_block(block) return block
def new_transaction(self, sender_wallet: Wallet, receiver_wallet: Wallet, amount): if not self.current_block: self.current_block = Block(self.blockchain.last_block_hash()) transaction = sender_wallet.send_funds(self.all_utxos, receiver_wallet.public_key_str, amount) self.current_block.add_transaction(transaction, self.all_utxos, 0.001) if len(self.current_block.transactions) == self.central_bank.number_of_transactions_in_block: self.blockchain.append_block(self.current_block, True) self.current_block = None
def chain_deserializer(chain_json): chain = [] for block_json in chain_json: transactions = transactions_deserializer(block_json['transactions']) block_to_append = Block(block_json['timestamp'], transactions, block_json['prev_hash']) block_to_append.nonce = block_json['nonce'] block_to_append.hash = block_json['hash'] chain.append(block_to_append) return chain
def mine_transactions(self): new_block = Block(prev_hash=self.blockchain.chain[-1].hash, transactions=self.unconfirmed_txn[0:5]) new_block.mine_block(self.reward_address) self.blockchain.chain.append(new_block) # announce mined block on the network for peer_address in self.network: data = {"block": json.dumps(new_block.__dict__)} requests.post(peer_address + "/add_block", data=json.dumps(data), headers=headers)
async def ws_handler(self, request): ws = web.WebSocketResponse() await ws.prepare(request) async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: msg = json.loads(msg.data) if msg["type"] == MessageType.REGISTER_ME: # 새로운 노드 연결 node = msg["nodeinfo"] await self.connect_to_peers([node]) self.nodes.append(node) elif msg["type"] == MessageType.REQUEST_NODE_LIST: # 노드 목록 알려줌 await ws.send_json(self.nodes) elif msg["type"] == MessageType.REQUEST_MAKE_BLOCK: # 블록 생성함 await asyncio.sleep(random.randint(3, 10)) # 해시 푸는 속도라고 가정하자 tr_info = msg["data"] _lastblock = self.chain.get_latest_block() new_block = Block(_lastblock.index + 1, tr_info["data"], tr_info["timestamp"], _lastblock.hash, '') new_block.calculate() if new_block.index > self.chain.latest_block.index: self.chain.add_block(new_block) # 컨펌 받기 await self.broadcast( json.dumps({ "type": MessageType.REQUEST_CONFIRM_BLOCK, "chain": self.chain.json() })) await ws.send_str("[+] Well done !") elif msg["type"] == MessageType.REQUEST_CONFIRM_BLOCK: # 블록 생성 컨펌해줌 blocks = [ Block.from_dict(j) for j in json.loads(msg["chain"]) ] if len(blocks) > self.chain.length: if BlockChain.is_valid_chain(blocks): self.chain.blocks = blocks else: pass elif msg.type == aiohttp.WSMsgType.Error: print('ws connection closed with exception ', ws.exception()) return ws
def test_block(): genesis_block = Block( **{ 'version': 0, 'previous_block_hash': None, 'merkle_tree_hash': None, 'timestamp': 1507593600, 'nbits': 504382016, 'nonce': 0 }) block_with_nonce = genesis_block.mine() assert block_with_nonce.nonce != genesis_block.nonce assert block_with_nonce._base_hash == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\r\xdcY@B\x10\x1e' assert block_with_nonce.nonce == 144875
def get_user_block(username): blockchain_sql = Table("blockchain", "number", "hash", "previous", "data", "nonce") user_blockchain = Blockchain() for b in blockchain_sql.getall(): data = b.get('data').split("-->") if username == data[0]: user_blockchain.add( Block(int(b.get('number')), b.get('previous'), b.get('data'), b.get('nonce'))) if username == data[1]: user_blockchain.add( Block(int(b.get('number')), b.get('previous'), b.get('data'), b.get('nonce'))) return user_blockchain
def generate_block(): index = request.form['index'] content = request.form['content'] previous = request.form['previous'] transaction = Transaction(satoshi.private_key, satoshi.public_key, str(content)) block = Block(int(index), [transaction], previous, 0) block.timestamp = datetime.datetime(2009, 1, 10, 12, 00) transaction.timestamp = datetime.datetime(2009, 1, 10, 12, 00) response = {'hash': block.calculate_hash() } return jsonify(response), 200
def print_result(result, elapsed, checkpoint1, checkpoint2, blockchain): for i in range(len(result)): print( "SmartContract number: " + str(i + 1) + " resulted the following ['used optimization algorithm', Optimal Schedule time, SC run time]:" ) if result[i][1] < checkpoint1: checkpoint1 = result[i][1] checkpoint2 = result[i][0] print(result[i]) print( "Best Optimal Schedule is provided by a Miner who ran " + checkpoint2 + " algorithm, with >> \napproximate execution time of the proposed assignment = " + str(checkpoint1)) print('Optimal Schedules received from miners in approximately ' + str({round(elapsed, 3)}) + 'second(s)') print('Total time from TPC receiving the tasks from EndUsers>>' '\n>>until result are back to TPC from cloud ' + str(round(elapsed + checkpoint1, 3)) + 'second(s)') print( "The following blocks were added to the publicly available blockchain:" ) for i in range(len(result)): blockchain.mine(Block(result[i])) print("*****\nBlock no." + str(blockchain.blocks[i + 1].blockNo) + " is " + str(blockchain.blocks[i + 1].transactions)) print("timestamp of Block no." + str(blockchain.blocks[i + 1].blockNo) + " is " + str(blockchain.blocks[i + 1].timestamp)) print("nonce of Block no." + str(blockchain.blocks[i + 1].blockNo) + " is " + str(blockchain.blocks[i + 1].nonce)) print("The hash of Block no." + str(blockchain.blocks[i + 1].blockNo) + " is " + str(blockchain.blocks[i + 1].hash()) + "\n*****")
def main(): print("Creating the blockchain...") data = input( "Creating the genesis block. What would you like its data to be?: ") genesis_block = Block("0", data) chain = Blockchain(genesis_block) print("Genesis block hash: ", genesis_block.hash) action = input( "What would you like to do? To get a list of options, type 'help': " ).lower() while (action != "quit" and action != "exit"): if action == "help": print_help() elif action == "verify": if chain.check_integrity(): print("The current blockchain is valid.") else: print("The current blockchain is not in a valid state.") elif action == "mine": chain.mine_block() elif action == "print": chain.print_chain() else: print( "Hmmmm, not sure what you meant. Type `help` to get a list of comamands." ) action = input("What would you like to do? ").lower()
def transfer_funds(sender_username, recipient_username, dispatched_amount): try: dispatched_amount = float(dispatched_amount) except ValueError: raise InvalidTransactionException('Invalid Transaction.') if dispatched_amount > fetch_balance( sender_username) and sender_username != 'BANK': raise InsufficientFundsException( 'Insufficient Funds: you do not have enough funds in your balance.' ) elif sender_username == recipient_username: raise InvalidTransactionException( 'Invalid Transaction: sender can\'t be the recipient.') elif dispatched_amount < 0.00: raise InvalidTransactionException( 'Invalid Transaction: you can\'t send or receive negative funds.') elif dispatched_amount == 0.00: raise InvalidTransactionException( 'Invalid Transaction: you can\'t send or receive funds equal to 0.00 ZBT' ) elif is_new_user(recipient_username): raise InvalidTransactionException( 'Invalid Transaction: user does not exist.') blockchain = fetch_blockchain() number = len(blockchain.chain) + 1 data = '%s]==>%s]==>%s' % (sender_username, recipient_username, dispatched_amount) blockchain.mine(Block(number, data=data)) synchronise_blockchain(blockchain)
def mine(): last_block = blockchain[len(blockchain) - 1] last_proof = last_block.data['proof-of-work'] this_nodes_transactions.append({ "from": "network", "to": miner_address, "amount": 1 }) proof = proof_of_work(last_proof) new_block_data = { "proof-of-work": proof, "transactions": list(this_nodes_transactions) } new_block_index = last_block.index + 1 new_block_timestamp = date.datetime.now() last_block_hash = last_block.hash this_nodes_transactions[:] = [] mined_block = Block(new_block_index, new_block_timestamp, new_block_data, last_block_hash) blockchain.append(mined_block) return json.dumps({ "index": new_block_index, "timestamp": str(new_block_timestamp), "data": new_block_data, "hash": last_block_hash }) + "\n"
def send_money(sender, recipient, amount): # Verify that the amount is an integer or floating value try: amount = float(amount) except ValueError: raise InvalidTransactionException("Invalid Transaction.") # Verify that the user has enough money to send # (exception if it is the BANK) if amount > get_balance(sender) and sender != "BANK": raise InsufficientFundsException("Insufficient Funds.") # Verify that the user is not sending money to # themselves or amount is less than or 0 elif sender == recipient or amount <= 0.00: raise InvalidTransactionException("Invalid Transaction.") # Verify that the recipient exists elif isnewuser(recipient): raise InvalidTransactionException("User Does Not Exist.") # Update the blockchain and sync to mysql blockchain = get_blockchain() number = len(blockchain.chain) + 1 data = f"{sender}-->{recipient}-->{amount}" blockchain.mine(Block(number, data=data)) sync_blockchain(blockchain)
def accept(bal, myVal): print("In Accept") if myVal is None: PREV_BLOCK = BLOCKCHAIN.tail prev_hash = "None" if PREV_BLOCK is not None: str_to_be_hashed = str(PREV_BLOCK.operation) + str( PREV_BLOCK.nonce) + str(PREV_BLOCK.prev_hash) prev_hash = str( hashlib.sha256(str_to_be_hashed.encode()).hexdigest()) operation = QUEUE.get() op = operation[0] client = operation[1] CLIENT_STREAM[bal] = CLIENT_SOCKETS[client] # Calculate nonce h = "----" nonce = 0 nonce_str = str(op) + str(nonce) h = str(hashlib.sha256(nonce_str.encode()).hexdigest()) while h[-1] != '0' and h[-1] != '1' and h[-1] != '2': nonce += 1 nonce_str = str(op) + str(nonce) h = str(hashlib.sha256(nonce_str.encode()).hexdigest()) myVal = Block(prev_hash=prev_hash, nonce=nonce, op=op) message = p.dumps(("Accept", bal, myVal, client)) time.sleep(3.0) for num in SERVER_NUMS: if SERVER_LINKS[num] == True: CONNECTION_SOCKS[num].sendall(message)
def test_block(): utxo_mgr = UTXOManager() utxo_mgr.utxo_set.clear() chain_mgr = ChainManager() chain_mgr.add_block_to_chain(block_with_nonce) assert len(chain_mgr.active_chain) == 1 assert block_with_nonce.nonce != genesis_block.nonce assert block_with_nonce._base_hash == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18\xff\x02\xdd\xbe\x1c5\xef\xc7M\xc4J\xa8G\xcf\r&\t\xf1\xde/\x05\xfd\xed\xeb\xc4\xcf\xb7k\x1e\xbd\xb6\x80\r\xdcY@B\x10\x1e' assert block_with_nonce.nonce == 161201 assert len(utxo_mgr.utxo_set) == 1 assert UTXOManager().get_current_balance_for_addr(address_1) == 5000000 # let's add some additional spending here # let's send some money from wallet 1 (address_1) to 2 (1Q3DzrqjyK54rGxqan9aiEWgRN5RrQ4Whb) txn1 = build_transaction(address_2, 50000, address_1, signing_key_1) txn2 = build_transaction(address_2, 50000, address_1, signing_key_1) txns = [txn1, txn2] second_block = Block.assemble_and_solve_block(block_with_nonce.id, address_2, txns) chain_mgr.add_block_to_chain(second_block) # there should be 5 utxo assert len(utxo_mgr.utxo_set) == 5 assert second_block.transaction_fees[txn1.id] == TRANSACTION_FEE assert second_block.transaction_fees[txn2.id] == TRANSACTION_FEE assert second_block.fees == len(txns) * TRANSACTION_FEE # should be 5000000 - 51000 - 51000 assert UTXOManager().get_current_balance_for_addr(address_1) == 10400000
def get_block(self, msg): B = Block() B.add_message(Message(msg)) return B
def GET(self, number): number = int(number) blk = Block.get_by_number(number) raise web.seeother('/blockhash/%s' % h2h(blk.hash))
def GET(self, hexhash): h = hexhash.decode("hex")[::-1] blk = Block.get_by_hash(h) return get_render().block(blk)
from blockchain import Message, Block, Blockchain import pickle B1 = Block() B1.add_message(Message("This is the first message")) B1.add_message(Message("Second message", "Alice", "Bob")) B1.add_message(Message("Third message", "Bob", "Alice")) B1.seal() B2 = Block() 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...")