def test_contains_valid_transactions_duplicate_transaction(self): transaction = Transaction(Wallet(), "recipient", 1).serialize() self.blockchain.add_block([transaction, transaction]) with self.assertRaises(ContainsInvalidTransactionError): Blockchain.contains_valid_transactions(self.blockchain.chain)
def main(): """Example use of the Blockchain, with the ability to read and write to a file.""" try: with open("chain_data.json", "r") as chain_data_h: chain_data_raw = chain_data_h.read() except: print("Chain data missing or invalid, writing default chain.") chain_data_raw = write_default_blockchain() chain_data = [] try: # Convert the file contents (JSON) to a list of Blocks represented as dicts. chain_data = json.loads(chain_data_raw) except: print("Invalid chain data detected.") sys.exit(-1) # Initialise the Blockchain with the imported data. chain = Blockchain(chain_data) print(f"The blockchain has {len(chain.blocks)} blocks.") print(f"Hash of genesis block is {chain.blocks[0].generate_hash()}") print("Valid?", chain.validate()) # If you're tinkering... here you could try adding or removing Blocks. # You may wish to use chain.add_data(data: str), or even add a # malicious block using the chain.blocks list directly. # In case of any modifications, write the chain to a file again. save_chain(chain)
def mine(): # Run the proof-of-work algorithm to get the next proof last_block = Blockchain.last_block proof = Blockchain.proof_of_work(last_block) # Receive a reward for finding the proof # A sender "0" signifies that the node has mined a new coin Blockchain.new_transaction( sender="0", recipient=node_identifier, amount=1, ) # Forge a new block by adding transaction to the chain previous_hash = Blockchain.hash(last_block) block = Blockchain.new_block(proof, previous_hash) response = { 'message': "New Block forged", 'index': block['index'], 'transactions': block['transactions'], 'proof': block['proof'], 'previous_hash': block['previous_hash'], } return jsonify(response), 200
def test_contains_valid_transactions_duplicate_rewards(self): self.blockchain.add_block([ Transaction.reward(Wallet()).serialize(), Transaction.reward(Wallet()).serialize(), ]) # Block contains multiple reward transactions so we expect an exception with self.assertRaises(ContainsInvalidTransactionError): Blockchain.contains_valid_transactions(self.blockchain.chain)
def test_add_block(): bc = Blockchain() client1 = Client() client2 = Client() tx = Transaction("Hello from the beginning", client1, client2) bc.unconfirmed_transactions.append(tx.get_tx_dict()) bc.mine(bc.chain[-1]) assert bc.chain[-1].transactions is not None
def test_replace(self): # Create a new blockchain, only has genesis blockchain = Blockchain() # Try replacing chain with longer chain blockchain.replace(self.blockchain.chain) # Assert that chain was replaced by longer one self.assertEqual(blockchain.chain, self.blockchain.chain)
def test_replace_incoming_not_valid(self): # Create a new blockchain, only has genesis blockchain = Blockchain() self.blockchain.chain[1].data = "Some bad data" with self.assertRaises(ChainReplacementError): # Try replacing chain with shorter chain blockchain.replace(self.blockchain.chain)
def test_contains_valid_transactions_bad_transaction(self): bad_transaction = Transaction(Wallet(), "recipient", 1) # Use same transaction output but signed by wrong wallet bad_transaction.input["signature"] = Wallet().sign( bad_transaction.output) self.blockchain.add_block([bad_transaction.serialize()]) with self.assertRaises(TransactionSignatureError): Blockchain.contains_valid_transactions(self.blockchain.chain)
def register_nodes(): values = request.get_json() print(f'Values is: {values}') nodes = values.get('nodes') if nodes is None: return "Error: Please supply a valid list of nodes", 400 for node in nodes: Blockchain.register_node(node) response = { 'message': 'New nodes have been added', 'total_nodes': list(Blockchain.nodes), } return jsonify(response), 201
def write_default_blockchain() -> str: """Returns the string representation of the default Blockchain data.""" genesis_block = Block() genesis_block.data = "This is the sickest Blockchain implementation ever." genesis_block.timestamp = time.time() genesis_block.previous_hash = "" # Create a temporary chain which we can convert to JSON. default_chain = Blockchain([]) default_chain.blocks.append(genesis_block) save_chain(default_chain) return default_chain.to_json()
def test_contains_valid_transactions_bad_historic_balance(self): wallet = Wallet() bad_transaction = Transaction(wallet, "recipient", 1) # Tamper with transaction, giving wallet a high amount bad_transaction.output[wallet.address] = 1000 # Ensure input amount and transaction amount are still correct so validation doesn't fail at that point bad_transaction.input["amount"] = 1001 # Re-sign wallet.sign(bad_transaction.output) self.blockchain.add_block([bad_transaction.serialize()]) with self.assertRaises(ContainsInvalidTransactionError): Blockchain.contains_valid_transactions(self.blockchain.chain)
def is_valid(): if Blockchain.is_chain_valid(blockchain.chain): response = {'message': 'All good. The Blockchain is valid.'} else: response = { 'message': 'Houston, we have a problem. The Blockchain is not valid.' } return jsonify(response), 200
def test_replace_incoming_not_longer(self): # Create a new blockchain, only has genesis incoming = Blockchain() with self.assertRaisesRegex( ChainReplacementError, "Cannot replace. Incoming chain must be longer than local chain.", ): # Try replacing chain with shorter chain self.blockchain.replace(incoming.chain)
def __init__(self, PORT_ADDRESS): self.nodes = list() self.PORT_ADDRESS = PORT_ADDRESS self.transactions = [] Blockchain.__init__(self) try: json_file_read = open('nodes.txt', 'r') data = json.load(json_file_read) for p in data['nodes']: self.nodes.append(p) json_file_read.close() except FileNotFoundError: print("Creating file nodes.txt...") finally: self.nodes.append(PORT_ADDRESS) json_file_write = open('nodes.txt', 'w') data = {"nodes": self.nodes} json.dump(data, json_file_write) json_file_write.close()
def mine(): last_block = blockchain.last_block last_proof = blockchain.last_block['proof'] proof = blockchain.proof_of_work(last_proof) blockchain.new_transactions("0", node_identifier, 1) previous_hash = Blockchain.hash_block(last_block) block = blockchain.new_block(previous_hash, proof) return jsonify({'message': 'New block forged', 'block': block}), 200
def test_clear_transaction(self): transaction_pool = TransactionPool() transaction1 = Transaction(Wallet(), "recipient_address", 1) transaction2 = Transaction(Wallet(), "recipient_address", 2) transaction_pool.add_transaction(transaction1) transaction_pool.add_transaction(transaction2) blockchain = Blockchain() blockchain.add_block( [transaction1.serialize(), transaction2.serialize()]) self.assertIn(transaction1.id, transaction_pool.transactions) self.assertIn(transaction2.id, transaction_pool.transactions) transaction_pool.clear_transactions(blockchain) self.assertNotIn(transaction1.id, transaction_pool.transactions) self.assertNotIn(transaction2.id, transaction_pool.transactions)
def wait_chains(): try: new_chain_json = self.chain_syncher.get_chain() new_blockchain = Blockchain.from_json(new_chain_json) self.blockchain.replace_chain(new_blockchain, self.entry_pool) self.entry_pool.filter(self.blockchain) print('\nBlockchain synchronisiert') except Exception as e: print(f'\nBlockchain nicht synchronisiert -> {e}')
def test_calculate_balance(self): blockchain = Blockchain() wallet = Wallet() self.assertEqual( Wallet.calculate_balance(blockchain, wallet.address), STARTING_BALANCE ) amount = 50 transaction = Transaction(wallet, "recipient_address", amount) blockchain.add_block([transaction.serialize()]) self.assertEqual( Wallet.calculate_balance(blockchain, wallet.address), STARTING_BALANCE - amount, ) # Add some transactions where wallet receives an amount blockchain.add_block( [ Transaction(Wallet(), wallet.address, 30).serialize(), Transaction(Wallet(), wallet.address, 75).serialize(), ] ) self.assertEqual( Wallet.calculate_balance(blockchain, wallet.address), STARTING_BALANCE - amount + 30 + 75, )
def consensus(): replaced = Blockchain.resolve_conflicts() if replaced: response = { 'message': 'Chain was replaced', 'new_chain': Blockchain.chain } else: response = { 'message': 'Chain is authoritative', 'chain': Blockchain.chain } return jsonify(response), 200
def new_transaction(): values = request.get_json() # Are the required fields in the POSTed data? required = ['sender', 'receiver', 'amount'] if not all(k in values for k in required): return 'Missing Values', 400 # Create a new transaction index = Blockchain.new_transaction(values['sender'], values['receiver'], values['amount']) response = {'message': f'Transaction will be added to Block {index}'} return jsonify(response), 201
def save_chain(chain: Blockchain, location: str = "chain_data.json") -> bool: """ Returns a bool indicating whether or not the data was saved. Parameters: chain -- the Blockchain to write to the file. location -- the path to the file in which the data will be written. """ try: with open(location, "w") as chain_data_h: chain_data_h.write(chain.to_json()) return True except: return False
def message(self, pubnub, message_object): if message_object.channel == 'BLOCK': sender_addr = message_object.message["sender_address"] if sender_addr != self.keychain.address: print( f'\nBlock empfangen von Node: {sender_addr} -> {Block.from_json(message_object.message["block"])}' ) block = Block.from_json(message_object.message["block"]) new_chain = self.blockchain.chain[:] new_chain.append(block) try: self.blockchain.replace_chain(Blockchain(new_chain), self.entry_pool) self.entry_pool.filter(self.blockchain) print('\nBlockchain ergänzt') except Exception as e: print(f'\nFehler bei Ergänzung -> {e}') if message_object.channel == 'ENTRY': try: entry = json_to_entry(message_object.message) self.entry_pool.add_entry(entry) print(f'\nEintrag empfangen: {entry}') except Exception as e: print(f'\nFehler beim Empfangen eines Eintrags -> {e}') if message_object.channel == 'CHAIN': recipient_addr = message_object.message["recipient_address"] if recipient_addr == self.keychain.address: self.chain_syncher.add_chain(message_object.message["chain"]) print('\nChain empfangen') if message_object.channel == 'SYNC': sender_addr = message_object.message["sender_address"] if self.keychain.address != sender_addr: self.p2p.send_chain(self.blockchain, sender_addr) print(f'\nChain gesendet an Node: {sender_addr}')
from flask import Flask, jsonify, request from uuid import uuid4 from blockchain.blockchain import Blockchain # Создаем икземплярнашего узла app = Flask(__name__) # Генерируем уникальный адрес для нашего узла node_identifier = str(uuid4()).replace('-', '') # Создаем экзеипляр Blockchain blockchain = Blockchain() @app.route('/', methods=['GET']) def index(): return 'Our very first REAL BLOCKCHAIN!!!' @app.route('/my/address', methods=['GET']) def my_address(): response = {"address": node_identifier} return jsonify(response), 200 @app.route('/mine', methods=['GET']) def mine(): # Запускаем алгоритм PoW для того чтобы найти proof ... last_block = blockchain.last_block last_proof = last_block['proof']
def test_genesis_block(): bc = Blockchain() assert bc.chain[0]
class BlockchainTest(TestCase): KEYS = [ ("ak_zPoY7cSHy2wBKFsdWJGXM7LnSjVt6cn1TWBDdRBUMC7Tur2NQ", "36595b50bf097cd19423c40ee66b117ed15fc5ec03d8676796bdf32bc8fe367d82517293a0f82362eb4f93d0de77af5724fba64cbcf55542328bc173dbe13d33" ), ("ak_gLYH5tAexTCvvQA6NpXksrkPJKCkLnB9MTDFTVCBuHNDJ3uZv", "6eb127925aa10d6d468630a0ca28ff5e1b8ad00db151fdcc4878362514d6ae865951b78cf5ef047cab42218e0d5a4020ad34821ca043c0f1febd27aaa87d5ed7" ), ("ak_23p6pT7bajYMJRbnJ5BsbFUuYGX2PBoZAiiYcsrRHZ1BUY2zSF", "e15908673cda8a171ea31333538437460d9ca1d8ba2e61c31a9a3d01a8158c398a14cd12266e480f85cc1dc3239ed5cfa99f3d6955082446bebfe961449dc48b" ), ] def setUp(self): self.bc = Blockchain() def test_mint(self): pubkey = self.KEYS[0][0] amount = int(1.234e8) balance_pre = self.bc.get_balance(pubkey) response = self.client.post("/blockchain/mint", { "receiver_pubkey": pubkey, "amount": amount, }) self.assertEqual(response.status_code, 200) self.assertEqual( json.loads(response.content.decode("utf-8"))["status"], "ok") balance_post = self.bc.get_balance(pubkey) self.assertEqual(balance_post, balance_pre + amount) def test_transfer_aeter(self): pubkey = self.KEYS[0][0] amount = int(1.234e8) balance_pre = self.bc.get_balance_aeter(pubkey) response = self.client.post("/blockchain/transfer_aeter", { "receiver_pubkey": pubkey, "amount": amount, }) self.assertEqual(response.status_code, 200) self.assertEqual( json.loads(response.content.decode("utf-8"))["status"], "ok") balance_post = self.bc.get_balance_aeter(pubkey) self.assertEqual(balance_post, balance_pre + amount) def test_get_balance(self): pubkey = self.KEYS[0][0] response = self.client.get("/blockchain/get_balance", { "pubkey": pubkey, }) self.assertEqual(response.status_code, 200) self.assertTrue(response.content.decode("utf-8").isdigit()) def test_get_nonce(self): pubkey = self.KEYS[0][0] response = self.client.get("/blockchain/get_nonce", { "pubkey": pubkey, }) self.assertEqual(response.status_code, 200) self.assertTrue(response.content.decode("utf-8").isdigit()) def test_get_transfer_tx(self): # TODO pass def test_broadcast_signed_tx(self): # TODO pass
def setUp(self): self.bc = Blockchain()
def test_add_block(): blockchain=Blockchain() data='test-data' blockchain.addBlock(data) assert blockchain.ledger[-1].data==data
def test_replaceLedgerBadLedger(blockchain_three_blocks): blockchain = Blockchain() blockchain_three_blocks.ledger[1].hash = 'bad_hash' with pytest.raises(Exception, match='cannot replace. The incoming chain is invalid:'): blockchain.replaceLedger(blockchain_three_blocks.ledger)
def test_blockchain_instance(): blockchain=Blockchain() assert blockchain.ledger[0].hash==GENESIS_DATA['hash']
def test_replaceLedgerNotLonger(blockchain_three_blocks): blockchain = Blockchain() with pytest.raises(Exception, match='cannot replace. The incoming chain must be longer.'): blockchain_three_blocks.replaceLedger(blockchain.ledger)