Esempio n. 1
0
class Messenger(object):
    def __init__(self, validator_url):
        self._connection = Connection(validator_url)
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._batch_signer = self._crypto_factory.new_signer(
            self._context.new_random_private_key())

    def open_validator_connection(self):
        self._connection.open()

    def close_validator_connection(self):
        self._connection.close()

    def get_new_key_pair(self):
        private_key = self._context.new_random_private_key()
        public_key = self._context.get_public_key(private_key)
        return public_key.as_hex(), private_key.as_hex()

    async def send_create_agent_transaction(self,
                                            private_key,
                                            name,
                                            timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_agent_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            name=name,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def _send_and_wait_for_commit(self, batch):
        # Send transaction to validator
        submit_request = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=[batch])
        await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            submit_request.SerializeToString())

        # Send status request to validator
        batch_id = batch.header_signature
        status_request = client_batch_submit_pb2.ClientBatchStatusRequest(
            batch_ids=[batch_id], wait=True)
        validator_response = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            status_request.SerializeToString())

        # Parse response
        status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
        status_response.ParseFromString(validator_response.content)
        status = status_response.batch_statuses[0].status
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
            error = status_response.batch_statuses[0].invalid_transactions[0]
            raise ApiBadRequest(error.message)
        elif status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
            raise ApiInternalError('Transaction submitted but timed out')
        elif status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            raise ApiInternalError('Something went wrong. Try again later')
Esempio n. 2
0
def main():
    loop = ZMQEventLoop()
    asyncio.set_event_loop(loop)

    connection = None
    try:
        opts = parse_args(sys.argv[1:])

        init_console_logging(verbose_level=opts.verbose)

        url = opts.connect
        if "tcp://" not in url:
            url = "tcp://" + url
        connection = Connection(url)

        try:
            host, port = opts.bind.split(":")
            port = int(port)
        except ValueError:
            print("Unable to parse binding {}: Must be in the format"
                  " host:port".format(opts.bind))
            sys.exit(1)

        start_rest_api(host, port, connection)
    except Exception as err:  # pylint: disable=broad-except
        LOGGER.exception(err)
        sys.exit(1)
    finally:
        if connection is not None:
            connection.close()
Esempio n. 3
0
 def __init__(self, validator_url, database):
     self._connection = Connection(validator_url)
     self._context = create_context('secp256k1')
     self._crypto_factory = CryptoFactory(self._context)
     self._batch_signer = self._crypto_factory.new_signer(
         self._context.new_random_private_key())
     self._database = database
Esempio n. 4
0
async def open_connections(appl):
    appl.config.INVESTIGATOR_VAL_CONN = Connection(appl.config.TRIAL_VALIDATOR_URL)
    appl.config.CONSENT_VAL_CONN = Connection(appl.config.CONSENT_VALIDATOR_URL)

    LOGGER.warning('opening validator connection for Investigator network: ' + str(appl.config.TRIAL_VALIDATOR_URL))
    LOGGER.warning('opening validator connection for Consent network: ' + str(appl.config.CONSENT_VALIDATOR_URL))

    appl.config.INVESTIGATOR_VAL_CONN.open()
    appl.config.CONSENT_VAL_CONN.open()
Esempio n. 5
0
def main():
    loop = ZMQEventLoop()
    asyncio.set_event_loop(loop)

    connection = None
    try:
        opts = parse_args(sys.argv[1:])
        opts_config = RestApiConfig(
            bind=opts.bind,
            connect=opts.connect,
            timeout=opts.timeout)
        rest_api_config = load_rest_api_config(opts_config)
        url = None
        if "tcp://" not in rest_api_config.connect:
            url = "tcp://" + rest_api_config.connect
        else:
            url = rest_api_config.connect

        connection = Connection(url)

        log_config = get_log_config(filename="rest_api_log_config.toml")

        # If no toml, try loading yaml
        if log_config is None:
            log_config = get_log_config(filename="rest_api_log_config.yaml")

        if log_config is not None:
            log_configuration(log_config=log_config)
        else:
            log_dir = get_log_dir()
            log_configuration(log_dir=log_dir, name="rest_api")
        init_console_logging(verbose_level=opts.verbose)

        try:
            host, port = rest_api_config.bind[0].split(":")
            port = int(port)
        except ValueError as e:
            print("Unable to parse binding {}: Must be in the format"
                  " host:port".format(rest_api_config.bind[0]))
            sys.exit(1)

        start_rest_api(
            host,
            port,
            connection,
            int(rest_api_config.timeout))
        # pylint: disable=broad-except
    except Exception as e:
        print("Error: {}".format(e), file=sys.stderr)
    finally:
        if connection is not None:
            connection.close()
Esempio n. 6
0
def main():
    loop = ZMQEventLoop()
    asyncio.set_event_loop(loop)

    connection = None
    try:
        opts = parse_args(sys.argv[1:])
        opts_config = RestApiConfig(
            bind=opts.bind,
            connect=opts.connect,
            timeout=opts.timeout)
        rest_api_config = load_rest_api_config(opts_config)
        url = None
        if "tcp://" not in rest_api_config.connect:
            url = "tcp://" + rest_api_config.connect
        else:
            url = rest_api_config.connect

        connection = Connection(url)

        log_config = get_log_config(filename="rest_api_log_config.toml")
        if log_config is not None:
            log_configuration(log_config=log_config)
        else:
            log_dir = get_log_dir()
            log_configuration(log_dir=log_dir, name="sawtooth_rest_api")
        init_console_logging(verbose_level=opts.verbose)

        try:
            host, port = rest_api_config.bind[0].split(":")
            port = int(port)
        except ValueError as e:
            print("Unable to parse binding {}: Must be in the format"
                  " host:port".format(rest_api_config.bind[0]))
            sys.exit(1)

        start_rest_api(
            host,
            port,
            connection,
            int(rest_api_config.timeout))
        # pylint: disable=broad-except
    except Exception as e:
        print("Error: {}".format(e), file=sys.stderr)
    finally:
        if connection is not None:
            connection.close()
Esempio n. 7
0
async def open_connections(appl):
    # LOGGER.warning('opening database connection')
    # r.set_loop_type('asyncio')
    # app.config.DB_CONN = await r.connect(
    #     host=app.config.DB_HOST,
    #     port=app.config.DB_PORT,
    #     db=app.config.DB_NAME)

    appl.config.EHR_VAL_CONN = Connection(appl.config.EHR_VALIDATOR_URL)
    appl.config.CONSENT_VAL_CONN = Connection(
        appl.config.CONSENT_VALIDATOR_URL)

    LOGGER.warning('opening validator connection for EHR network: ' +
                   str(appl.config.EHR_VALIDATOR_URL))
    LOGGER.warning('opening validator connection for Consent network: ' +
                   str(appl.config.CONSENT_VALIDATOR_URL))

    appl.config.EHR_VAL_CONN.open()
    appl.config.CONSENT_VAL_CONN.open()
Esempio n. 8
0
async def open_connections(app):
    LOGGER.warning('opening database connection')
    r.set_loop_type('asyncio')
    app.config.DB_CONN = await r.connect(host=app.config.DB_HOST,
                                         port=app.config.DB_PORT,
                                         db=app.config.DB_NAME)

    app.config.VAL_CONN = Connection(app.config.VALIDATOR_URL)

    LOGGER.warning('opening validator connection')
    app.config.VAL_CONN.open()
Esempio n. 9
0
async def open_connections(app):
    LOGGER.warning("opening database connection")
    app.config.DB_CONN = await db_utils.create_connection(
        app.config.DB_HOST, app.config.DB_PORT, app.config.DB_NAME
    )

    validator_url = "{}:{}".format(app.config.VALIDATOR_HOST, app.config.VALIDATOR_PORT)
    if "tcp://" not in app.config.VALIDATOR_HOST:
        validator_url = "tcp://" + validator_url
    app.config.VAL_CONN = Connection(validator_url)

    LOGGER.warning("opening validator connection")
    app.config.VAL_CONN.open()
Esempio n. 10
0
def main():
    loop = ZMQEventLoop()
    asyncio.set_event_loop(loop)

    connection = None
    try:
        opts = parse_args(sys.argv[1:])
        opts_config = RestApiConfig(bind=opts.bind,
                                    connect=opts.connect,
                                    timeout=opts.timeout,
                                    opentsdb_url=opts.opentsdb_url,
                                    opentsdb_db=opts.opentsdb_db)
        rest_api_config = load_rest_api_config(opts_config)
        url = None
        if "tcp://" not in rest_api_config.connect:
            url = "tcp://" + rest_api_config.connect
        else:
            url = rest_api_config.connect

        connection = Connection(url)

        log_config = get_log_config(filename="rest_api_log_config.toml")

        # If no toml, try loading yaml
        if log_config is None:
            log_config = get_log_config(filename="rest_api_log_config.yaml")

        if log_config is not None:
            log_configuration(log_config=log_config)
        else:
            log_dir = get_log_dir()
            log_configuration(log_dir=log_dir, name="rest_api")
        init_console_logging(verbose_level=opts.verbose)

        try:
            host, port = rest_api_config.bind[0].split(":")
            port = int(port)
        except ValueError as e:
            print("Unable to parse binding {}: Must be in the format"
                  " host:port".format(rest_api_config.bind[0]))
            sys.exit(1)

        wrapped_registry = None
        if rest_api_config.opentsdb_url:
            LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                        rest_api_config.opentsdb_url,
                        rest_api_config.opentsdb_db)

            url = urlparse(rest_api_config.opentsdb_url)
            proto, db_server, db_port, = url.scheme, url.hostname, url.port

            registry = MetricsRegistry()
            wrapped_registry = MetricsRegistryWrapper(registry)

            reporter = InfluxReporter(
                registry=registry,
                reporting_interval=10,
                database=rest_api_config.opentsdb_db,
                prefix="sawtooth_rest_api",
                port=db_port,
                protocol=proto,
                server=db_server,
                username=rest_api_config.opentsdb_username,
                password=rest_api_config.opentsdb_password)
            reporter.start()

        start_rest_api(host, port, connection, int(rest_api_config.timeout),
                       wrapped_registry)
        # pylint: disable=broad-except
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if connection is not None:
            connection.close()
Esempio n. 11
0
class Messenger(object):
    TIMEOUT = 300

    def __init__(self, validator_url):
        self._connection = Connection(validator_url)
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._batch_signer = self._crypto_factory.new_signer(
            self._context.new_random_private_key())

    def open_validator_connection(self):
        self._connection.open()

    def close_validator_connection(self):
        self._connection.close()

    def get_new_key_pair(self):
        private_key = self._context.new_random_private_key()
        public_key = self._context.get_public_key(private_key)
        return public_key.as_hex(), private_key.as_hex()

    async def send_create_agent_transaction(self, private_key, name, timestamp,
                                            role):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_agent_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            name=name,
            timestamp=timestamp,
            role=role)
        await self._send_and_wait_for_commit(batch)

    async def send_create_record_transaction(self, private_key, record_id,
                                             description, price, quantity,
                                             units, parent_id, other_fields,
                                             remarks, new, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            record_id=record_id,
            description=description,
            price=price,
            quantity=quantity,
            units=units,
            parent_id=parent_id,
            other_fields=other_fields,
            remarks=remarks,
            new=new,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_transfer_record_transaction(self, private_key,
                                               receiving_agent, record_id,
                                               timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_transfer_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            receiving_agent=receiving_agent,
            record_id=record_id,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_update_record_transaction(self, private_key, record_id,
                                             description, price, quantity,
                                             units, parent_id, other_fields,
                                             timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))
        batch = make_update_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            record_id=record_id,
            description=description,
            price=price,
            quantity=quantity,
            units=units,
            parent_id=parent_id,
            other_fields=other_fields,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def send_finalize_record_transaction(self, private_key, record_id,
                                               status, remarks, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))
        batch = make_finalize_record_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            record_id=record_id,
            status=status,
            remarks=remarks,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

    async def _send_and_wait_for_commit(self, batch):
        # Send transaction to validator
        submit_request = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=[batch])
        await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            submit_request.SerializeToString())

        # Send status request to validator
        batch_id = batch.header_signature
        status_request = client_batch_submit_pb2.ClientBatchStatusRequest(
            batch_ids=[batch_id], wait=True)
        validator_response = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            status_request.SerializeToString())

        # Parse response
        status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
        status_response.ParseFromString(validator_response.content)
        status = status_response.batch_statuses[0].status
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
            error = status_response.batch_statuses[0].invalid_transactions[0]
            raise ApiBadRequest(error.message)
        elif status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
            raise ApiInternalError('Transaction submitted but timed out')
        elif status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            raise ApiInternalError('Something went wrong. Try again later')

    async def _query_validator(self,
                               request_type,
                               response_proto,
                               payload,
                               error_traps=None):
        """Sends a request to the validator and parses the response.
        """
        LOGGER.debug('Sending %s request to validator',
                     self._get_type_name(request_type))

        payload_bytes = payload.SerializeToString()
        response = await self._send_request(request_type, payload_bytes)
        content = self._parse_response(response_proto, response)

        LOGGER.debug('Received %s response from validator with status %s',
                     self._get_type_name(response.message_type),
                     self._get_status_name(response_proto, content.status))

        self._check_status_errors(response_proto, content, error_traps)
        return self._message_to_dict(content)

    async def _send_request(self, request_type, payload):
        """Uses an executor to send an asynchronous ZMQ request to the
        validator with the handler's Connection
        """
        try:
            return await self._connection.send(message_type=request_type,
                                               message_content=payload,
                                               timeout=self.TIMEOUT)
        except DisconnectError:
            LOGGER.warning('Validator disconnected while waiting for response')
            raise errors.ValidatorDisconnected()
        except asyncio.TimeoutError:
            LOGGER.warning('Timed out while waiting for validator response')
            raise errors.ValidatorTimedOut()

    @staticmethod
    def _parse_response(proto, response):
        """Parses the content from a validator response Message.
        """
        try:
            content = proto()
            content.ParseFromString(response.content)
            return content
        except (DecodeError, AttributeError):
            LOGGER.error('Validator response was not parsable: %s', response)
            raise errors.ValidatorResponseInvalid()

    @staticmethod
    def _get_type_name(type_enum):
        return Message.MessageType.Name(type_enum)

    @staticmethod
    def _get_status_name(proto, status_enum):
        try:
            return proto.Status.Name(status_enum)
        except ValueError:
            return 'Unknown ({})'.format(status_enum)

    @staticmethod
    def _check_status_errors(proto, content, error_traps=None):
        """Raises HTTPErrors based on error statuses sent from validator.
        Checks for common statuses and runs route specific error traps.
        """
        if content.status == proto.OK:
            return

        try:
            if content.status == proto.INTERNAL_ERROR:
                raise errors.UnknownValidatorError()
        except AttributeError:
            # Not every protobuf has every status enum, so pass AttributeErrors
            pass

        try:
            if content.status == proto.NOT_READY:
                raise errors.ValidatorNotReady()
        except AttributeError:
            pass

        try:
            if content.status == proto.NO_ROOT:
                raise errors.HeadNotFound()
        except AttributeError:
            pass

        try:
            if content.status == proto.INVALID_PAGING:
                raise errors.PagingInvalid()
        except AttributeError:
            pass

        try:
            if content.status == proto.INVALID_SORT:
                raise errors.SortInvalid()
        except AttributeError:
            pass

        # Check custom error traps from the particular route message
        if error_traps is not None:
            for trap in error_traps:
                trap.check(content.status)

    @staticmethod
    def _message_to_dict(message):
        """Converts a Protobuf object to a python dict with desired settings.
        """
        return MessageToDict(message,
                             including_default_value_fields=True,
                             preserving_proto_field_name=True)
Esempio n. 12
0
class Messenger(object):
    def __init__(self, validator_url, database):
        self._connection = Connection(validator_url)
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._batch_signer = self._crypto_factory.new_signer(
            self._context.new_random_private_key())
        self._database = database

    def open_validator_connection(self):
        self._connection.open()

    def close_validator_connection(self):
        self._connection.close()

    def get_new_key_pair(self):
        private_key = self._context.new_random_private_key()
        public_key = self._context.get_public_key(private_key)
        return public_key.as_hex(), private_key.as_hex()

    async def send_create_election_transaction(
            self, private_key, election_id, name, description, start_timestamp,
            end_timestamp, results_permission, can_change_vote,
            can_show_realtime, admin_id, status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_election_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            election_id=election_id,
            name=name,
            description=description,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp,
            results_permission=results_permission,
            can_change_vote=can_change_vote,
            can_show_realtime=can_show_realtime,
            admin_id=admin_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            election = await self._database.fetch_election_resource(
                election_id=election_id)

            if election is not None:
                break

            LOGGER.info("Invalid transaction. Retrying...")
            count_tries = count_tries + 1

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_create_voting_option_transaction(self, private_key,
                                                    voting_option_id, name,
                                                    description, election_id,
                                                    status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_voting_option_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voting_option_id=voting_option_id,
            name=name,
            description=description,
            election_id=election_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            voting_option = await self._database.fetch_voting_option_resource(
                voting_option_id=voting_option_id)

            if voting_option is not None:
                break

            LOGGER.info("Invalid transaction. Retrying...")
            count_tries = count_tries + 1

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_create_poll_registration_transaction(
            self, private_key, voter_id, name, election_id, status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_poll_registration_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voter_id=voter_id,
            name=name,
            election_id=election_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            poll_book_registration = await self._database.fetch_poll_book_registration(
                election_id=election_id, voter_id=voter_id)

            if poll_book_registration is not None:
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_create_voter_transaction(self, private_key, voter_id,
                                            public_key, name, created_at,
                                            type):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_voter_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voter_id=voter_id,
            public_key=public_key,
            name=name,
            created_at=created_at,
            type=type)

        count_tries = 0

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            voter = await self._database.fetch_voter_resource(voter_id=voter_id
                                                              )
            if voter is not None:
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_update_voter_transaction(self, private_key, voter_id,
                                            public_key, name, created_at,
                                            type):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_voter_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voter_id=voter_id,
            public_key=public_key,
            name=name,
            created_at=created_at,
            type=type)

        count_tries = 0

        original_voter = await self._database.fetch_voter_resource(
            voter_id=voter_id)

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            voter = await self._database.fetch_voter_resource(voter_id=voter_id
                                                              )
            if voter is not None and original_voter.get("end_block_num") == voter.get("end_block_num") \
                    and original_voter.get("start_block_num") != voter.get("start_block_num"):
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_create_vote_transaction(self, private_key, vote_id,
                                           timestamp, voter_id, election_id,
                                           voting_option_id):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_vote_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            vote_id=vote_id,
            timestamp=timestamp,
            voter_id=voter_id,
            election_id=election_id,
            voting_option_id=voting_option_id)

        count_tries = 0

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            vote = await self._database.fetch_vote_resource(vote_id=vote_id)
            if vote is not None:
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_update_vote_transaction(self, private_key, vote_id,
                                           timestamp, voting_option_id):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_vote_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            vote_id=vote_id,
            timestamp=timestamp,
            voting_option_id=voting_option_id)

        count_tries = 0

        original_vote = await self._database.fetch_vote_resource(
            vote_id=vote_id)

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            vote = await self._database.fetch_vote_resource(vote_id=vote_id)
            if vote is not None and original_vote.get("end_block_num") == vote.get("end_block_num") \
                    and original_vote.get("start_block_num") != vote.get("start_block_num"):
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_update_election_transaction(
            self, private_key, election_id, name, description, start_timestamp,
            end_timestamp, results_permission, can_change_vote,
            can_show_realtime, admin_id, status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_election_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            election_id=election_id,
            name=name,
            description=description,
            start_timestamp=start_timestamp,
            end_timestamp=end_timestamp,
            results_permission=results_permission,
            can_change_vote=can_change_vote,
            can_show_realtime=can_show_realtime,
            admin_id=admin_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        original_election = await self._database.fetch_election_resource(
            election_id=election_id)

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            election = await self._database.fetch_election_resource(
                election_id=election_id)
            if election is not None and original_election.get("end_block_num") == election.get("end_block_num") \
                    and original_election.get("start_block_num") != election.get("start_block_num"):
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_update_voting_option_status_transaction(
            self, private_key, voting_option_id, name, description,
            election_id, status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_voting_option_status_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voting_option_id=voting_option_id,
            name=name,
            description=description,
            election_id=election_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        original_voting_option = await self._database.fetch_voting_option_resource(
            voting_option_id=voting_option_id)

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            voting_option = await self._database.fetch_voting_option_resource(
                voting_option_id=voting_option_id)
            if voting_option is not None and original_voting_option.get("end_block_num") == voting_option.get("end_block_num") \
                    and original_voting_option.get("start_block_num") != voting_option.get("start_block_num"):
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def send_update_voter_poll_book_status_transaction(
            self, private_key, voter_id, name, election_id, status, timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_poll_book_status_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            voter_id=voter_id,
            name=name,
            election_id=election_id,
            status=status,
            timestamp=timestamp)

        count_tries = 0

        original_poll_book_registration = await self._database.fetch_poll_book_registration(
            election_id=election_id, voter_id=voter_id)

        while await self._send_and_wait_for_commit(
                batch) is False and count_tries < MAX_TRIES:
            poll_book_registration = await self._database.fetch_poll_book_registration(
                election_id=election_id, voter_id=voter_id)

            if poll_book_registration is not None \
                    and original_poll_book_registration.get("end_block_num") == poll_book_registration.get("end_block_num") \
                    and original_poll_book_registration.get("start_block_num") != poll_book_registration.get("start_block_num"):
                break

            LOGGER.debug("Invalid transaction. Retrying...")

        if count_tries == MAX_TRIES:
            raise ApiInternalError(
                "Invalid transaction. MAX_TRIES limit reached.")

    async def _send_and_wait_for_commit(self, batch):
        # Send transaction to validator
        submit_request = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=[batch])
        res = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            submit_request.SerializeToString(), 500)

        submit_response = client_batch_submit_pb2.ClientBatchSubmitResponse()
        submit_response.ParseFromString(res.content)

        # Send status request to validator
        batch_id = batch.header_signature
        status_request = client_batch_submit_pb2.ClientBatchStatusRequest(
            batch_ids=[batch_id], wait=True, timeout=500)
        validator_response = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            status_request.SerializeToString(), 500)

        # Parse response
        status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
        status_response.ParseFromString(validator_response.content)
        status = status_response.batch_statuses[0].status
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID \
                or status == client_batch_submit_pb2.ClientBatchStatus.PENDING \
                or status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            return False

        return True
Esempio n. 13
0
def main():
    loop = ZMQEventLoop()
    asyncio.set_event_loop(loop)

    connection = None
    try:
        opts = parse_args(sys.argv[1:])
        opts_config = RestApiConfig(
            bind=opts.bind,
            connect=opts.connect,
            timeout=opts.timeout,
            opentsdb_url=opts.opentsdb_url,
            opentsdb_db=opts.opentsdb_db)
        rest_api_config = load_rest_api_config(opts_config)
        url = None
        if "tcp://" not in rest_api_config.connect:
            url = "tcp://" + rest_api_config.connect
        else:
            url = rest_api_config.connect

        connection = Connection(url)

        log_config = get_log_config(filename="rest_api_log_config.toml")

        # If no toml, try loading yaml
        if log_config is None:
            log_config = get_log_config(filename="rest_api_log_config.yaml")

        if log_config is not None:
            log_configuration(log_config=log_config)
        else:
            log_dir = get_log_dir()
            log_configuration(log_dir=log_dir, name="rest_api")
        init_console_logging(verbose_level=opts.verbose)

        try:
            host, port = rest_api_config.bind[0].split(":")
            port = int(port)
        except ValueError as e:
            print("Unable to parse binding {}: Must be in the format"
                  " host:port".format(rest_api_config.bind[0]))
            sys.exit(1)

        wrapped_registry = None
        if rest_api_config.opentsdb_url:
            LOGGER.info("Adding metrics reporter: url=%s, db=%s",
                        rest_api_config.opentsdb_url,
                        rest_api_config.opentsdb_db)

            url = urlparse(rest_api_config.opentsdb_url)
            proto, db_server, db_port, = url.scheme, url.hostname, url.port

            registry = MetricsRegistry()
            wrapped_registry = MetricsRegistryWrapper(registry)

            reporter = InfluxReporter(
                registry=registry,
                reporting_interval=10,
                database=rest_api_config.opentsdb_db,
                prefix="sawtooth_rest_api",
                port=db_port,
                protocol=proto,
                server=db_server,
                username=rest_api_config.opentsdb_username,
                password=rest_api_config.opentsdb_password)
            reporter.start()

        start_rest_api(
            host,
            port,
            connection,
            int(rest_api_config.timeout),
            wrapped_registry)
        # pylint: disable=broad-except
    except Exception as e:
        LOGGER.exception(e)
        sys.exit(1)
    finally:
        if connection is not None:
            connection.close()
class Messenger(object):
    def __init__(self, validator_url):
        self._connection = Connection(validator_url)
        self._context = create_context('secp256k1')
        self._crypto_factory = CryptoFactory(self._context)
        self._batch_signer = self._crypto_factory.new_signer(
            self._context.new_random_private_key())

    def open_validator_connection(self):
        self._connection.open()

    def close_validator_connection(self):
        self._connection.close()

    def get_new_key_pair(self):
        private_key = self._context.new_random_private_key()
        public_key = self._context.get_public_key(private_key)
        return public_key.as_hex(), private_key.as_hex()

    async def send_create_user_transaction(self,
                                            private_key,
                                            username,
                                            role,
                                            timestamp):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_create_user_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            username=username,
            role=role,
            timestamp=timestamp)
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_drug_import_transaction(self,
                                          private_key,
                                          timestamp,
                                         id,
                                         name
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_drug_import_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            name=name
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_company_import_transaction(self,
                                            private_key,
                                            timestamp,
                                            id,
                                            name,
                                            date,
                                            address
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_company_import_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            name=name,
            date=date,
            address=address
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_employee_import_transaction(self,
                                            private_key,
                                            timestamp,
                                            id,
                                            name,
                                            age,
                                            address, 
                                            email,
                                            company_id
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_employee_import_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            name=name,
            age=age,
            address=address, 
            email=email,
            company_id=company_id
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_get_drug_transaction(self,
                                        private_key,
                                        timestamp,
                                        id
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_get_drug_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_get_company_transaction(self,
                                        private_key,
                                        timestamp,
                                        id
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_get_company_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id
            )
        await self._send_and_wait_for_commit(batch)

        return batch
    
    async def send_get_employee_transaction(self,
                                        private_key,
                                        timestamp,
                                        id
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_get_employee_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_update_status_transaction(self,
                                          private_key,
                                          timestamp,
                                         id,
                                         quantity,
                                         price
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_status_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            quantity=quantity,
            price=price
            )
        await self._send_and_wait_for_commit(batch)

        return batch
    async def send_update_location_transaction(self,
                                          private_key,
                                          timestamp,
                                         id,
                                         longitude,
                                         latitude
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_location_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            longitude=longitude,
            latitude=latitude
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_update_company_transaction(self,
                                          private_key,
                                          timestamp,
                                         id,
                                         address,
                                         price_IPO
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_company_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            address=address,
            price_IPO=price_IPO
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def send_update_employee_transaction(self,
                                          private_key,
                                          timestamp,
                                         id,
                                         position,
                                         salary
                                        ):
        transaction_signer = self._crypto_factory.new_signer(
            secp256k1.Secp256k1PrivateKey.from_hex(private_key))

        batch = make_update_employee_transaction(
            transaction_signer=transaction_signer,
            batch_signer=self._batch_signer,
            timestamp=timestamp,
            id=id,
            position=position,
            salary=salary
            )
        await self._send_and_wait_for_commit(batch)

        return batch

    async def _send_and_wait_for_commit(self, batch):
        # Send transaction to validator
        submit_request = client_batch_submit_pb2.ClientBatchSubmitRequest(
            batches=[batch])
        await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST,
            submit_request.SerializeToString())

        # Send status request to validator
        batch_id = batch.header_signature
        status_request = client_batch_submit_pb2.ClientBatchStatusRequest(
            batch_ids=[batch_id], wait=True)
        validator_response = await self._connection.send(
            validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST,
            status_request.SerializeToString())

        # Parse response
        status_response = client_batch_submit_pb2.ClientBatchStatusResponse()
        status_response.ParseFromString(validator_response.content)
        status = status_response.batch_statuses[0].status
        if status == client_batch_submit_pb2.ClientBatchStatus.INVALID:
            error = status_response.batch_statuses[0].invalid_transactions[0]
            raise ApiBadRequest(error.message)
        elif status == client_batch_submit_pb2.ClientBatchStatus.PENDING:
            raise ApiInternalError('Transaction submitted but timed out')
        elif status == client_batch_submit_pb2.ClientBatchStatus.UNKNOWN:
            raise ApiInternalError('Something went wrong. Try again later')