Пример #1
0
    def remove_transaction_by_short_id(self,
                                       short_id: int,
                                       remove_related_short_ids: bool = False):
        """
        Clean up short id mapping. Removes transaction contents and mapping if only one short id mapping.
        :param short_id: short id to clean up
        """
        if short_id in self._short_id_to_tx_cache_key:
            if self.node.opts.dump_removed_short_ids:
                self._removed_short_ids.add(short_id)

            transaction_cache_key = self._short_id_to_tx_cache_key.pop(
                short_id)
            transaction_hash = self._tx_cache_key_to_hash(
                transaction_cache_key)
            tx_stats.add_tx_by_hash_event(
                transaction_hash,
                TransactionStatEventType.TX_REMOVED_FROM_MEMORY,
                self.network_num,
                short_id,
                reason="RemoveByShortId")
            if transaction_cache_key in self._tx_cache_key_to_short_ids:
                short_ids = self._tx_cache_key_to_short_ids[
                    transaction_cache_key]

                # Only clear mapping and txhash_to_contents if last SID assignment
                if len(short_ids) == 1 or remove_related_short_ids:
                    for dup_short_id in short_ids:
                        if dup_short_id != short_id:
                            tx_stats.add_tx_by_hash_event(
                                transaction_hash,
                                TransactionStatEventType.
                                TX_REMOVED_FROM_MEMORY,
                                self.network_num,
                                dup_short_id,
                                reason="RemoveRelatedShortId")
                            if dup_short_id in self._short_id_to_tx_cache_key:
                                del self._short_id_to_tx_cache_key[
                                    dup_short_id]
                            self._tx_assignment_expire_queue.remove(
                                dup_short_id)
                            if self.node.opts.dump_removed_short_ids:
                                self._removed_short_ids.add(dup_short_id)

                    if transaction_cache_key in self._tx_cache_key_to_contents:
                        self._total_tx_contents_size -= len(
                            self.
                            _tx_cache_key_to_contents[transaction_cache_key])
                        del self._tx_cache_key_to_contents[
                            transaction_cache_key]

                    # Delete short ids from _tx_cache_key_to_short_ids after iterating short_ids.
                    # Otherwise extension implementation disposes short_ids list after this line
                    del self._tx_cache_key_to_short_ids[transaction_cache_key]
                    if not remove_related_short_ids:  # TODO : remove this after creating AbstractTransactionService
                        self._track_seen_transaction(transaction_cache_key)
                else:
                    short_ids.remove(short_id)

        self._tx_assignment_expire_queue.remove(short_id)
 def update_removed_transactions(self, removed_content_size: int,
                                 short_ids: List[int]) -> None:
     self._total_tx_contents_size -= removed_content_size
     for short_id in short_ids:
         tx_stats.add_tx_by_hash_event(
             constants.UNKNOWN_TRANSACTION_HASH,
             TransactionStatEventType.TX_REMOVED_FROM_MEMORY,
             self.network_num,
             short_id,
             reason="ExtensionsTrackSeenShortId")
         self._tx_assignment_expire_queue.remove(short_id)
         if self.node.opts.dump_removed_short_ids:
             self._removed_short_ids.add(short_id)
 def update_removed_transactions(self, removed_content_size: int,
                                 short_ids: List[int]) -> None:
     self._total_tx_contents_size -= removed_content_size
     for short_id in short_ids:
         tx_stats.add_tx_by_hash_event(
             UNKNOWN_TRANSACTION_HASH,
             TransactionStatEventType.TX_REMOVED_FROM_MEMORY,
             self.network_num,
             short_id,
             reason=TxRemovalReason.EXTENSION_BLOCK_CLEANUP.value)
         self._tx_assignment_expire_queue.remove(short_id)
         if self.node.opts.dump_removed_short_ids:
             self._removed_short_ids.add(short_id)
    def msg_txs(self, msg: TxsMessage):
        if ConnectionType.RELAY_TRANSACTION not in self.CONNECTION_TYPE:
            self.log_error(log_messages.UNEXPECTED_TXS_ON_NON_RELAY_CONN, msg)
            return

        transactions = msg.get_txs()
        tx_service = self.node.get_tx_service()

        tx_stats.add_txs_by_short_ids_event(
            map(lambda x: x.short_id, transactions),
            TransactionStatEventType.
            TX_UNKNOWN_SHORT_IDS_REPLY_RECEIVED_BY_GATEWAY_FROM_RELAY,
            network_num=self.node.network_num,
            peer=stats_format.connection(self),
            found_tx_hashes=map(lambda x: convert.bytes_to_hex(x.hash.binary),
                                transactions))

        for transaction in transactions:
            tx_hash, transaction_contents, short_id = transaction

            assert tx_hash is not None
            assert short_id is not None

            self.node.block_recovery_service.check_missing_sid(short_id)

            if not tx_service.has_short_id(short_id):
                tx_service.assign_short_id(tx_hash, short_id)

            self.node.block_recovery_service.check_missing_tx_hash(tx_hash)

            if not tx_service.has_transaction_contents(tx_hash):
                assert transaction_contents is not None
                tx_service.set_transaction_contents(tx_hash,
                                                    transaction_contents)

            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.
                TX_UNKNOWN_TRANSACTION_RECEIVED_BY_GATEWAY_FROM_RELAY,
                self.node.network_num,
                short_id,
                peer=stats_format.connection(self))

        self.node.block_processing_service.retry_broadcast_recovered_blocks(
            self)

        for block_awaiting_recovery in self.node.block_recovery_service.get_blocks_awaiting_recovery(
        ):
            self.node.block_processing_service.schedule_recovery_retry(
                block_awaiting_recovery)
Пример #5
0
    async def post_process_transaction(
        self, network_num: int, account_id: str, quota_type: QuotaType, transaction_str: str
    ) -> JsonRpcResponse:
        try:
            message_converter = self.node.message_converter
            assert message_converter is not None, "Invalid server state!"
            transaction = message_converter.encode_raw_msg(transaction_str)
            bx_tx = message_converter.bdn_tx_to_bx_tx(transaction, network_num, quota_type)
        except (ValueError, ParseError) as e:
            logger.error(common_log_messages.RPC_COULD_NOT_PARSE_TRANSACTION, e)
            raise RpcInvalidParams(
                self.request_id, f"Invalid transaction param: {transaction_str}"
            )
        tx_service = self.node.get_tx_service()
        tx_hash = bx_tx.tx_hash()
        if tx_service.has_transaction_contents(tx_hash):
            short_id = tx_service.get_short_id(tx_hash)
            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.TX_RECEIVED_FROM_RPC_REQUEST_IGNORE_SEEN,
                network_num,
                account_id=account_id, short_id=short_id
            )
            tx_json = {
                "tx_hash": str(tx_hash),
                "quota_type": quota_type.name.lower(),
                "account_id": account_id,
            }
            return self.ok(tx_json)
        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_RECEIVED_FROM_RPC_REQUEST,
            network_num,
            account_id=account_id
        )
        if self.node.has_active_blockchain_peer():
            blockchain_tx_message = self.node.message_converter.bx_tx_to_tx(bx_tx)
            self.node.broadcast(blockchain_tx_message, connection_types=[ConnectionType.BLOCKCHAIN_NODE])

        # All connections outside of this one is a bloXroute server
        broadcast_peers = self.node.broadcast(bx_tx, connection_types=[ConnectionType.RELAY_TRANSACTION])
        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_SENT_FROM_GATEWAY_TO_PEERS,
            network_num,
            peers=broadcast_peers
        )
        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_GATEWAY_RPC_RESPONSE_SENT,
            network_num
        )
        tx_service.set_transaction_contents(tx_hash, bx_tx.tx_val())
        tx_json = {
            "tx_hash": str(tx_hash),
            "quota_type": quota_type.name.lower(),
            "account_id": account_id
        }
        return self.ok(tx_json)
    def _test_should_log_event(self, last_byte_value: int, network_num: int,
                               short_id: Optional[int], expected_to_log: bool):

        tx_stats.logger.log = MagicMock()

        tx_hash = helpers.generate_bytearray(crypto.SHA256_HASH_LEN)
        struct.pack_into("<B", tx_hash, crypto.SHA256_HASH_LEN - 1,
                         last_byte_value)
        tx_stats.add_tx_by_hash_event(
            Sha256Hash(tx_hash),
            TransactionStatEventType.TX_SENT_FROM_GATEWAY_TO_PEERS,
            network_num, short_id)
        if expected_to_log:
            tx_stats.logger.log.assert_called_once()
        else:
            tx_stats.logger.log.assert_not_called()
 def remove_transaction_by_short_id(self,
                                    short_id: int,
                                    remove_related_short_ids: bool = False):
     # overriding this in order to handle removes triggered by either the mem limit or expiration queue
     # if the remove_related_short_ids is True than we assume the call originated by the track seen call
     # else we assume it was triggered by the cleanup.
     # this is only a temporary fix and the whole class hierarchy requires some refactoring!
     if remove_related_short_ids:
         self._tx_assignment_expire_queue.remove(short_id)
         tx_stats.add_tx_by_hash_event(
             constants.UNKNOWN_TRANSACTION_HASH,
             TransactionStatEventType.TX_REMOVED_FROM_MEMORY,
             self.network_num,
             short_id,
             reason="ExtensionRemoveShortId")
         if self.node.opts.dump_removed_short_ids:
             self._removed_short_ids.add(short_id)
     else:
         super(ExtensionTransactionService,
               self).remove_transaction_by_short_id(short_id)
    def msg_txs(self,
                msg: TxsMessage,
                recovered_txs_source: RecoveredTxsSource = RecoveredTxsSource.
                TXS_RECOVERED):
        transactions = msg.get_txs()
        tx_service = self.node.get_tx_service()
        missing_txs: Set[MissingTransactions] = tx_service.process_txs_message(
            msg)

        tx_stats.add_txs_by_short_ids_event(
            map(lambda x: x.short_id, transactions),
            TransactionStatEventType.
            TX_UNKNOWN_SHORT_IDS_REPLY_RECEIVED_BY_GATEWAY_FROM_RELAY,
            network_num=self.node.network_num,
            peers=[self],
            found_tx_hashes=map(lambda x: convert.bytes_to_hex(x.hash.binary),
                                transactions))

        for (short_id, transaction_hash) in missing_txs:
            self.node.block_recovery_service.check_missing_sid(
                short_id, recovered_txs_source)
            self.node.block_recovery_service.check_missing_tx_hash(
                transaction_hash, recovered_txs_source)

            tx_stats.add_tx_by_hash_event(
                transaction_hash,
                TransactionStatEventType.
                TX_UNKNOWN_TRANSACTION_RECEIVED_BY_GATEWAY_FROM_RELAY,
                self.node.network_num,
                short_id,
                peers=[self])

        self.node.block_processing_service.retry_broadcast_recovered_blocks(
            self)

        for block_awaiting_recovery in self.node.block_recovery_service.get_blocks_awaiting_recovery(
        ):
            self.node.block_processing_service.schedule_recovery_retry(
                block_awaiting_recovery)
Пример #9
0
    def remove_transaction_by_tx_hash(
            self, transaction_hash: Sha256Hash) -> Optional[Set[int]]:
        """
        Clean up mapping. Removes transaction contents and mapping.
        :param transaction_hash: tx hash to clean up
        """
        transaction_cache_key = self._tx_hash_to_cache_key(transaction_hash)
        removed_sids = 0
        removed_txns = 0

        if transaction_cache_key in self._tx_cache_key_to_short_ids:
            short_ids = self._tx_cache_key_to_short_ids.pop(
                transaction_cache_key)
            for short_id in short_ids:
                tx_stats.add_tx_by_hash_event(
                    transaction_hash,
                    TransactionStatEventType.TX_REMOVED_FROM_MEMORY,
                    self.network_num,
                    short_id,
                    reason="RemoveByTransactionHash")
                removed_sids += 1
                if short_id in self._short_id_to_tx_cache_key:
                    del self._short_id_to_tx_cache_key[short_id]
                self._tx_assignment_expire_queue.remove(short_id)
                if self.node.opts.dump_removed_short_ids:
                    self._removed_short_ids.add(short_id)
        else:
            short_ids = None

        if transaction_cache_key in self._tx_cache_key_to_contents:
            self._total_tx_contents_size -= len(
                self._tx_cache_key_to_contents[transaction_cache_key])
            del self._tx_cache_key_to_contents[transaction_cache_key]
            removed_txns += 1
        logger.trace(
            "Removed transaction: {}, with {} associated short ids and {} contents.",
            transaction_hash, removed_sids, removed_txns)
        return short_ids
Пример #10
0
    def broadcast_transactions_to_nodes(
            self, msg: AbstractMessage,
            broadcasting_conn: Optional[AbstractConnection]) -> bool:
        msg = cast(TransactionsEthProtocolMessage, msg)

        if self.opts.filter_txs_factor > 0:
            average_block_gas_filter = self.average_block_gas_price.average * self.opts.filter_txs_factor
        else:
            average_block_gas_filter = 0
        min_gas_price_from_node = self.min_tx_from_node_gas_price.current_minimum

        gas_price_filter = max(average_block_gas_filter,
                               min_gas_price_from_node)

        if gas_price_filter > 0:
            assert len(msg.get_transactions()) == 1
            transaction = msg.get_transactions()[0]

            gas_price = float(transaction.gas_price)

            if gas_price < gas_price_filter:
                logger.trace(
                    "Skipping sending transaction {} with gas price: {}. Average was {}. Minimum from node was {}.",
                    transaction.hash(), float(transaction.gas_price),
                    average_block_gas_filter, min_gas_price_from_node)
                tx_stats.add_tx_by_hash_event(
                    transaction.hash(),
                    TransactionStatEventType.TX_FROM_BDN_IGNORE_LOW_GAS_PRICE,
                    self.network_num,
                    peers=[broadcasting_conn],
                    more_info=
                    "Tx gas price {}. Average block gas price: {}. Node min gas price {}."
                    .format(gas_price, average_block_gas_filter,
                            min_gas_price_from_node))
                return False

        return super().broadcast_transactions_to_nodes(msg, broadcasting_conn)
    async def post_process_transaction(
            self, network_num: int, account_id: str,
            transaction_flag: TransactionFlag,
            transaction_str: str) -> JsonRpcResponse:
        try:
            message_converter = self.node.message_converter
            assert message_converter is not None, "Invalid server state!"
            transaction = message_converter.encode_raw_msg(transaction_str)
            bx_tx = message_converter.bdn_tx_to_bx_tx(transaction, network_num,
                                                      transaction_flag,
                                                      account_id)
        except (ValueError, ParseError) as e:
            logger.error(common_log_messages.RPC_COULD_NOT_PARSE_TRANSACTION,
                         e)
            raise RpcInvalidParams(
                self.request_id,
                f"Invalid transaction param: {transaction_str}")
        tx_service = self.node.get_tx_service()
        tx_hash = bx_tx.tx_hash()
        transaction_key = tx_service.get_transaction_key(tx_hash)
        if (tx_service.has_transaction_contents_by_key(transaction_key)
                or tx_service.removed_transaction_by_key(transaction_key)):
            short_id = tx_service.get_short_id_by_key(transaction_key)
            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.
                TX_RECEIVED_FROM_RPC_REQUEST_IGNORE_SEEN,
                network_num,
                account_id=account_id,
                short_id=short_id)
            tx_json = {
                "tx_hash": str(tx_hash),
            }
            return self.ok(tx_json)
        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_RECEIVED_FROM_RPC_REQUEST,
            network_num,
            account_id=account_id)
        if self.node.has_active_blockchain_peer():
            blockchain_tx_message = self.node.message_converter.bx_tx_to_tx(
                bx_tx)
            self.node.broadcast(
                blockchain_tx_message,
                connection_types=(ConnectionType.BLOCKCHAIN_NODE, ))

        # All connections outside of this one is a bloXroute server
        broadcast_peers = self.node.broadcast(
            bx_tx, connection_types=(ConnectionType.RELAY_TRANSACTION, ))
        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_SENT_FROM_GATEWAY_TO_PEERS,
            network_num,
            peers=broadcast_peers)
        tx_stats.add_tx_by_hash_event(
            tx_hash, TransactionStatEventType.TX_GATEWAY_RPC_RESPONSE_SENT,
            network_num)
        tx_service.set_transaction_contents_by_key(transaction_key,
                                                   bx_tx.tx_val())
        tx_json = {
            "tx_hash": str(tx_hash),
        }
        if not self.node.account_model.is_account_valid():
            raise RpcAccountIdError(
                self.request_id,
                "The account associated with this gateway has expired. "
                "Please visit https://portal.bloxroute.com to renew your subscription."
            )
        if self.node.quota_level == constants.FULL_QUOTA_PERCENTAGE:
            raise RpcBlocked(
                self.request_id,
                "The account associated with this gateway has exceeded its daily transaction quota."
            )
        else:
            return self.ok(tx_json)
Пример #12
0
    def msg_tx(self, msg):
        """
        Handle transactions receive from bloXroute network.
        """

        start_time = time.time()

        if ConnectionType.RELAY_TRANSACTION not in self.CONNECTION_TYPE:
            self.log_error(log_messages.UNEXPECTED_TX_MESSAGE, msg)
            return

        tx_service = self.node.get_tx_service()

        tx_hash = msg.tx_hash()
        short_id = msg.short_id()
        tx_contents = msg.tx_val()
        is_compact = msg.is_compact()
        network_num = msg.network_num()
        attempt_recovery = False

        ext_start_time = time.time()

        processing_result = tx_service.process_gateway_transaction_from_bdn(
            tx_hash, short_id, tx_contents, is_compact)

        ext_end_time = time.time()

        if processing_result.ignore_seen:
            gateway_transaction_stats_service.log_duplicate_transaction_from_relay(
            )
            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.
                TX_RECEIVED_BY_GATEWAY_FROM_PEER_IGNORE_SEEN,
                network_num,
                short_id,
                peers=[self],
                is_compact_transaction=False)
            self.log_trace("Transaction has already been seen: {}", tx_hash)
            return

        if processing_result.existing_short_id:
            gateway_transaction_stats_service.log_duplicate_transaction_from_relay(
                is_compact)
            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.
                TX_RECEIVED_BY_GATEWAY_FROM_PEER_IGNORE_SEEN,
                network_num,
                short_id,
                peers=[self],
                is_compact_transaction=is_compact)
            return

        tx_stats.add_tx_by_hash_event(
            tx_hash,
            TransactionStatEventType.TX_RECEIVED_BY_GATEWAY_FROM_PEER,
            network_num,
            short_id,
            peers=[self],
            is_compact_transaction=msg.is_compact())
        gateway_transaction_stats_service.log_transaction_from_relay(
            tx_hash, short_id is not None, msg.is_compact())

        if processing_result.assigned_short_id:
            was_missing = self.node.block_recovery_service.check_missing_sid(
                short_id, RecoveredTxsSource.TXS_RECEIVED_FROM_BDN)
            attempt_recovery |= was_missing
            tx_stats.add_tx_by_hash_event(
                tx_hash,
                TransactionStatEventType.TX_SHORT_ID_STORED_BY_GATEWAY,
                network_num,
                short_id,
                was_missing=was_missing)
            gateway_transaction_stats_service.log_short_id_assignment_processed(
            )

        if not is_compact and processing_result.existing_contents:
            gateway_transaction_stats_service.log_redundant_transaction_content(
            )

        if processing_result.set_content:
            self.log_trace(
                "Adding hash value to tx service and forwarding it to node")
            gateway_bdn_performance_stats_service.log_tx_from_bdn(
                not self.node.is_gas_price_above_min_network_fee(tx_contents))
            attempt_recovery |= self.node.block_recovery_service.check_missing_tx_hash(
                tx_hash, RecoveredTxsSource.TXS_RECEIVED_FROM_BDN)

            self.publish_new_transaction(
                tx_hash, tx_contents, TransactionFlag.LOCAL_REGION
                in msg.transaction_flag())

            if self.node.has_active_blockchain_peer():
                blockchain_tx_message = self.node.message_converter.bx_tx_to_tx(
                    msg)
                transaction_feed_stats_service.log_new_transaction(tx_hash)

                sent = self.node.broadcast_transactions_to_nodes(
                    blockchain_tx_message, self)
                if sent:
                    tx_stats.add_tx_by_hash_event(
                        tx_hash, TransactionStatEventType.
                        TX_SENT_FROM_GATEWAY_TO_BLOCKCHAIN_NODE, network_num,
                        short_id)
                    gateway_bdn_performance_stats_service.log_tx_sent_to_nodes(
                    )
                else:
                    gateway_transaction_stats_service.log_dropped_transaction_from_relay(
                    )

        if attempt_recovery:
            self.node.block_processing_service.retry_broadcast_recovered_blocks(
                self)

        end_time = time.time()

        total_duration_ms = (end_time - start_time) * 1000
        duration_before_ext_ms = (ext_start_time - start_time) * 1000
        duration_ext_ms = (ext_end_time - ext_start_time) * 1000
        duration_after_ext_ms = (end_time - ext_end_time) * 1000

        gateway_transaction_stats_service.log_processed_bdn_transaction(
            total_duration_ms, duration_before_ext_ms, duration_ext_ms,
            duration_after_ext_ms)

        performance_utils.log_operation_duration(
            msg_handling_logger,
            "Process single transaction from BDN",
            start_time,
            gateway_constants.BDN_TX_PROCESSING_TIME_WARNING_THRESHOLD_S,
            connection=self,
            message=msg,
            total_duration_ms=total_duration_ms,
            duration_before_ext_ms=duration_before_ext_ms,
            duration_ext_ms=duration_ext_ms,
            duration_after_ext_ms=duration_after_ext_ms)
Пример #13
0
    def msg_tx(self, msg):
        """
        Handle a TX message by broadcasting to the entire network
        """
        start_time = time.time()
        txn_count = 0
        broadcast_txs_count = 0

        process_tx_msg_result = self.tx_service.process_transactions_message_from_node(
            msg, self.node.get_network_min_transaction_fee(),
            self.node.opts.transaction_validation)

        if not self.node.opts.has_fully_updated_tx_service:
            logger.debug(
                "Gateway received {} transaction messages while syncing, skipping..",
                len(process_tx_msg_result))
            return

        broadcast_start_time = time.time()

        for tx_result in process_tx_msg_result:
            txn_count += 1
            if TxValidationStatus.INVALID_FORMAT in tx_result.tx_validation_status:
                gateway_transaction_stats_service.log_tx_validation_failed_structure(
                )
                logger.warning(
                    log_messages.NODE_RECEIVED_TX_WITH_INVALID_FORMAT,
                    self.node.NODE_TYPE, tx_result.transaction_hash,
                    stats_format.connection(self.connection))

                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.TX_VALIDATION_FAILED_STRUCTURE,
                    self.connection.network_num,
                    peers=[self.connection])
                continue

            if TxValidationStatus.INVALID_SIGNATURE in tx_result.tx_validation_status:
                gateway_transaction_stats_service.log_tx_validation_failed_signature(
                )
                logger.warning(log_messages.NODE_RECEIVED_TX_WITH_INVALID_SIG,
                               self.node.NODE_TYPE, tx_result.transaction_hash,
                               stats_format.connection(self.connection))

                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.TX_VALIDATION_FAILED_SIGNATURE,
                    self.connection.network_num,
                    peers=[self.connection])
                continue

            if TxValidationStatus.LOW_FEE in tx_result.tx_validation_status:
                gateway_transaction_stats_service.log_tx_validation_failed_gas_price(
                )
                # log low fee transaction here for bdn_performance
                gateway_bdn_performance_stats_service.log_tx_from_blockchain_node(
                    True)

                logger.trace(
                    "transaction {} has gas price lower then the setting {}",
                    tx_result.transaction_hash,
                    self.node.get_network_min_transaction_fee())

                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.TX_VALIDATION_FAILED_GAS_PRICE,
                    self.connection.network_num,
                    peers=[self.connection])
                continue

            if tx_result.seen:
                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.
                    TX_RECEIVED_FROM_BLOCKCHAIN_NODE_IGNORE_SEEN,
                    self.connection.network_num,
                    peers=[self.connection])
                gateway_transaction_stats_service.log_duplicate_transaction_from_blockchain(
                )
                continue

            broadcast_txs_count += 1

            tx_stats.add_tx_by_hash_event(
                tx_result.transaction_hash,
                TransactionStatEventType.TX_RECEIVED_FROM_BLOCKCHAIN_NODE,
                self.connection.network_num,
                peers=[self.connection])
            gateway_transaction_stats_service.log_transaction_from_blockchain(
                tx_result.transaction_hash)

            # log transactions that passed validation, according to fee
            gateway_bdn_performance_stats_service.log_tx_from_blockchain_node(
                not self.node.is_gas_price_above_min_network_fee(
                    tx_result.transaction_contents))

            # All connections outside of this one is a bloXroute server
            broadcast_peers = self.node.broadcast(
                tx_result.bdn_transaction_message,
                self.connection,
                connection_types=[ConnectionType.RELAY_TRANSACTION])
            self.node.broadcast(
                msg,
                self.connection,
                connection_types=[ConnectionType.BLOCKCHAIN_NODE])

            if self.node.opts.ws:
                self.publish_transaction(
                    tx_result.transaction_hash,
                    memoryview(tx_result.transaction_contents))

            if broadcast_peers:
                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.TX_SENT_FROM_GATEWAY_TO_PEERS,
                    self.connection.network_num,
                    peers=broadcast_peers)
            else:
                logger.trace(
                    "Tx Message: {} from BlockchainNode was dropped, no upstream relay connection available",
                    tx_result.transaction_hash)

        set_content_start_time = time.time()
        end_time = time.time()

        total_duration_ms = (end_time - start_time) * 1000
        duration_before_broadcast_ms = (broadcast_start_time -
                                        start_time) * 1000
        duration_broadcast_ms = (set_content_start_time -
                                 broadcast_start_time) * 1000
        duration_set_content_ms = (end_time - set_content_start_time) * 1000

        gateway_transaction_stats_service.log_processed_node_transaction(
            total_duration_ms, duration_before_broadcast_ms,
            duration_broadcast_ms, duration_set_content_ms,
            broadcast_txs_count)

        performance_utils.log_operation_duration(
            msg_handling_logger,
            "Process single transaction from Blockchain",
            start_time,
            gateway_constants.
            BLOCKCHAIN_TX_PROCESSING_TIME_WARNING_THRESHOLD_S,
            connection=self,
            message=msg,
            total_duration_ms=total_duration_ms,
            duration_before_broadcast_ms=duration_before_broadcast_ms,
            duration_broadcast_ms=duration_broadcast_ms,
            duration_set_content_ms=duration_set_content_ms)
Пример #14
0
    def msg_tx(self, msg):
        """
        Handle a TX message by broadcasting to the entire network
        """
        start_time = time.time()
        txn_count = 0
        broadcast_txs_count = 0

        tx_service = self.connection.node.get_tx_service()

        process_tx_msg_result = tx_service.process_transactions_message_from_node(msg)

        broadcast_start_time = time.time()

        for tx_result in process_tx_msg_result:
            txn_count += 1

            if tx_result.seen:
                tx_stats.add_tx_by_hash_event(tx_result.transaction_hash,
                                              TransactionStatEventType.TX_RECEIVED_FROM_BLOCKCHAIN_NODE_IGNORE_SEEN,
                                              self.connection.network_num,
                                              peer=stats_format.connection(self.connection))
                gateway_transaction_stats_service.log_duplicate_transaction_from_blockchain()
                continue

            broadcast_txs_count += 1

            tx_stats.add_tx_by_hash_event(
                tx_result.transaction_hash,
                TransactionStatEventType.TX_RECEIVED_FROM_BLOCKCHAIN_NODE,
                self.connection.network_num,
                peer=stats_format.connection(self.connection)
            )
            gateway_transaction_stats_service.log_transaction_from_blockchain(tx_result.transaction_hash)
            gateway_bdn_performance_stats_service.log_tx_from_blockchain_node()

            # All connections outside of this one is a bloXroute server
            broadcast_peers = self.connection.node.broadcast(
                tx_result.bdn_transaction_message,
                self.connection,
                connection_types=[ConnectionType.RELAY_TRANSACTION]
            )
            if self.connection.node.opts.ws:
                self.publish_transaction(
                    tx_result.transaction_hash, memoryview(tx_result.transaction_contents)
                )

            if broadcast_peers:
                tx_stats.add_tx_by_hash_event(
                    tx_result.transaction_hash,
                    TransactionStatEventType.TX_SENT_FROM_GATEWAY_TO_PEERS,
                    self.connection.network_num,
                    peers=map(lambda conn: (stats_format.connection(conn)), broadcast_peers)
                )
            else:
                logger.trace(
                    "Tx Message: {} from BlockchainNode was dropped, no upstream relay connection available",
                    tx_result.transaction_hash
                )

        set_content_start_time = time.time()
        end_time = time.time()

        total_duration_ms = (end_time - start_time) * 1000
        duration_before_broadcast_ms = (broadcast_start_time - start_time) * 1000
        duration_broadcast_ms = (set_content_start_time - broadcast_start_time) * 1000
        duration_set_content_ms = (end_time - set_content_start_time) * 1000

        gateway_transaction_stats_service.log_processed_node_transaction(
            total_duration_ms,
            duration_before_broadcast_ms,
            duration_broadcast_ms,
            duration_set_content_ms,
            broadcast_txs_count
        )

        performance_utils.log_operation_duration(
            msg_handling_logger,
            "Process single transaction from Blockchain",
            start_time,
            gateway_constants.BLOCKCHAIN_TX_PROCESSING_TIME_WARNING_THRESHOLD_S,
            connection=self,
            message=msg,
            total_duration_ms=total_duration_ms,
            duration_before_broadcast_ms=duration_before_broadcast_ms,
            duration_broadcast_ms=duration_broadcast_ms,
            duration_set_content_ms=duration_set_content_ms
        )