def _lock_asset(payload, signer, timestamp, state): """ Prevents an asset from being touched by locking it. To lock an asset, an rfid must be provided by the agent who last held it. Locking sets the locked field in history to true, and prevents further touchpoints being added to state without unlocking. """ _verify_agent(state, signer) rfid = payload.rfid if not rfid: raise InvalidTransaction( 'RFID needed to lock asset.') # Get the asset history. history_address = addressing.make_history_address(rfid) history_container = _get_container(state, history_address) try: history = next( entry for entry in history_container.entries if entry.rfid == rfid ) except StopIteration: raise InvalidTransaction( 'History could not be found. Asset likely doesn\'t exist.') touchpoint_index = history.curr_touchpoint_index touchpoint_address = addressing.make_touchpoint_address(rfid, touchpoint_index) touchpoint_container = _get_container(state, touchpoint_address) try: touchpoint = touchpoint_container.entries[0] except: raise InvalidTransaction('Unable to get needed touchpoint.') last_reporter = history.reporter_list[touchpoint.reporter_index] if not last_reporter.public_key == signer: raise InvalidTransaction('Not authorized to lock this asset.') history.locked = True _set_container(state, history_address, history_container)
def _unlock_asset(payload, signer, timestamp, state): """ Unlocks an asset to allow new touchpoints being created An agent needs the authorization to unlock an asset. The credentials lie with the last reported holder of the object. """ _verify_agent(state, signer) rfid = payload.rfid if not rfid: raise InvalidTransaction( 'RFID needed to lock asset.') # Get the asset history. history_address = addressing.make_history_address(rfid) history_container = _get_container(state, history_address) try: history = next( entry for entry in history_container.entries if entry.rfid == rfid ) except StopIteration: raise InvalidTransaction( 'History could not be found. Asset likely doesn\'t exist.') touchpoint_index = history.curr_touchpoint_index touchpoint_address = addressing.make_touchpoint_address(rfid, touchpoint_index) touchpoint_container = _get_container(state, touchpoint_address) try: touchpoint = touchpoint_container.entries[0] except: raise InvalidTransaction('Unable to get needed touchpoint.') last_reporter = history.reporter_list[touchpoint.reporter_index] if not last_reporter.public_key == signer: raise InvalidTransaction('Not authorized to unlock this asset.') history.locked = False _set_container(state, history_address, history_container)
def _touch_asset(payload, signer, timestamp, state): """ Adds a touchpoint to the list of existing touchpoints for a given asset. The position in the tree is determined by the addressing method used. LaceTP identifies an asset with a 6 character hash of the transaction family, followed by a single character to indicate an agent(2), asset(1) or history(0). All touchpoints have this single character set to asset(1). The final betweent this character and the final four is a random hash of 59 characters. The final four characters indicate the touchpoint index. The index can never be zero as that is reserved for the history. The touchpoint can wrap around zero. """ _verify_agent(state, signer) rfid = payload.rfid if not rfid: raise InvalidTransaction( 'Asset must have rfid.') # Get the asset history. history_address = addressing.make_history_address(rfid) history_container = _get_container(state, history_address) try: history = next( entry for entry in history_container.entries if entry.rfid == rfid ) except StopIteration: raise InvalidTransaction( 'History could not be found. Asset likely doesn\'t exist.') # Check for a lock if history.locked: raise InvalidTransaction( 'Asset is locked. You must unlock it or request that it be unlocked.') # Find the correct reporter index or loop out. reporter_count = INITIAL_REPORTER_INDEX reporter_index = -1 # reporter does not exist for reporter in history.reporter_list: if reporter.public_key == signer: reporter_index = reporter_count reporter_count += 1 touchpoint = TouchPoint ( longitude = payload.longitude, latitude = payload.latitude, reporter_index = INITIAL_REPORTER_INDEX, timestamp = timestamp, ) # Check if we need to create a new reporter list entry. if reporter_index == -1: # then it wasn't found reporter = Reporter( public_key = signer, authorization_level = DEFAULT_AUTH_LEVEL, ) history.reporter_list.extend([reporter]) touchpoint.reporter_index = len(history.reporter_list) - 1 else: touchpoint.reporter_index = reporter_index # Calculate index, considering that it may wrap around. if history.curr_touchpoint_index == MAX_TOUCH_POINT: history.has_wrapped = True history.curr_touchpoint_index = INITIAL_TOUCHPOINT_INDEX else: history.curr_touchpoint_index += 1 address = addressing.make_touchpoint_address(rfid, history.curr_touchpoint_index) container = _get_container(state, address) if len(container.entries) > 0: del container.entries[:] container.entries.extend([touchpoint]) else: container.entries.extend([touchpoint]) _set_container(state, address, container) _set_container(state, history_address, history_container)
def _create_asset(payload, signer, timestamp, state): """Creates a history and initial touchpoint for an asset. The position in the tree is determined by the addressing method used. LaceTP identifies an asset with a 6 character hash of the transaction family, followed by a single character to indicate an agent(2), asset(1) or history(0). All touchpoints have this single character set to asset(1). Between this character and the last four (59 chars) is a random hash of an rfid. The final four characters indicate the touchpoint index. The index can never be zero as that is reserved for the history. The touchpoint can wrap around zero. """ _verify_agent(state, signer) rfid = payload.rfid asset_address = addressing.make_asset_address(rfid) asset_container = _get_container(state, asset_address) if any(asset.rfid == rfid for asset in asset_container.entries): raise InvalidTransaction( 'Asset already exists') # Create the asset and extend the asset container. asset = Asset( rfid = payload.rfid, size = payload.size, sku = payload.sku, ) asset_container.entries.extend([asset]) # Create the history for the asset. history_address = addressing.make_history_address(rfid) history_container = _get_container(state, history_address) if any(history.rfid == rfid for history in history_container.entries): raise InvalidTransaction( 'History already exists for asset that didn\'t...') history = History( rfid = rfid, curr_touchpoint_index = INITIAL_TOUCHPOINT_INDEX, has_wrapped = False, ) history.reporter_list.extend([ Reporter( public_key = signer, authorization_level = DEFAULT_AUTH_LEVEL, # Default for now. ) ]) # Extend the history container history_container.entries.extend([history]) # Create the initial touchpoint touchpoint_address = addressing.make_touchpoint_address(rfid, INITIAL_TOUCHPOINT_INDEX) touchpoint_container = _get_container(state, touchpoint_address) touchpoint = TouchPoint( longitude = payload.longitude, latitude = payload.latitude, timestamp = timestamp, reporter_index = INITIAL_REPORTER_INDEX, ) # Extend touchpoint container. touchpoint_container.entries.extend([touchpoint]) # Set the state for the asset and its history. _set_container(state, asset_address, asset_container) _set_container(state, history_address, history_container) _set_container(state, touchpoint_address, touchpoint_container)