def test_duplicate_name(self):
        # Create a mock store
        store = MarketPlaceGlobalStore()

        # Because we have not "registered" any participants, the name
        # should not be a duplicate
        update = participant_update.UpdateName(
            update_type=participant_update.UpdateName.UpdateType,
            object_id='0000000000000000',
            creator_id='0000000000000000',
            name='participant')
        self.assertTrue(update.is_valid_name(store))

        # Put a participant in the store
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000', minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because the participant name is in the store, trying to update the
        # name a valid name as it is a duplicate
        update = participant_update.UpdateName(
            update_type=participant_update.UpdateName.UpdateType,
            object_id=participant.ObjectID,
            creator_id=participant.ObjectID,
            name='participant')
        self.assertFalse(update.is_valid_name(store))
    def test_duplicate_name(self):
        # Create a mock store and put a participant in it
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000',
            minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because we have not "registered" any asset types, the name
        # should not be a duplicate
        update = asset_type_update.Register(
            update_type=asset_type_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='/assettype'
        )
        self.assertTrue(market_place_object_update.global_is_valid_name(
            store,
            name='/assettype',
            object_type=update.ObjectType,
            creator_id=participant.ObjectID))

        # Add an asset type to the store with the creator being the
        # participant we inserted initially
        asset_type = asset_type_update.AssetTypeObject(
            objectid='0000000000000001',
            minfo={
                'name': '//participant/assettype',
                'creator': participant.ObjectID
            })
        store[asset_type.ObjectID] = asset_type.dump()

        # Because the asset type name is in the store, trying to register
        # using a relative name based upon creator and a fully-qualified name
        # should not be a valid name as it is a duplicate
        asset_type = asset_type_update.Register(
            update_type=asset_type_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='/assettype'
        )
        self.assertFalse(market_place_object_update.global_is_valid_name(
            store,
            name='/assettype',
            object_type=asset_type.ObjectType,
            creator_id=participant.ObjectID))

        update = asset_type_update.Register(
            update_type=asset_type_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='//participant/assettype'
        )
        self.assertFalse(market_place_object_update.global_is_valid_name(
            store,
            name='//participant/assettype',
            object_type=update.ObjectType,
            creator_id=participant.ObjectID))
Esempio n. 3
0
    def test_duplicate_name(self):
        # Create a mock store and put a participant in it
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000', minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because we have not "registered" any sell offers, the name
        # should not be a duplicate
        update = sell_offer_update.Register(
            input_id='**FAKE**',
            output_id='**FAKE**',
            update_type=sell_offer_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='/selloffer')
        self.assertTrue(
            market_place_object_update.global_is_valid_name(
                store, '/selloffer', sell_offer_update.Register.ObjectType,
                participant.ObjectID))

        # Add a sell offer to the store with the creator being the participant
        # we inserted initially
        sell_offer = sell_offer_update.SellOfferObject(
            objectid='0000000000000001',
            minfo={
                'name': '//participant/selloffer',
                'creator': participant.ObjectID
            })
        store[sell_offer.ObjectID] = sell_offer.dump()

        # Because the sell offer name is in the store, trying to register
        # using a relative name based upon creator and a fully-qualified name
        # should not be a valid name as it is a duplicate
        update = sell_offer_update.Register(
            input_id='**FAKE**',
            output_id='**FAKE**',
            update_type=sell_offer_update.Register,
            creator_id=participant.ObjectID,
            name='/selloffer')
        self.assertFalse(
            market_place_object_update.global_is_valid_name(
                store, '/selloffer', sell_offer_update.Register.ObjectType,
                participant.ObjectID))
        update = sell_offer_update.Register(
            update_type=sell_offer_update.Register.UpdateType,
            input_id='**FAKE**',
            output_id='**FAKE**',
            creator_id=participant.ObjectID,
            name='//participant/selloffer')
        self.assertFalse(
            market_place_object_update.global_is_valid_name(
                store, '//participant/selloffer',
                sell_offer_update.Register.ObjectType, participant.ObjectID))
Esempio n. 4
0
    def test_duplicate_name(self):
        # Create a mock store and put a participant in it
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000',
            minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because we have not "registered" any liabilities, the name
        # should not be a duplicate
        update = liability_update.Register(
            update_type=liability_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='/liability'
        )
        self.assertTrue(global_is_valid_name(
            store, '/liability',
            liability_update.Register.ObjectType,
            participant.ObjectID))

        # Add a liability to the store with the creator being the participant
        # we inserted initially
        liability = liability_update.LiabilityObject(
            objectid='0000000000000001',
            minfo={
                'name': '//participant/liability',
                'creator': participant.ObjectID
            })
        store[liability.ObjectID] = liability.dump()

        # Because the liability name is in the store, trying to register using
        # a relative name based upon creator and a fully-qualified name should
        # not be a valid name as it is a duplicate
        update = liability_update.Register(
            update_type=liability_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='/liability'
        )
        self.assertFalse(global_is_valid_name(
            store, '/liability',
            liability_update.Register.ObjectType,
            participant.ObjectID))

        update = liability_update.Register(
            update_type=liability_update.Register.UpdateType,
            creator_id=participant.ObjectID,
            name='//participant/liability'
        )
        self.assertFalse(global_is_valid_name(
            store, '//participant/liability',
            liability_update.Register.ObjectType,
            participant.ObjectID))
    def fetch(self, store='MarketPlaceTransaction'):
        """
        Retrieve the current state from the validator. Rebuild
        the name, type, and id maps for the resulting objects.

        :param str store: optional, the name of the marketplace store to
            retrieve
        """

        logger.debug('fetch state from %s/%s/*', self.BaseURL, store)

        blockids = self.getmsg('/block?blockcount=10')
        blockid = blockids[0]

        if blockid == self.CurrentBlockID:
            return

        if self.CurrentBlockID in blockids:
            fetchlist = blockids[:blockids.index(self.CurrentBlockID)]
            for fetchid in reversed(fetchlist):
                logger.debug('only fetch delta of state for block %s', fetchid)
                delta = self.getmsg('/store/{0}/*?delta=1&blockid={1}'.format(
                    store, fetchid))
                self._state = self._state.clone_store(delta)
        else:
            logger.debug('full fetch of state for block %s', blockid)
            state = self.getmsg("/store/{0}/*?blockid={1}".format(
                store, blockid))
            self._state = \
                MarketPlaceGlobalStore(prevstore=None,
                                       storeinfo={
                                           'Store': state, 'DeletedKeys': []
                                       }
                                       )

        # State is actually a clone of the block state, this is a free
        # operation because of the copy on write implementation of the global
        #  store. This way market clients can update the state speculatively
        # without corrupting the synchronized storage
        self.State = self._state.clone_store()
        self.CurrentBlockID = blockid
    def test_duplicate_name(self):
        # Create a mock store and put a participant in it
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000',
            minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because we have not "registered" any exchange offers, the name
        # should not be a duplicate
        update = exchange_offer_update.UpdateName(
            update_type=exchange_offer_update.UpdateName.UpdateType,
            object_id='0000000000000001',
            creator_id=participant.ObjectID,
            name='/exchangeoffer'
        )
        self.assertTrue(update.is_valid_name(store))

        # Add an exchange offer to the store with the creator being the
        # participant we inserted initially
        exchange_offer = exchange_offer_update.ExchangeOfferObject(
            objectid='0000000000000001',
            minfo={
                'name': '//participant/exchangeoffer',
                'creator': participant.ObjectID
            })
        store[exchange_offer.ObjectID] = exchange_offer.dump()

        # Because the exchange offer name is in the store, trying to update
        # the name using a relative name based upon creator and a fully-
        # qualified name should not be a valid name as it is a duplicate
        update = exchange_offer_update.UpdateName(
            update_type=exchange_offer_update.UpdateName.UpdateType,
            object_id=exchange_offer.ObjectID,
            creator_id=participant.ObjectID,
            name='/exchangeoffer'
        )
        self.assertFalse(update.is_valid_name(store))
        update = exchange_offer_update.UpdateName(
            update_type=exchange_offer_update.UpdateName.UpdateType,
            object_id=exchange_offer.ObjectID,
            creator_id=participant.ObjectID,
            name='//participant/exchangeoffer'
        )
        self.assertFalse(update.is_valid_name(store))
    def test_duplicate_name(self):
        # Create a mock store and put a participant in it
        participant = participant_update.ParticipantObject(
            participantid='0000000000000000', minfo={
                'name': 'participant',
            })
        store = MarketPlaceGlobalStore()
        store[participant.ObjectID] = participant.dump()

        # Because we have not "registered" any accounts, the name
        # should not be a duplicate
        update = account_update.UpdateName(
            update_type=account_update.UpdateName.UpdateType,
            object_id='0000000000000001',
            creator_id=participant.ObjectID,
            name='/account')
        self.assertTrue(update.is_valid_name(store))

        # Add an account to the store with the creator being the participant
        # we inserted initially
        account = account_update.AccountObject(objectid='0000000000000001',
                                               minfo={
                                                   'name':
                                                   '//participant/account',
                                                   'creator':
                                                   participant.ObjectID
                                               })
        store[account.ObjectID] = account.dump()

        # Because the account name is in the store, trying to update the name
        # using a relative name based upon creator and a fully-qualified name
        # should not be a valid name as it is a duplicate
        update = account_update.UpdateName(
            update_type=account_update.UpdateName.UpdateType,
            object_id=account.ObjectID,
            creator_id=participant.ObjectID,
            name='/account')
        self.assertFalse(update.is_valid_name(store))
        update = account_update.UpdateName(
            update_type=account_update.UpdateName.UpdateType,
            object_id=account.ObjectID,
            creator_id=participant.ObjectID,
            name='//participant/account')
        self.assertFalse(update.is_valid_name(store))
    def fetch(self, store='MarketPlaceTransaction'):
        """
        Retrieve the current state from the validator. Rebuild
        the name, type, and id maps for the resulting objects.

        :param str store: optional, the name of the marketplace store to
            retrieve
        """

        logger.debug('fetch state from %s/%s/*', self.BaseURL, store)

        blockids = self.getmsg('/block?blockcount=10')
        blockid = blockids[0]

        if blockid == self.CurrentBlockID:
            return

        if self.CurrentBlockID in blockids:
            fetchlist = blockids[:blockids.index(self.CurrentBlockID)]
            for fetchid in reversed(fetchlist):
                logger.debug('only fetch delta of state for block %s', fetchid)
                delta = self.getmsg(
                    '/store/{0}/*?delta=1&blockid={1}'.format(store, fetchid))
                self._state = self._state.clone_store(delta)
        else:
            logger.debug('full fetch of state for block %s', blockid)
            state = self.getmsg(
                "/store/{0}/*?blockid={1}".format(store, blockid))
            self._state = \
                MarketPlaceGlobalStore(prevstore=None,
                                       storeinfo={
                                           'Store': state, 'DeletedKeys': []
                                       }
                                       )

        # State is actually a clone of the block state, this is a free
        # operation because of the copy on write implementation of the global
        #  store. This way market clients can update the state speculatively
        # without corrupting the synchronized storage
        self.State = self._state.clone_store()
        self.CurrentBlockID = blockid
Esempio n. 9
0
class MarketPlaceState(MarketPlaceCommunication):
    """
    A class to wrap the current ledger state for a market place. Retrieves
    the state from a validator and builds maps for names and ids. Exports
    methods for querying state.

    :param url baseurl: the base URL for a Sawtooth Lake validator that
        supports an HTTP interface
    :param id creator: the identifier for the participant generating
        transactions

    :var dict State: The key/value store associated with the head of the
        ledger, for the MarketPlace store, keys are object identifiers and the
        values are the current state of each object.

    """
    def __init__(self, baseurl, creator=None, creator_name=None):
        super(MarketPlaceState, self).__init__(baseurl)

        self._state = None
        self.State = None
        self.ScratchState = None
        self.CurrentBlockID = None

        self.fetch()

        self.CreatorID = creator
        if not self.CreatorID and creator_name:
            self.CreatorID = self.State.n2i('//' + creator_name, 'Participant')

    def n2i(self, name, obj_type):
        """
        Convert a name into an identifier. The name can take one of these
        forms:
        @ -- resolves to the identifier for creator
        ///<IDENTIFIER>  -- resolves to the identifier
        //<CREATOR>/<PATH> -- fully qualified name
        /<PATH> -- resolve relative to the current creator if specified

        :param str name: object name
        :return: object identifier
        :rtype: id
        """
        if name == '@':
            return self.CreatorID

        if not name.startswith('//'):
            cname = self.CreatorID
            if not cname:
                return None
            name = '{0}{1}'.format(cname, name)
        else:

            def unpack_indeterminate(creator, *path):
                return creator, path

            creator, path = unpack_indeterminate(*name[2:].split('/'))
            creator_id = self.State.n2i("//" + creator, 'Participant')
            if path:
                name = '{}/{}'.format(creator_id, "/".join(path))
            else:
                name = "//" + creator

        identifier = self.State.n2i(name, obj_type)
        if not identifier:
            logger.info('could not find identifier by name: %s', name)
        return identifier

    def i2n(self, objectid):
        """
        Construct the fully qualified name for an object

        If the object does not have a name the format will be ///<IDENTIFIER>
        If the object is a participant the format will be //<NAME>
        Otherwise the format will be //<CREATOR NAME>/<NAME>

        :param id objectid: identifier for the object
        :return: the fully qualified name for the object
        :rtype: str
        """
        return self.State.i2n(objectid)

    def fetch(self, store='MarketPlaceTransaction'):
        """
        Retrieve the current state from the validator. Rebuild
        the name, type, and id maps for the resulting objects.

        :param str store: optional, the name of the marketplace store to
            retrieve
        """

        logger.debug('fetch state from %s/%s/*', self.BaseURL, store)

        blockids = self.getmsg('/block?blockcount=10')
        blockid = blockids[0]

        if blockid == self.CurrentBlockID:
            return

        if self.CurrentBlockID in blockids:
            fetchlist = blockids[:blockids.index(self.CurrentBlockID)]
            for fetchid in reversed(fetchlist):
                logger.debug('only fetch delta of state for block %s', fetchid)
                delta = self.getmsg('/store/{0}/*?delta=1&blockid={1}'.format(
                    store, fetchid))
                self._state = self._state.clone_store(delta)
        else:
            logger.debug('full fetch of state for block %s', blockid)
            state = self.getmsg("/store/{0}/*?blockid={1}".format(
                store, blockid))
            self._state = MarketPlaceGlobalStore(prevstore=None,
                                                 storeinfo={
                                                     'Store': state,
                                                     'DeletedKeys': []
                                                 })

        # State is actually a clone of the block state, this is a free
        # operation because of the copy on write implementation of the global
        #  store. This way market clients can update the state speculatively
        # without corrupting the synchronized storage
        self.State = self._state.clone_store()
        self.CurrentBlockID = blockid

    def path(self, path):
        """
        Function to retrieve the value of a property of an object in the
        saved state

        Args:
            path -- '.' separate expression for extracting a value from state
        """

        pathargs = path.split('.')
        value = self.State
        while pathargs:
            value = value.get(pathargs.pop(0))

        return value

    def lambdafilter(self, *predicates):
        """
        Apply a series of predicates to state objects. Predicates are
        lambda expressions on the data of an object. See the Filters class
        for tools for creating lambda expressions.

        :param predicates: a list of predicates used to filter the set of
            objects
        :type predicates: list of lambda functions
        :returns: a list of object identifiers
        :rtype: list of identifiers
        """

        objlist = []
        for objid, objinfo in self.State.iteritems():
            match = True
            for predicate in predicates:
                if not predicate(objinfo):
                    match = False
                    break

            if match:
                objlist.append(objid)

        return objlist

    def list(self, objtype=None, creator=None, name=None, fields=None):
        """
        Simple filter for common query operations on the current state
        """
        result = []
        for objid, objinfo in self.State.iteritems():
            if objtype and objinfo.get('object-type') != objtype:
                continue

            if creator and objinfo.get('creator') != creator:
                continue

            if name and not objinfo.get('name').startswith(name):
                continue

            # provide a couple useful properties
            objinfo['id'] = objid
            objinfo['fqname'] = self.i2n(objid)
            if not objinfo['name']:
                objinfo['name'] = '/id/' + objid

            if not fields:
                result.append(objid)
            elif fields == '*':
                result.append(objinfo)
            else:
                result.append([objinfo.get(fld) for fld in fields])

        return result
class MarketPlaceState(MarketPlaceCommunication):
    """
    A class to wrap the current ledger state for a market place. Retrieves
    the state from a validator and builds maps for names and ids. Exports
    methods for querying state.

    :param url baseurl: the base URL for a Sawtooth Lake validator that
        supports an HTTP interface
    :param id creator: the identifier for the participant generating
        transactions

    :var dict State: The key/value store associated with the head of the
        ledger, for the MarketPlace store, keys are object identifiers and the
        values are the current state of each object.

    """

    def __init__(self, baseurl, creator=None, creator_name=None):
        super(MarketPlaceState, self).__init__(baseurl)

        self._state = None
        self.State = None
        self.ScratchState = None
        self.CurrentBlockID = None

        self.fetch()

        self.CreatorID = creator
        if not self.CreatorID and creator_name:
            self.CreatorID = self.State.n2i('//' + creator_name)

    def bind(self, name, objectid):
        """
        Add a binding between a fully qualified name and an objectid

        :param str name: fully qualified object name
        :param id objectid: object identifier
        """

        return self.State.bind(name, objectid)

    def unbind(self, name):
        """
        Drop the binding of a name to an identifier

        :param str name: object name
        """
        return self.State.unbind(name)

    def n2i(self, name):
        """
        Convert a name into an identifier. The name can take one of these
        forms:
        @ -- resolves to the identifier for creator
        ///<IDENTIFIER>  -- resolves to the identifier
        //<CREATOR>/<PATH> -- fully qualified name
        /<PATH> -- resolve relative to the current creator if specified

        :param str name: object name
        :return: object identifier
        :rtype: id
        """
        if name == '@':
            return self.CreatorID

        if not name.startswith('//'):
            cname = self.i2n(self.CreatorID)
            if not cname:
                return None
            name = '{0}{1}'.format(cname, name)

        return self.State.n2i(name)

    def i2n(self, objectid):
        """
        Construct the fully qualified name for an object

        If the object does not have a name the format will be ///<IDENTIFIER>
        If the object is a participant the format will be //<NAME>
        Otherwise the format will be //<CREATOR NAME>/<NAME>

        :param id objectid: identifier for the object
        :return: the fully qualified name for the object
        :rtype: str
        """
        return self.State.i2n(objectid)

    def fetch(self, store='MarketPlaceTransaction'):
        """
        Retrieve the current state from the validator. Rebuild
        the name, type, and id maps for the resulting objects.

        :param str store: optional, the name of the marketplace store to
            retrieve
        """

        logger.debug('fetch state from %s/%s/*', self.BaseURL, store)

        blockids = self.getmsg('/block?blockcount=10')
        blockid = blockids[0]

        if blockid == self.CurrentBlockID:
            return

        if self.CurrentBlockID in blockids:
            fetchlist = blockids[:blockids.index(self.CurrentBlockID)]
            for fetchid in reversed(fetchlist):
                logger.debug('only fetch delta of state for block %s', fetchid)
                delta = self.getmsg(
                    '/store/{0}/*?delta=1&blockid={1}'.format(store, fetchid))
                self._state = self._state.clone_store(delta)
        else:
            logger.debug('full fetch of state for block %s', blockid)
            state = self.getmsg(
                "/store/{0}/*?blockid={1}".format(store, blockid))
            self._state = MarketPlaceGlobalStore(prevstore=None,
                                                 storeinfo={'Store': state,
                                                            'DeletedKeys': []})

        # State is actually a clone of the block state, this is a free
        # operation because of the copy on write implementation of the global
        #  store. This way market clients can update the state speculatively
        # without corrupting the synchronized storage
        self.State = self._state.clone_store()
        self.CurrentBlockID = blockid

    def path(self, path):
        """
        Function to retrieve the value of a property of an object in the
        saved state

        Args:
            path -- '.' separate expression for extracting a value from state
        """

        pathargs = path.split('.')
        value = self.State
        while pathargs:
            value = value.get(pathargs.pop(0))

        return value

    def lambdafilter(self, *predicates):
        """
        Apply a series of predicates to state objects. Predicates are
        lambda expressions on the data of an object. See the Filters class
        for tools for creating lambda expressions.

        :param predicates: a list of predicates used to filter the set of
            objects
        :type predicates: list of lambda functions
        :returns: a list of object identifiers
        :rtype: list of identifiers
        """

        objlist = []
        for objid, objinfo in self.State.iteritems():
            match = True
            for predicate in predicates:
                if not predicate(objinfo):
                    match = False
                    break

            if match:
                objlist.append(objid)

        return objlist

    def list(self, objtype=None, creator=None, name=None, fields=None):
        """
        Simple filter for common query operations on the current state
        """
        result = []
        for objid, objinfo in self.State.iteritems():
            if objtype and objinfo.get('object-type') != objtype:
                continue

            if creator and objinfo.get('creator') != creator:
                continue

            if name and not objinfo.get('name').startswith(name):
                continue

            # provide a couple useful properties
            objinfo['id'] = objid
            objinfo['fqname'] = self.i2n(objid)
            if not objinfo['name']:
                objinfo['name'] = '/id/' + objid

            if not fields:
                result.append(objid)
            elif fields == '*':
                result.append(objinfo)
            else:
                result.append([objinfo.get(fld) for fld in fields])

        return result