def receive_block(cls, block, proof_result, sender_node_url, tx_to_miner): last_block = Blockchain.fetch_last_block() if not proof_result.is_valid(): raise InvalidReceivedBlockException() if last_block.block_id != block.previous_block_hash: if last_block.block_number < block.block_number: print('resolving conflicting...') cls._resolve_conflicts(sender_node_url) else: print('win conflict') raise TooShortReceivedBlockException() if last_block.block_id == block.previous_block_hash: Blockchain.create_block(block) UnconfirmedTxPool.transactions.clear() UnconfirmedTxPool.create_transaction(tx_to_miner)
def fetch_unspent_tx_outputs_by_address(cls, request): address = request.get_json()['address'] unspent_tx_outputs_in_blockchain = Blockchain.fetch_unspent_tx_outputs_by_address( address) result_tx_outputs = list( filter( lambda tx_o: tx_o.transaction_output_id not in UnconfirmedTxPool.list_spent_tx_output_ids(), unspent_tx_outputs_in_blockchain)) return jsonify(result_tx_outputs), 200
def _resolve_conflicts(cls, send_node_url): json = requests.get(send_node_url + '/blocks').json() send_node_blocks = list( map(lambda block_dict: decode_block(block_dict), json)) my_node_blocks = Blockchain.fetch_all_blocks() forked_block_number = cls._search_forked_block_number( send_node_blocks, my_node_blocks) deleting_blocks = list( filter(lambda block: block.block_number > forked_block_number, my_node_blocks)) adding_blocks = list( filter(lambda block: block.block_number > forked_block_number, send_node_blocks)) for deleting_block in deleting_blocks: Blockchain.delete_block(deleting_block) for adding_block in adding_blocks: Blockchain.create_block(adding_block)
def create_transaction(cls, tx_request): # 使用としているトランザクションアウトプットIDが既に未承認のトランザクションアウトプットIDに含まれていたら例外を投げる spent_tx_output_ids_in_unconfirmed_tx_pool = UnconfirmedTxPool.list_spent_tx_output_ids() tx_request.assert_unspent_tx_output_ids(spent_tx_output_ids_in_unconfirmed_tx_pool) unspent_tx_outputs_in_blockchain = Blockchain.fetch_unspent_tx_outputs_by_tx_output_ids( tx_request.get_requesting_tx_output_ids()) # 今回使用しようとしているトランザクションインプットを算出 tx_inputs = tx_request.get_tx_inputs(unspent_tx_outputs_in_blockchain) TransactionInput.verify_tx_inputs(tx_inputs, tx_request.sender_address) transaction = Transaction.build_with_tx_outputs( timestamp = tx_request.timestamp, tx_inputs = tx_inputs, request_amount = tx_request.amount, sender_address = tx_request.sender_address, recipient_address = tx_request.recipient_address ) UnconfirmedTxPool.transactions.append(transaction) return transaction
def _create_block(cls): last_block = Blockchain.fetch_last_block() previous_hash = last_block.block_id block_number = Blockchain.fetch_block_count() + 1 proof_of_work = ProofOfWork(previous_hash, last_block.difficulty_target) proof_result = proof_of_work.prove() proof_result.assert_valid() transactions = UnconfirmedTxPool.transactions.copy() UnconfirmedTxPool.transactions.clear() target_transactions = Blockchain.search_new_transactions(transactions) block = Block.build( block_number=block_number, previous_block_hash=previous_hash, timestamp=datetime.now().timestamp(), merkle_root="", # TODO difficulty_target=last_block.difficulty_target, nonce=proof_result.nonce, transactions=target_transactions) last_block = Blockchain.fetch_last_block() if last_block.block_id != block.previous_block_hash: print('lost mining', block.block_id) raise LoseMiningException() Blockchain.create_block(block) print('block created', block.block_id) print('current block number', block.block_number) return block, proof_result
def assert_new_block(cls, block_id): block = Blockchain.find_block(block_id) if block is not None: raise DuplicatedBlockException() return
def fetch_all_blocks(cls): return jsonify(Blockchain.fetch_all_blocks()), 200