Beispiel #1
0
    def test_block_to_json(self):
        wallet = Wallet()
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "0")
        content = block.to_json()

        self.assertIsInstance(content, str)
        self.assertGreater(len(content), 0)
Beispiel #2
0
    def test_block_compute_hash(self):
        wallet = Wallet()
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "0")
        hash_val = block.compute_hash()

        self.assertIsInstance(hash_val, str)
        self.assertGreater(len(hash_val), 0)
Beispiel #3
0
 def proof_of_work(self, block: Block) -> str:
     '''Proof-of-Work to verify a valid block and find the corresponding nonce value'''
     block.nonce = 0
     computed_hash = block.compute_hash()
     # Keep trying and increasing the nonce value
     # until the new hash value meets the difficulty level restriction (Solve the hash puzzle)
     while not computed_hash.startswith('0' * block.difficulty):
         block.nonce += 1
         computed_hash = block.compute_hash()
     return computed_hash
Beispiel #4
0
    def test_block_to_dict(self):
        wallet = Wallet()
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "0")
        content = block.to_dict()

        self.assertIsInstance(content, dict)
        self.assertEqual(list(content.keys()), ["index", "timestamp", "previous_hash", "merkle_root", "nonce", "difficulty"])
Beispiel #5
0
 def create_genesis_block(self, wallet: Wallet):
     '''method to create and puts the genesis block into the blockchain'''
     block_reward = Transaction("Block_Reward", wallet.pubkey,
                                "5.0").to_json()
     genesis_block = Block(
         0, [block_reward],
         datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "0")
     # Hash of genesis block cannot be computed directly, proof of work is needed
     genesis_block.hash = self.proof_of_work(genesis_block)
     self.chain.append(genesis_block.to_json())
Beispiel #6
0
 def add_block(self, block: Block, proof: str) -> bool:
     '''
     method to check if a new block could be added at the end of the blockchain
     1. by checking that the new block from parameter is the next block from our last block
     2. by checking the new block and the given hash (from proof-of-work) is legit
     '''
     previous_hash = self.last_block['hash']
     if previous_hash != block.previous_hash:
         return False
     if not self.is_valid_proof(block, proof):
         return False
     block.hash = proof
     self.chain.append(block.to_json())
     return True
Beispiel #7
0
    def test_block_initialize(self):
        wallet = Wallet()
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        block = Block(0, [transaction], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "0")

        self.assertIsInstance(block, Block)
Beispiel #8
0
 def is_valid_proof(self, block: Block, block_hash: str) -> bool:
     '''
     we might receive blocks from another node, a validation method is also needed.
     a valid proof should have a valid hash starting with the corresponding difficulty number of 0
     (e.g. difficulty = 2; hash = 00abcd...), and the testing block's hash should match with the computed hash.
     '''
     return (block_hash.startswith('0' * block.difficulty)
             and (block_hash == block.compute_hash()))
Beispiel #9
0
    def mine(self, wallet: Wallet) -> Union[Block, bool]:
        '''
        method to generate new blocks and claim the block reward and all the transaction fees
        It confirms all unconfirmed transactions into blocks by using the proof-of-work method.
        convert to JSON to store transaction in the blockchain
        '''
        # get all available wallet addresses in the network
        addresses = self.get_addresses_from_transactions()
        # create Transaction objects for interest
        interest_txs = self.create_interest_transactions(addresses)
        for interest_tx in interest_txs:
            self.unconfirmed_transactions.insert(0, interest_tx.to_json())

        # add up all the transaction fee from all unconfirmed transactions
        tx_fees = [
            float(json.loads(transaction)['fee'])
            for transaction in self.unconfirmed_transactions
        ]
        total_tx_fee = sum(tx_fees)
        # create and add a transaction into the list of unconfirmed transactions
        # for sending out a block reward, which also include all of their transaction fees
        block_reward = Transaction("Block_Reward", wallet.pubkey,
                                   str(5.0 + total_tx_fee))
        self.unconfirmed_transactions.insert(0, block_reward.to_json())

        # if there are no unconfirmed transactions, return False
        if not self.unconfirmed_transactions:
            return False

        new_block = Block(
            index=self.last_block['index'] + 1,
            transaction=self.unconfirmed_transactions,
            timestamp=datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"),
            previous_hash=self.last_block['hash'])
        new_block.difficulty = self.next_difficulty(self.last_block)

        proof = self.proof_of_work(new_block)
        if self.add_block(new_block, proof):
            self.unconfirmed_transactions = []
            return new_block
        else:
            return False
Beispiel #10
0
    def test_blockchain_add_block_wrong_previous_hash(self):
        wallet = Wallet()
        blockchain = Blockchain(wallet)
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), "Wrong")
        computed_hash = blockchain.proof_of_work(block)
        result = blockchain.add_block(block, computed_hash)

        self.assertFalse(result)
Beispiel #11
0
    def test_blockchain_proof_of_work_bad_block(self):
        wallet = Wallet()
        blockchain = Blockchain(wallet)
        transaction = Transaction(wallet.pubkey, "CityU", 1)
        signature = wallet.sign_transaction(transaction)
        transaction.add_signature(signature)
        previous_hash = blockchain.last_block["hash"]
        block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), previous_hash)
        delattr(block, "transaction")

        self.assertRaises(AttributeError, blockchain.proof_of_work, block)
Beispiel #12
0
 def test_blockchain_proof_of_work(self):
     wallet = Wallet()
     blockchain = Blockchain(wallet)
     transaction = Transaction(wallet.pubkey, "CityU", 1)
     signature = wallet.sign_transaction(transaction)
     transaction.add_signature(signature)
     previous_hash = blockchain.last_block["hash"]
     block = Block(0, [transaction.to_json()], datetime.datetime.now().strftime("%m/%d/%Y, %H:%M:%S"), previous_hash)
     computed_hash = blockchain.proof_of_work(block)
     
     self.assertGreater(len(computed_hash), 0)
Beispiel #13
0
def lightweight():
    fullchain = [json.loads(block) for block in blockchain.chain]
    lightweight = []
    for block in fullchain:
        block_object = Block(block['index'], block['transaction'], block['timestamp'], block['previous_hash'])
        block_object.merkle_root = block['merkle_root']
        block_object.nonce = block['nonce']
        block_object.difficulty = block['difficulty']
        lightweight.append(block_object.to_dict())
    response = {
        'chain': json.dumps(lightweight),
        'length': len(lightweight)
    }
    return jsonify(response), 200
Beispiel #14
0
    def valid_chain(self, chain: List[str]) -> bool:
        '''check if a blockchain (all blocks) is valid'''
        current_index = 0
        chain = json.loads(chain)

        # load and check every block from the blockchain
        while current_index < len(chain):
            block = json.loads(chain[current_index])
            current_block = Block(block['index'], block['transaction'],
                                  block['timestamp'], block['previous_hash'])
            current_block.merkle_root = block['merkle_root']
            current_block.nonce = block['nonce']
            current_block.difficulty = block['difficulty']

            # if the current block is NOT the last block
            if current_index + 1 < len(chain):
                # if the hash value of the current block != previous block's hash value of the next block, then reject
                if current_block.compute_hash() != json.loads(
                        chain[current_index + 1])['previous_hash']:
                    return False
            # check if the current block is an instance from the list of chain
            if isinstance(current_block.transaction, list):
                for transaction in current_block.transaction:
                    transaction = json.loads(transaction)
                    # Skip block reward because it does not have signature
                    if transaction['sender'] == 'Block_Reward':
                        continue
                    current_transaction = Transaction(transaction['sender'],
                                                      transaction['recipient'],
                                                      transaction['value'])
                    current_transaction.signature = transaction['signature']
                    # check if digital signature of each transaction is valid, if not then reject
                    if not current_transaction.verify_transaction_signature():
                        return False
                # check if hash value of the current block is not valid, if yes then reject
                if not self.is_valid_proof(current_block, block['hash']):
                    return False
            current_index += 1
        return True