def test_invalid_chain_transactions(self): # Mine 10 coins to initial_address coinbase_transaction = { 'sender': '0', 'recipient': self.initial_address, 'amount': 10 } transactions_hash = self.mempool.hash([coinbase_transaction]) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) self.blockchain.create_block(nonce, previous_block_hash, [coinbase_transaction]) # Include a transaction in block with to much coins spent signed_transaction = self.wallet.sign_transaction( self.initial_address, '14peaf2JegQP5nmNQESAdpRGLbse8JqgJD', 100) self.mempool.current_transactions.append(signed_transaction) transactions_hash = self.mempool.hash( self.mempool.current_transactions) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) self.blockchain.create_block(nonce, previous_block_hash, self.mempool.current_transactions) self.assertFalse(self.blockchain.valid_chain(self.blockchain.chain))
def test_proof_of_work(self): transactions_hash = self.mempool.hash([]) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) encoded = f'{transactions_hash}{previous_block_hash}{nonce}'.encode() hashed = hashlib.sha256(encoded).hexdigest() self.assertEqual(hashed[:4], '0000') self.assertTrue( ProofOfWork.valid_proof(transactions_hash, previous_block_hash, nonce))
def mine(): # Create a coinbase transaction to collect the block reward (10 coins) the address of the sender has to be "0" coinbase_transaction = { 'sender': '0', 'recipient': wallet.addresses[0], 'amount': 10, 'signature': 'coinbase transaction' } # Include all transactions of the mempool in the next block including the coinbase transaction transactions_of_block = blockchain.mempool.current_transactions transactions_of_block.append(coinbase_transaction) # Run the Proof of Work algorithm to find a valid nonce for the block previous_block = blockchain.last_block previous_block_hash = blockchain.hash(previous_block) transactions_hash = blockchain.mempool.hash(transactions_of_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) # Create the new block block = blockchain.create_block(nonce, previous_block_hash, transactions_of_block) response = { 'message': "New block added to the chain", 'index': block['index'], 'timestamp': block['timestamp'], 'nonce': block['nonce'], 'transactions_hash': block['transactions_hash'], 'previous_block_hash': block['previous_block_hash'], 'transactions': block['transactions'] } return jsonify(response), 200
def test_proof_of_work_invalid_nonce(self): transactions_hash = self.mempool.hash([]) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = 12345 self.assertFalse( ProofOfWork.valid_proof(transactions_hash, previous_block_hash, nonce))
def test_valid_chain(self): signed_transaction = self.wallet.sign_transaction( self.initial_address, '14peaf2JegQP5nmNQESAdpRGLbse8JqgJD', 0) self.mempool.add_transaction(signed_transaction, self.blockchain) transactions_hash = self.mempool.hash( self.mempool.current_transactions) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) self.blockchain.create_block(nonce, previous_block_hash, self.mempool.current_transactions) self.assertTrue(self.blockchain.valid_chain(self.blockchain.chain))
def test_block_hash(self): signed_transaction = self.wallet.sign_transaction( self.initial_address, '14peaf2JegQP5nmNQESAdpRGLbse8JqgJD', 0) self.mempool.add_transaction(signed_transaction, self.blockchain) transactions_hash = self.mempool.hash( self.mempool.current_transactions) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) self.blockchain.create_block(nonce, previous_block_hash, self.mempool.current_transactions) created_block = self.blockchain.last_block block_encoded = json.dumps(created_block, sort_keys=True).encode() block_hash = hashlib.sha256(block_encoded).hexdigest() self.assertEqual(len(self.blockchain.hash(created_block)), 64) self.assertEqual(self.blockchain.hash(created_block), block_hash)
def valid_chain(self, chain): """ Validate a given blockchain by checking the hash, the Proof of Work and the transactions for each block. :param chain: <list> The blockchain :return: <bool> True if valid, False if not """ previous_block = chain[0] block_index = 1 while block_index < len(chain): current_block = chain[block_index] # Validate the hash of the block if current_block['previous_block_hash'] != self.hash( previous_block): return False # Validate the Proof of Work if not ProofOfWork.valid_proof(current_block['transactions_hash'], self.hash(previous_block), current_block['nonce']): return False # Validate the transactions of the block if current_block['transactions']: coinbase_transactions = 0 for current_transaction in current_block['transactions']: # Count the amount of coinbase transactions in the block if current_transaction['sender'] == "0": coinbase_transactions += 1 if not self.valid_transaction(current_transaction, chain, block_index): return False # If the block contains more than one coinbase transaction return False if coinbase_transactions > 1: return False previous_block = current_block block_index += 1 return True
def mine(): # get the last proof of work last_block = blockchain.get_most_recent_block() last_proof = last_block['data']['proof_of_work'] new_block_index = last_block['index'] + 1 logger.info('mining new block with height {}'.format(new_block_index)) # find the new proof of work for the current block being mined # The program will hang here until the proof of work is found proof = ProofOfWork(last_proof).calculate() # once we find a valid proof of work, we know we can mine a block so # we reward the miner by adding a transaction transactions.add_transaction({ 'from': 'network', 'to': MINER_ADDRESS, 'amount': MINER_REWARD }) new_block_data = { 'proof_of_work': proof, 'transactions': transactions.get_transactions() } new_block_timestamp = str(date.datetime.now()) last_block_hash = last_block['hash'] # create the new block new_block = Block( new_block_index, new_block_timestamp, new_block_data ) new_block.hash_block(last_block_hash) blockchain.write_block_to_disk(new_block) transactions.clear_transactions() # notify all nodes in network of new block network.broadcast_new_block(new_block)
def test_invalid_chain_prev_block_hash(self): signed_transaction = self.wallet.sign_transaction( self.initial_address, '14peaf2JegQP5nmNQESAdpRGLbse8JqgJD', 0) transactions_hash = self.mempool.hash( self.mempool.current_transactions) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'nonce': nonce, 'transactions_hash': transactions_hash, 'previous_block_hash': '12345', 'transactions': [signed_transaction] } self.blockchain.chain.append(block) self.assertFalse(self.blockchain.valid_chain(self.blockchain.chain))
def test_invalid_chain_coinbase_transaction_amount(self): coinbase_transaction = { 'sender': '0', 'recipient': self.initial_address, 'amount': 100 } transactions_hash = self.mempool.hash([coinbase_transaction]) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) block = { 'index': len(self.chain) + 1, 'timestamp': time(), 'nonce': nonce, 'transactions_hash': transactions_hash, 'previous_block_hash': previous_block_hash, 'transactions': [coinbase_transaction] } self.blockchain.chain.append(block) self.assertFalse(self.blockchain.valid_chain(self.blockchain.chain))
def test_create_block(self): signed_transaction = self.wallet.sign_transaction( self.initial_address, '14peaf2JegQP5nmNQESAdpRGLbse8JqgJD', 0) self.mempool.add_transaction(signed_transaction, self.blockchain) transactions_hash = self.mempool.hash( self.mempool.current_transactions) previous_block_hash = self.blockchain.hash(self.blockchain.last_block) nonce = ProofOfWork.proof_of_work(transactions_hash, previous_block_hash) self.blockchain.create_block(nonce, previous_block_hash, self.mempool.current_transactions) created_block = self.blockchain.last_block self.assertEqual(len(self.blockchain.chain), 2) self.assertEqual(created_block, self.blockchain.chain[-1]) self.assertEqual(created_block['index'], 2) self.assertIsNotNone(created_block['timestamp']) self.assertEqual(created_block['nonce'], nonce) self.assertEqual(created_block['transactions_hash'], transactions_hash) self.assertEqual(created_block['previous_block_hash'], previous_block_hash) self.assertEqual(created_block['transactions'], [signed_transaction]) self.assertEqual(len(self.mempool.current_transactions), 0)