def message(self, pubnub, message_obj): print( f"\n -- Channel: {message_obj.channel} | Message: {message_obj.message}" ) if (message_obj.channel == CHANNELS["BLOCK"]): prospective_block = Block.deserialize_from_json( message_obj.message) prospective_chain = self.blockchain.chain[:] prospective_chain.append(prospective_block) try: self.blockchain.surrogate_chain(prospective_chain) # purge recorded Tx from Pool self.transaction_pool.purge(self.blockchain) print(f"\n -- Chain surrogation successful.") except Exception as err: print(f"\n -- Chain surrogation failed. See: {err}") elif (message_obj.channel == CHANNELS["TRANSACTION"]): transaction = Transaction.deserialize_from_json( message_obj.message) self.transaction_pool.set_transaction(transaction) print( "\n -- New transaction successfully broadcast, added to the transaction pool." )
def is_tx_chain_valid(blockchain): """ Validate incoming blockchain comprised of blocks with Tx therein qua the following ruleset: - each Tx occurs once in the blockchain (i.e. 'double spend') - there is only one valid reward Tx per block - transaction obj must be intrinsically valid """ # Tx tracked by id, raise if duplicate tx_tracking_pool = set() # unwrap blockchain, unwrap blocks therein, deserialize ea block's Tx and parse them for i in range(len(blockchain)): block = blockchain[i] mining_reward_extant = False for serialized_tx in block.data: deserialized_tx = Transaction.deserialize_from_json( serialized_tx) # if Tx already exists if (deserialized_tx.id in tx_tracking_pool): raise Exception( f"Transaction {deserialized_tx.id} is not unique; this transaction is therefore invalid." ) # add Tx to tracking pool tx_tracking_pool.add(deserialized_tx.id) # if Tx is a block reward, only validate against reward fields if (deserialized_tx.input == MINING_REWARD_INPUT): if (mining_reward_extant): raise Exception(f""" There can only be one mining reward per block. Evaluation of block with hash: {block.hash} recommended.""" ) mining_reward_extant = True else: # recalc balance after every Tx to prevent input tamper blockchain_provenance = Blockchain() blockchain_provenance.chain = blockchain[0:i] balance_provenance = Wallet.calculate_balance( blockchain_provenance, deserialized_tx.input["address"]) if (balance_provenance != deserialized_tx.input["amount"]): raise Exception( f"Transaction {deserialized_tx.id} contains an invalid input amount." ) # last, run validator to check format Transaction.is_tx_valid(deserialized_tx)