def test_validate_blockchain(): """Test BlockChain validation""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) # Add a new candidate assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 2)) assert blockchain.candidate_proof(4) assert blockchain.is_valid # Alter the index blockchain.chain[1].index = 2 assert blockchain.chain[1].is_valid is False assert blockchain.is_valid is False # Mining new id blockchain.chain[1].mining() assert blockchain.chain[1].is_valid assert blockchain.is_valid is False # Change the block blockchain.chain[1] = block assert blockchain.is_valid is False
def test_add_candidates(): """Validate to include a new candidate""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) assert blockchain.last_block == block assert blockchain.candidate_block is None assert blockchain.num_blocks == 1 assert blockchain.is_valid # Add a new candidate assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 2)) assert blockchain.last_block == block assert blockchain.candidate_block is not None assert blockchain.num_blocks == 1 assert blockchain.is_valid # Fail in the mining process assert blockchain.mining_candidate(maximum_iter=0) is False # Mining the candidate block assert blockchain.mining_candidate() # The blockchain is now valid assert blockchain.last_block != block assert blockchain.candidate_block is None assert blockchain.num_blocks == 2 assert blockchain.is_valid
def test_minimum_interval(): """Test minimum interval period""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1, 0, 0, 0), difficulty=4, mining=True) blockchain = BlockChain(block) # A block in a minute assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 0, 1, 0)) assert blockchain.mining_candidate() # A block in 30 seconds is not valid assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 0, 1, 30)) is False
def test_replace_chain(): """Test replace a chain""" # Generate the genesis block block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) # Generate a old chain old_chain = BlockChain(block) # Generate longer chain blockchain = BlockChain(block) # Cannot be replace the chain assert old_chain.replace_chain(blockchain) is False # Add new block assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 2)) assert blockchain.candidate_proof(4) # Replace the chain assert old_chain.replace_chain(blockchain) # Check the chain values assert old_chain.num_blocks == 2 assert old_chain.candidate_block is None
def test_change_block_contains(): """Test different attacks to the blockchain""" data = ["Avocado", "Apple", "Cherry", "Orange", "Strawberry"] block = Block.genesis_block(data[0], timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) for minute in range(1, len(data)): assert blockchain.add_candidate(data[minute], timestamp=datetime(2000, 1, 1, 0, minute, 0)) assert blockchain.mining_candidate() assert blockchain.is_valid # Alter the blockchain data blockchain.chain[2].data = 'Khaki' assert blockchain.is_valid is False
def test_basic_blockchain(): """Test the basic blockchain""" # BlockChain without values blockchain = BlockChain() assert blockchain.last_block is not None assert blockchain.candidate_block is None assert blockchain.num_blocks == 1 assert blockchain.is_valid # Manual definition of the genesis block block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4) blockchain = BlockChain(block) assert blockchain.last_block is None assert blockchain.candidate_block == block assert blockchain.num_blocks == 0 assert blockchain.is_valid is False # it is not possible to add a new candidate assert blockchain.add_candidate(None) is False # Mining the candidate block assert blockchain.mining_candidate() # The blockchain is now valid assert blockchain.last_block == block assert blockchain.candidate_block is None assert blockchain.num_blocks == 1 assert blockchain.is_valid
def test_mining_candidate(): """Test mining candidate """ block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) # Add a new candidate assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 2)) assert blockchain.mining_candidate() # Add an empty candidate assert blockchain.add_candidate(None) assert blockchain.mining_candidate() # Add an invalid candidate (same date) assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1)) is False assert blockchain.mining_candidate() is False
def test_minimal_cryptocurrency(): """Test basic process of a create a cryptocurrency""" # Generate first user wallet = Wallet() # Create a new currency with 10 units blockchain = BlockChain.new_cryptocurrency(wallet.account, 10, timestamp=datetime(2018, 1, 1, 0, 0, 0), difficulty=4, mining=True) # Get the wallets of Alice and Bob alice = blockchain.get_wallet(wallet.key) bob = blockchain.get_wallet() assert alice.get_balance() == 10 assert bob.get_balance() == 0 # Alice transfer to Bob 5 units and get 10 units because she mining the block assert blockchain.add_transaction(alice.key, bob.account, 5) blockchain.generate_candidate(alice.account, timestamp=datetime(2018, 1, 1, 0, 1, 0)) blockchain.mining_candidate() assert alice.get_balance() == 15 assert bob.get_balance() == 5 # New users Carol, Dan and Eve carol = blockchain.get_wallet() dan = blockchain.get_wallet() eve = blockchain.get_wallet() # Alice transfer 3 to Carol and 4.5 to Dan assert blockchain.add_transaction(alice.key, carol.account, 3) assert blockchain.add_transaction(alice.key, dan.account, 4.5) # Bon transfer 2.2 to Dan assert blockchain.add_transaction(bob.key, dan.account, 2.2) # Eve mine the Block blockchain.generate_candidate(eve.account, timestamp=datetime(2018, 1, 1, 0, 2, 0)) blockchain.mining_candidate() assert alice.get_balance() == 7.5 assert bob.get_balance() == 2.8 assert carol.get_balance() == 3 assert dan.get_balance() == 6.7 assert eve.get_balance() == 10
def test_add_candidates_prof(): """Test to update the proof to a candidate""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) # Add a new candidate assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 2)) # Add proof to candidate assert blockchain.candidate_proof(3) is False assert blockchain.candidate_proof(4) # Add an empty candidate assert blockchain.add_candidate(None) # Add an invalid candidate (same date) assert blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1)) is False assert blockchain.candidate_proof(3) is False assert blockchain.candidate_proof(4) is False
def test_block_repr(): """Test the report function""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1), difficulty=4, mining=True) blockchain = BlockChain(block) assert repr(blockchain) == \ "Block: 0 (2000-01-01 00:00:00) - Hash: 015921ac58652b4e01d109cbb3ad10b55836e700a93e761036343ce8a82023ae\n" for minute in range(1, 6): blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 0, minute, 0)) blockchain.mining_candidate() assert repr(blockchain) == \ "Block: 5 (2000-01-01 00:05:00) - Hash: 0332726221951b73e5fb945914341aa1e92014151680375cdf8c632256dc9a54\n" + \ "Block: 4 (2000-01-01 00:04:00) - Hash: 0bf9e27631d08c326b15f7b459b47f91d9202c07ede76ce8503d636e09070402\n" + \ "Block: 3 (2000-01-01 00:03:00) - Hash: 07ded3c477dc38fe3d0bc434b2924430f81231a0d7878f906e2a655c1f17d444\n" + \ "Block: 2 (2000-01-01 00:02:00) - Hash: 0f8ed5b1cc4dca95c0c04b5b64a1ac409d636dbfd294282092f579d3872b1c15\n" + \ "Block: 1 (2000-01-01 00:01:00) - Hash: 037eeba6b1779e5edd02e4a2b4909260193adaab7ef8abaf04ddc8ab2fc39c95\n" + \ "\nand 1 block hidden"
def test_minimal_cryptocurrency(): """Test the operation with a minimal cryptocurrency""" wallet_1 = Wallet('aedc3975fa118bec4a1d203cd2b996c4ceb5aa398b7f7518') # Launch a new currency blockchain = BlockChain.new_cryptocurrency(wallet_1.public, 100, timestamp=datetime( 2000, 1, 1, 0, 0, 0), difficulty=4, mining=True) # Open the wallets wallet_1 = blockchain.get_wallet( 'aedc3975fa118bec4a1d203cd2b996c4ceb5aa398b7f7518') wallet_2 = blockchain.get_wallet( '7d6433bcc63f973580dc7562d2ca79fcb12bb4e08c7e7333') wallet_3 = blockchain.get_wallet( '3d66f0ea52a2c5cf42893560d5522e82621790edeb7f609b') # Ask for the accounts assert wallet_1.get_balance() == 100 assert wallet_2.get_balance() == 0 assert wallet_3.get_balance() == 0 # Generate an unspent transaction assert blockchain.add_transaction(wallet_1.private, wallet_2.public, 190) is False assert blockchain.add_transaction(wallet_1.private, wallet_2.public, 90) assert blockchain.add_transaction(wallet_1.private, wallet_2.public, 90) is False # Generate a candidate to mining blockchain.generate_candidate(wallet_1.public, timestamp=datetime(2000, 1, 1, 0, 1, 0)) blockchain.mining_candidate() # Ask for the accounts assert wallet_1.get_balance() == 110 assert wallet_2.get_balance() == 90 assert wallet_3.get_balance() == 0 # Move more operations assert blockchain.add_transaction(wallet_1.private, wallet_2.public, 10) assert blockchain.add_transaction(wallet_2.private, wallet_3.public, 20) # Generate a candidate to mining blockchain.generate_candidate(wallet_1.public, timestamp=datetime(2000, 1, 1, 0, 2, 0)) blockchain.mining_candidate() # Ask for the accounts assert wallet_1.get_balance() == 200 assert wallet_2.get_balance() == 80 assert wallet_3.get_balance() == 20 # Move more operations assert blockchain.add_transaction(wallet_1.private, wallet_2.public, 25) assert blockchain.add_transaction(wallet_1.private, wallet_3.public, 25) assert blockchain.add_transaction(wallet_2.private, wallet_3.public, 50) # Generate a candidate to mining blockchain.generate_candidate(wallet_2.public, timestamp=datetime(2000, 1, 1, 0, 3, 0)) blockchain.mining_candidate() # Ask for the accounts assert wallet_1.get_balance() == 150 assert wallet_2.get_balance() == 155 assert wallet_3.get_balance() == 95
def test_creation_blockchain(): """Test errors during the build of an object""" # The input is not a block object with pytest.raises(Exception): BlockChain(1)
def test_update_difficulty(): """Test increase and decrease difficulty values""" block = Block.genesis_block(timestamp=datetime(2000, 1, 1, 0, 0, 0), difficulty=4, mining=True) blockchain = BlockChain(block) # Change the interval for tests blockchain.difficulty_interval = 2 # Blocks generates in a minute: the difficulty must increase for minute in range(1, 7): blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 0, minute, 0)) blockchain.mining_candidate() assert blockchain.chain[3].difficulty == 4 assert blockchain.chain[4].difficulty == 5 assert blockchain.chain[5].difficulty == 5 assert blockchain.chain[6].difficulty == 6 # Blocks generates in any eleven minutes: the difficulty must decrease for minute in range(17, 60, 11): blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 0, minute, 0)) blockchain.mining_candidate() blockchain.add_candidate(None, timestamp=datetime(2000, 1, 1, 1, 1, 0)) blockchain.mining_candidate() assert blockchain.chain[9].difficulty == 7 assert blockchain.chain[10].difficulty == 6