def test_transaction_to_json(self): wallet = Wallet() transaction = Transaction(wallet.pubkey, "CityU", 1) content = transaction.to_json() self.assertIsInstance(content, str) self.assertGreater(len(content), 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)
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"])
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)
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)
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)
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)
def merkle_path(self, transaction: Transaction): '''return merkle path of given transaction''' path = [] transactionHash = sha256(str( transaction.to_json()).encode()).hexdigest() block = self.search_block_with_transaction(transactionHash) leaves = [] if block: for trans in block['transaction']: trans = json.loads(trans) new_trans = Transaction(trans['sender'], trans['recipient'], trans['value']) if 'signature' in trans.keys(): new_trans.signature = trans['signature'] new_transHash = sha256(str( new_trans.to_json()).encode()).hexdigest() leaves.append(new_transHash) path = self._merklePath(leaves, transactionHash, []) path.append(block['merkle_root']) return path
def add_new_transaction(self, transaction: Transaction) -> bool: ''' add a new transaction to the block after checking balance ''' if transaction.verify_transaction_signature(): # Check balance and fee before confirming a transaction total_charge = float(transaction.value) + float(transaction.fee) if transaction.sender != "Block_Reward" and \ self.check_balance(transaction.sender) >= total_charge: self.unconfirmed_transactions.append(transaction.to_json()) return True return False
def partial_validation(): values = request.form required = ['root', 'path', 'sender', 'recipient', 'value'] # Check that the required fields are in the POST data if not all(k in values for k in required): return 'Missing values', 400 root = values.get('root') path = json.loads(values.get('path')) transaction = Transaction(values.get('sender'), values.get('recipient'), values.get('value')) if values.get('signature'): transaction.signature = values.get('signature') h = sha256(str(transaction.to_json()).encode()).hexdigest() new_root = blockchain.partialValidation(path, h) result = root == new_root return jsonify(result), 200
def search_block_with_transaction(self, transactionHash): '''return block that matches given transaction hash''' fullchain = [json.loads(block) for block in self.chain] for block in fullchain[::-1]: for trans in block['transaction']: trans = json.loads(trans) new_trans = Transaction(trans['sender'], trans['recipient'], trans['value']) if 'signature' in trans.keys(): new_trans.signature = trans['signature'] new_transHash = sha256(str( new_trans.to_json()).encode()).hexdigest() if transactionHash == new_transHash: return block return False
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