def state_put_single(state, uid, data): addresses = state.set([ StateEntry(address=uid, data=json.dumps(data, sort_keys=True).encode()) ]) if not addresses or uid not in addresses: raise InternalError("Error setting state, addresses returned: %s.", addresses)
def _set_config_value(state, key, value): address = _make_config_key(key) setting = _get_setting_entry(state, address) old_value = None old_entry_index = None for i, entry in enumerate(setting.entries): if key == entry.key: old_value = entry.value old_entry_index = i if old_entry_index is not None: setting.entries[old_entry_index].value = value else: setting.entries.add(key=key, value=value) try: addresses = list( state.set([ StateEntry(address=address, data=setting.SerializeToString()) ], timeout=STATE_TIMEOUT_SEC)) except FutureTimeoutError: LOGGER.warning('Timeout occured on state.set([%s, <value>])', address) raise InternalError('Unable to set {}'.format(key)) if len(addresses) != 1: LOGGER.warning('Failed to save value on address %s', address) raise InternalError('Unable to save config value {}'.format(key)) LOGGER.info('Config setting %s changed from %s to %s', key, old_value, value)
def apply(self, transaction, state_store): # 1. Deserialize the transaction and verify it is valid header = TransactionHeader() header.ParseFromString(transaction.header) stored_supplier_str = "" try: # The payload is csv utf-8 encoded string supplier_id, short_id, supplier_name, passwd, supplier_url, action, part_id = transaction.payload.decode( ).split(",") except ValueError: raise InvalidTransaction("Invalid payload serialization") validate_transaction(supplier_id, short_id, supplier_name, passwd, supplier_url, action, part_id) data_address = make_supplier_address(self._namespace_prefix, supplier_id) state_entries = state_store.get([data_address]) if len(state_entries) != 0: try: stored_supplier_id, stored_supplier_str = \ state_entries[0].data.decode().split(",",1) stored_supplier = json.loads(stored_supplier_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_supplier_id = stored_supplier = None if action == "create" and stored_supplier_id is not None: raise InvalidTransaction("Invalid Action-supplier already exists.") if action == "create": supplier = create_supplier(supplier_id, short_id, supplier_name, passwd, supplier_url) stored_supplier_id = supplier_id stored_supplier = supplier _display("Created a supplier.") if action == "AddPart": if part_id not in stored_supplier_str: supplier = add_part(part_id, stored_supplier) stored_supplier = supplier # Put data back in state storage stored_supp_str = json.dumps(stored_supplier) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_supplier_id, stored_supp_str]).encode()) ]) return addresses
def _set_state_data(name, state, state_store): address = make_intkey_address(name) encoded = cbor.dumps(state) addresses = state_store.set([StateEntry(address=address, data=encoded)]) if not addresses: raise InternalError('State error')
def _set_state_object(state, obj, tag): name = _get_unique_key(obj, tag) addresses = state.set([ StateEntry(address=make_omi_address(name, tag), data=obj.SerializeToString()) ]) if not addresses: raise InternalError('State error')
def _set_role(data, state): role = Role() role.ParseFromString(data) if not role.name: raise InvalidTransaction("The name must be set in a role") if not role.policy_name: raise InvalidTransaction("A role must contain a policy name.") # Check that the policy refernced exists policy_address = _get_policy_address(role.policy_name) entries_list = _get_data(policy_address, state) if entries_list == []: raise InvalidTransaction( "Cannot set Role: {}, the Policy: {} is not set.".format( role.name, role.policy_name)) else: policy_list = PolicyList() policy_list.ParseFromString(entries_list[0].data) exist = False for policy in policy_list.policies: if policy.name == role.policy_name: exist = True break if not exist: raise InvalidTransaction( "Cannot set Role {}, the Policy {} is not set.".format( role.name, role.policy_name)) address = _get_role_address(role.name) entries_list = _get_data(address, state) # Store role in a Roleist incase of hash collisions role_list = RoleList() if entries_list != []: role_list.ParseFromString(entries_list[0].data) # sort all roles by using sorted(roles, Role.name) roles = [x for x in role_list.roles if x.name != role.name] roles.append(role) roles = sorted(roles, key=lambda role: role.name) # set RoleList at the address above. addresses = state.set([ StateEntry(address=address, data=RoleList(roles=roles).SerializeToString()) ]) if not addresses: LOGGER.warning('Failed to set role %s at %s', role.name, address) raise InternalError('Unable to save role {}'.format(role.name)) LOGGER.debug("Set role: \n%s", role)
def _set(state, items): entries = [] for (addr, container) in items: entries.append( StateEntry(address=addr, data=container.SerializeToString())) result_addresses = state.set(entries) if result_addresses: for (addr, _) in items: if addr not in result_addresses: raise InternalError( "Error setting state, " + "address %s not set.", addr) else: raise InternalError("Error setting state nothing updated?")
def apply(self, transaction, state_store): header = TransactionHeader() header.ParseFromString(transaction.header) try: # The payload is csv utf-8 encoded string category_id, category_name, description, action = transaction.payload.decode( ).split(",") except ValueError: raise InvalidTransaction("Invalid payload") validate_transaction(category_id, category_name, description, action) data_address = create_category_address(self._namespace_prefix, category_id) state_entries = state_store.get([data_address]) # Retrieve data from state storage if len(state_entries) != 0: try: stored_category_id, stored_category_str = \ state_entries[0].data.decode().split(",",1) stored_category = json.loads(stored_category_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_category_id = stored_category = None # Validate category data if action == "create" and stored_category_id is not None: raise InvalidTransaction("Invalid Action-category already exists.") if action == "create": category = create_category_payload(category_id, category_name, description) stored_category_id = category_id stored_category = category _display("Created a category.") # Insert data back stored_supp_str = json.dumps(stored_category) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_category_id, stored_supp_str]).encode()) ]) return addresses
def apply(self, transaction, state_store): header = TransactionHeader() header.ParseFromString(transaction.header) try: # The payload is csv utf-8 encoded string user_public_key,user_name,email_address,authorized,role,action = transaction.payload.decode().split(",") except ValueError: raise InvalidTransaction("Invalid payload") validate_transaction(user_public_key,user_name,email_address,authorized,role,action) data_address = create_user_address(self._namespace_prefix,user_public_key) state_entries = state_store.get([data_address]) # Retrieve data from state storage if len(state_entries) != 0: try: stored_user_id, stored_user_str = \ state_entries[0].data.decode().split(",",1) stored_user = json.loads(stored_user_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_user_id = stored_user = None # Validate user data if action == "register" and stored_user_id is not None: raise InvalidTransaction("Invalid Action-user already exists.") if action == "register": user = create_user_payload(user_public_key,user_name,email_address,authorized,role) stored_user_id = user_public_key stored_user = user _display("Register a user.") # Insert data back stored_userAccount_str = json.dumps(stored_user) addresses = state_store.set([ StateEntry( address=data_address, data=",".join([stored_user_id, stored_userAccount_str]).encode() ) ]) return addresses
def _set_data(state, address, data): try: addresses = list( state.set([StateEntry(address=address, data=data)], timeout=STATE_TIMEOUT_SEC)) except FutureTimeoutError: LOGGER.warning('Timeout occured on state.set([%s, <value>])', address) raise InternalError( 'Failed to save value on address {}'.format(address)) if len(addresses) != 1: LOGGER.warning('Failed to save value on address %s', address) raise InternalError( 'Failed to save value on address {}'.format(address))
def _set_policy(data, state): new_policy = Policy() new_policy.ParseFromString(data) if not new_policy.entries: raise InvalidTransaction("Atleast one entry must be in a policy.") if not new_policy.name: raise InvalidTransaction("The name must be set in a policy.") # check entries in the policy for entry in new_policy.entries: if not entry.key: raise InvalidTransaction("Every policy entry must have a key.") address = _get_policy_address(new_policy.name) entries_list = _get_data(address, state) policy_list = PolicyList() policies = [] if entries_list != []: policy_list.ParseFromString(entries_list[0].data) # sort all roles by using sorted(roles, policy.name) # if a policy with the same name exists, replace that policy policies = [ x for x in policy_list.policies if x.name != new_policy.name ] policies.append(new_policy) policies = sorted(policies, key=lambda role: role.name) else: policies.append(new_policy) address = _get_policy_address(new_policy.name) # Store policy in a PolicyList incase of hash collisions new_policy_list = PolicyList(policies=policies) addresses = state.set([ StateEntry(address=address, data=new_policy_list.SerializeToString()) ]) if not addresses: LOGGER.warning('Failed to set policy %s at %s', new_policy.name, address) raise InternalError('Unable to save policy {}'.format(new_policy.name)) LOGGER.debug("Set policy : \n%s", new_policy)
def _store_state_data(state_store, game_list, name, board, state, player1, player2): game_list[name] = board, state, player1, player2 state_data = '|'.join( sorted([ ','.join([name, board, state, player1, player2]) for name, (board, state, player1, player2) in game_list.items() ])).encode() addresses = state_store.set( [StateEntry(address=_make_xo_address(name), data=state_data)]) if len(addresses) < 1: raise InternalError("State Error")
def apply(self, transaction, state_store): # 1. Deserialize the transaction and verify it is valid header = TransactionHeader() header.ParseFromString(transaction.header) # The transaction signer is the player player = header.signer_pubkey try: # The payload is csv utf-8 encoded string name, action, space = transaction.payload.decode().split(",") except ValueError: raise InvalidTransaction("Invalid payload serialization") if name == "": raise InvalidTransaction("Name is required") if '|' in name: raise InvalidTransaction('Name cannot contain "|"') if action == "": raise InvalidTransaction("Action is required") elif action == "take": try: space = int(space) except ValueError: raise InvalidTransaction( "Space could not be converted as an integer.") if space < 1 or space > 9: raise InvalidTransaction("Invalid space {}".format(space)) if action not in ("take", "create"): raise InvalidTransaction("Invalid Action : '{}'".format(action)) # 2. Retrieve the game data from state storage # Use the namespace prefix + the has of the game name to create the # storage address game_address = self._namespace_prefix \ + hashlib.sha512(name.encode("utf-8")).hexdigest()[0:64] # Get data from address state_entries = state_store.get([game_address]) # state_store.get() returns a list. If no data has been stored yet # at the given address, it will be empty. if state_entries: try: state_data = state_entries[0].data game_list = { name: (board, state, player1, player2) for name, board, state, player1, player2 in [ game.split(',') for game in state_data.decode().split('|') ] } board, state, player1, player2 = game_list[name] except ValueError: raise InternalError("Failed to deserialize game data.") else: game_list = {} board = state = player1 = player2 = None # 3. Validate the game data if action == "create" and board is not None: raise InvalidTransaction("Invalid Action: Game already exists.") elif action == "take": if board is None: raise InvalidTransaction( "Invalid Action: Take requires an existing game.") else: if state in ("P1-WIN", "P2-WIN", "TIE"): raise InvalidTransaction("Invalid Action: Game has ended.") elif state not in ("P1-NEXT", "P2-NEXT"): raise InternalError( "Game has reached an invalid state: {}".format(state)) # 4. Apply the transaction if action == "create": board = "---------" state = "P1-NEXT" player1 = "" player2 = "" elif action == "take": # Assign players if new game if player1 == "": player1 = player elif player2 == "": player2 = player # Verify player identity and take space lboard = list(board) if lboard[space - 1] != '-': raise InvalidTransaction( "Invalid Action: Space already taken.") if state == "P1-NEXT" and player == player1: lboard[space - 1] = "X" state = "P2-NEXT" elif state == "P2-NEXT" and player == player2: lboard[space - 1] = "O" state = "P1-NEXT" else: raise InvalidTransaction("Not this player's turn: {}".format( player[:6])) board = "".join(lboard) # Update game state if _is_win(board, "X"): state = "P1-WIN" elif _is_win(board, "O"): state = "P2-WIN" elif '-' not in board: state = "TIE" # 5. Log for tutorial usage if action == "create": _display("Player {} created a game.".format(player[:6])) elif action == "take": _display( "Player {} takes space: {}\n\n".format(player[:6], space) + _game_data_to_str(board, state, player1, player2, name)) # 6. Put the game data back in state storage game_list[name] = board, state, player1, player2 state_data = '|'.join( sorted([ ','.join([name, board, state, player1, player2]) for name, (board, state, player1, player2) in game_list.items() ])).encode() addresses = state_store.set( [StateEntry(address=game_address, data=state_data)]) if len(addresses) < 1: raise InternalError("State Error")
def apply(self, transaction, state_store): # 1. Deserialize the transaction and verify it is valid header = TransactionHeader() header.ParseFromString(transaction.header) # The transaction signer is the player player = header.signer_pubkey try: # The payload is csv utf-8 encoded string name, action, space = transaction.payload.decode().split(",") except: raise InvalidTransaction("Invalid payload serialization") if name == "": raise InvalidTransaction("Name is required") if action == "": raise InvalidTransaction("Action is required") elif action == "take": try: space = int(space) except: raise InvalidTransaction( "Space could not be converted as an integer.") if space < 1 or space > 9: raise InvalidTransaction("Invalid space {}".format(space)) if action not in ("take", "create"): raise InvalidTransaction("Invalid Action : '{}'".format(action)) # 2. Retrieve the game data from state storage # Use the namespace prefix + the has of the game name to create the # storage address game_address = self._namespace_prefix \ + hashlib.sha512(name.encode("utf-8")).hexdigest() # Get data from address state_entries = state_store.get([game_address]) # state_store.get() returns a list. If no data has been stored yet # at the given address, it will be empty. if len(state_entries) != 0: try: board, state, player1, player2, stored_name = \ state_entries[0].data.decode().split(",") except: raise InternalError("Failed to deserialize game data.") # NOTE: Since the game data is stored in a Merkle tree, there is a # small chance of collision. A more correct usage would be to store # a dictionary of games so that multiple games could be store at # the same location. See the python intkey handler for an example # of this. if stored_name != name: raise InternalError("Hash collision") else: board = state = player1 = player2 = None # 3. Validate the game data if action == "create" and board is not None: raise InvalidTransaction("Invalid Action: Game already exists.") elif action == "take": if board is None: raise InvalidTransaction( "Invalid Action: Take requires an existing game.") else: if state in ("P1-WIN", "P2-WIN", "TIE"): raise InvalidTransaction("Invalid Action: Game has ended.") elif state not in ("P1-NEXT", "P2-NEXT"): raise InternalError( "Game has reached an invalid state: {}".format(state)) # 4. Apply the transaction if action == "create": board = "---------" state = "P1-NEXT" player1 = "" player2 = "" elif action == "take": # Assign players if new game if player1 == "": player1 = player elif player2 == "": player2 = player # Verify player identity and take space lboard = list(board) if lboard[space - 1] != '-': raise InvalidTransaction( "Invalid Action: Space already taken.") if state == "P1-NEXT" and player == player1: lboard[space - 1] = "X" state = "P2-NEXT" elif state == "P2-NEXT" and player == player2: lboard[space - 1] = "O" state = "P1-NEXT" else: raise InvalidTransaction("Not this player's turn: {}".format( player[:6])) board = "".join(lboard) # Update game state if _is_win(board, "X"): state = "P1-WIN" elif _is_win(board, "O"): state = "P2-WIN" elif '-' not in board: state = "TIE" # 5. Log for tutorial usage if action == "create": _display("Player {} created a game.".format(player[:6])) elif action == "take": _display( "Player {} takes space: {}\n\n".format(player[:6], space) + _game_data_to_str(board, state, player1, player2, name)) # 6. Put the game data back in state storage addresses = state_store.set([ StateEntry(address=game_address, data=",".join([board, state, player1, player2, name]).encode()) ]) if len(addresses) < 1: raise InternalError("State Error")
def apply(self, transaction, state_store): # Deserialize the transaction and verify it is valid artifact_id, short_id, artifact_name, artifact_type, artifact_checksum, path, uri, label, openchain, action, sub_artifact_id, signer = extract_transaction( transaction) if artifact_id == "": raise InvalidTransaction("envelope Data is required") if action == "": raise InvalidTransaction("Action is required") # Checks to see if the action is valid or not if action not in ("create", "list-envelope", "show-envelope", "AddArtifact"): raise InvalidTransaction("Invalid Action '{}'".format(action)) data_address = self._namespace_prefix \ + hashlib.sha512(artifact_id.encode("utf-8")).hexdigest() # Retrieve data from address state_entries = state_store.get([data_address]) # Checks to see if the list is not empty if len(state_entries) != 0: try: stored_artifact_id, stored_artifact_str = \ state_entries[0].data.decode().split(",",1) stored_envelope = json.loads(stored_artifact_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_artifact_id = stored_envelope = None # 3. Validate the envelope data if action == "create" and stored_artifact_id is not None: raise InvalidTransaction("Invalid Action-envelope already exists.") if action == "create": artifact = create_artifact(artifact_id, short_id, artifact_name, artifact_type, artifact_checksum, path, uri, label, openchain) stored_artifact_id = artifact_id stored_artifact = artifact _display("Created a envelope.") if action == "AddArtifact": if sub_artifact_id not in stored_artifact_str: artifact = add_artifact(sub_artifact_id, stored_artifact) stored_artifact = artifact stored_artifact_str = json.dumps(stored_envelope) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_artifact_id, stored_artifact_str]).encode()) ]) if len(addresses) < 1: raise InternalError("State Error")
def apply(self, transaction, state): content = cbor.loads(transaction.payload) print(repr(content)) (verb, name, value) = \ (content['Verb'], content['Name'], content['Value']) if verb is None or len(verb) < 1: raise InvalidTransaction("Verb is required") if name is None or len(name) < 1: raise InvalidTransaction("Name is required") if value is None: raise InvalidTransaction("Value is required") if verb not in ['set', 'inc', 'dec']: raise InvalidTransaction("invalid Verb: '{}'".format(verb)) address = self._namespace_prefix + hashlib.sha512( name.encode()).hexdigest() entries_list = state.get([address]) state_value_rep = entries_list[0].data \ if len(entries_list) != 0 else None LOGGER.info("STATE VALUE %s", state_value_rep) if verb in ['inc', 'dec'] and (state_value_rep is None): raise InvalidTransaction("inc/dec require existing value") if verb == 'set': state_value = None if state_value_rep is not None: state_value = cbor.loads(state_value_rep) if name in state_value: raise InvalidTransaction( "Verb was 'set', but already exists: " "Name: {}, Value {}".format(name, state_value.get(name))) if state_value is None: data = {} else: data = {k: v for k, v in state_value.iteritems()} data[name] = value addresses = list( state.set([StateEntry(address=address, data=cbor.dumps(data))])) elif verb == 'inc': state_value = cbor.loads(state_value_rep) if name not in state_value: raise InvalidTransaction( "Verb was 'inc' but Name, {}, not in state.".format(name)) if int(value) < 0: raise InvalidTransaction( "Verb was 'inc', but Value was negative: {}".format(value)) state_value[name] = int(state_value[name]) + int(value) addresses = list( state.set([ StateEntry(address=address, data=cbor.dumps(state_value)) ])) elif verb == 'dec': state_value = cbor.loads(state_value_rep) if name not in state_value: raise InvalidTransaction( "Verb was 'dec', but Name, {}, not in state.".format(name)) if int(state_value[name]) - int(value) < 0: raise InvalidTransaction( "Verb was 'dec', but resulting value would be negative") state_value[name] = int(state_value[name]) - int(value) addresses = list( state.set([ StateEntry(address=address, data=cbor.dumps(state_value)) ])) else: # This would be a programming error. raise InternalError('unhandled Verb') if len(addresses) == 0: raise InternalError("State Error.")
def apply(self, transaction, state_store): header = TransactionHeader() header.ParseFromString(transaction.header) try: # The payload is csv utf-8 encoded string artifact_id,short_id,artifact_name,artifact_type,artifact_checksum,path,uri,label,openchain, action, sub_artifact_id = transaction.payload.decode().split(",") except ValueError: raise InvalidTransaction("Invalid payload serialization") validate_transaction(artifact_id,short_id,artifact_name,artifact_type,artifact_checksum,path,uri,label,openchain, action, sub_artifact_id) data_address = make_artifact_address(self._namespace_prefix,artifact_id) if artifact_id == "": raise InvalidTransaction("Artifact Data is required") if action == "": raise InvalidTransaction("Action is required") state_entries = state_store.get([data_address]) if len(state_entries) != 0: try: stored_artifact_id, stored_artifact_str = \ state_entries[0].data.decode().split(",",1) stored_artifact = json.loads(stored_artifact_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_artifact_id = stored_artifact = None # 3. Validate the envelope data if action == "create" and stored_artifact_id is not None: raise InvalidTransaction("Invalid Action-Envelope already exists.") elif action == "AddArtifact": if stored_artifact_id is None: raise InvalidTransaction( "Invalid Action-Add Artifact requires an existing envelope." ) if action == "create": artifact = create_artifact(artifact_id,short_id,artifact_name,artifact_type,artifact_checksum,path,uri,label,openchain) stored_artifact_id = artifact_id stored_artifact = artifact _display("Created an artifact.") if action == "AddArtifact": if sub_artifact_id not in stored_artifact_str: artifact = add_artifact(sub_artifact_id,stored_artifact) stored_artifact = artifact stored_art_str = json.dumps(stored_artifact) addresses = state_store.set([ StateEntry( address=data_address, data=",".join([stored_artifact_id, stored_art_str]).encode() ) ]) return addresses
def apply(self, transaction, state_store): # Deserialize the transaction and verify it is valid supplier_id, short_id, supplier_name, passwd, supplier_url, action, part_id, signer = extract_transaction( transaction) if supplier_id == "": raise InvalidTransaction("supplier Data is required") if action == "": raise InvalidTransaction("Action is required") # Checks to see if the action is valid or not if action not in ("create", "list-supplier", "show-supplier", "AddPart"): raise InvalidTransaction("Invalid Action '{}'".format(action)) data_address = self._namespace_prefix \ + hashlib.sha512(supplier_id.encode("utf-8")).hexdigest() # Retrieve data from address state_entries = state_store.get([data_address]) # Checks to see if the list is not empty if len(state_entries) != 0: try: stored_supplier_id, stored_supplier_str = \ state_entries[0].data.decode().split(",",1) stored_supplier = json.loads(stored_supplier_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_supplier_id = stored_supplier = None # Validate the envelope data if action == "create" and stored_supplier_id is not None: raise InvalidTransaction("Invalid Action-supplier already exists.") if action == "create": supplier = create_supplier(supplier_id, short_id, supplier_name, passwd, supplier_url) stored_supplier_id = supplier_id stored_supplier = supplier _display("Created a supplier.") if action == "AddPart": if part_id not in stored_supplier_str: supplier = add_part(part_id, stored_supplier) stored_supplier = supplier stored_cat_str = json.dumps(stored_supplier) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_supplier_id, stored_cat_str]).encode()) ]) if len(addresses) < 1: raise InternalError("State Error")
def apply(self, transaction, state_store): header = TransactionHeader() header.ParseFromString(transaction.header) try: # The payload is csv utf-8 encoded string pt_id, pt_name, checksum, version, alias, licensing, label, description, action, artifact_id, category_id, supplier_id = transaction.payload.decode( ).split(",") except ValueError: raise InvalidTransaction("Invalid payload serialization") validate_transaction(pt_id, action) data_address = make_part_address(self._namespace_prefix, pt_id) # Retrieve the data from state storage state_entries = state_store.get([data_address]) if len(state_entries) != 0: try: stored_pt_id, stored_pt_str = \ state_entries[0].data.decode().split(",",1) stored_pt = json.loads(stored_pt_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_pt_id = stored_pt = None if action == "create" and stored_pt_id is not None: raise InvalidTransaction("Invalid part already exists.") elif action == "AddArtifact" or action == "AddSupplier" or action == "AddCategory": if stored_pt_id is None: raise InvalidTransaction( "Invalid the operation requires an existing part.") if action == "create": pt = create_part(pt_id, pt_name, checksum, version, alias, licensing, label, description) stored_pt_id = pt_id stored_pt = pt _display("Created a part.") if action == "AddArtifact": if artifact_id not in stored_pt_str: pt = add_artifact(artifact_id, stored_pt) stored_pt = pt if action == "AddSupplier": if supplier_id not in stored_pt_str: pt = add_supplier(supplier_id, stored_pt) stored_pt = pt if action == "AddCategory": if category_id not in stored_pt_str: pt = add_category(category_id, stored_pt) stored_pt = pt # 6. Put data back in state storage stored_pt_str = json.dumps(stored_pt) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_pt_id, stored_pt_str]).encode()) ]) return addresses
def apply(self, transaction, state): # Unpack payload txn = BlockInfoTxn() txn.ParseFromString(transaction.payload) next_block = txn.block # Validate block info fields if next_block.block_num < 0: raise InvalidTransaction( "Invalid block num '{}'".format(next_block.block_num)) if not (validate_hex(next_block.previous_block_id, 128) or next_block.previous_block_id == "0000000000000000"): raise InvalidTransaction("Invalid previous block id '{}'".format( next_block.previous_block_id)) if not validate_hex(next_block.signer_pubkey, 66): raise InvalidTransaction("Invalid signer pubkey '{}'".format( next_block.signer_pubkey)) if not validate_hex(next_block.header_signature, 128): raise InvalidTransaction("Invalid header signature '{}'".format( next_block.header_signature)) if next_block.timestamp <= 0: raise InvalidTransaction( "Invalid timestamp '{}'".format(next_block.timestamp)) # Get config and previous block (according to the block info in the # transaction) from state entries = state.get([CONFIG_ADDRESS]) deletes = [] sets = [] config = BlockInfoConfig() # If there is no config in state, we don't know anything about what's # in state, so we have to treat this as the first entry if not entries: # If sync tolerance or target count were not specified in the txn, # use default values. config.sync_tolerance = \ DEFAULT_SYNC_TOLERANCE if txn.sync_tolerance == 0 \ else txn.sync_tolerance config.target_count = \ DEFAULT_TARGET_COUNT if txn.target_count == 0 \ else txn.target_count config.latest_block = next_block.block_num config.oldest_block = next_block.block_num validate_timestamp(next_block.timestamp, config.sync_tolerance) sets.append((CONFIG_ADDRESS, config.SerializeToString())) sets.append(( create_block_address(next_block.block_num), next_block.SerializeToString())) else: config.ParseFromString(entries[0].data) # If the config was changed in this transaction if txn.sync_tolerance != 0: config.sync_tolerance = txn.sync_tolerance if txn.target_count != 0: config.target_count = txn.target_count if next_block.block_num - 1 != config.latest_block: raise InvalidTransaction( "Block number must be one more than previous block's." " Got {} expected {}".format( next_block.block_num, config.latest_block + 1)) validate_timestamp(next_block.timestamp, config.sync_tolerance) entries = state.get([create_block_address(config.latest_block)]) if not entries: raise InternalError( "Config and state out of sync. Latest block not found in" " state.") prev_block = BlockInfo() prev_block.ParseFromString(entries[0].data) if prev_block.block_num != config.latest_block: raise InternalError( "Block info stored at latest block has incorrect block" " num.") if next_block.previous_block_id != prev_block.header_signature: raise InvalidTransaction( "Previous block id must match header signature of previous" " block. Go {} expected {}".format( next_block.previous_block_id, prev_block.header_signature)) if next_block.timestamp < prev_block.timestamp: raise InvalidTransaction( "Timestamp must be greater than previous block's." " Got {}, expected >{}".format( next_block.timestamp, prev_block.timestamp)) config.latest_block = next_block.block_num while (config.latest_block - config.oldest_block) \ > config.target_count: deletes.append(create_block_address(config.oldest_block)) config.oldest_block = config.oldest_block + 1 sets.append((CONFIG_ADDRESS, config.SerializeToString())) sets.append(( create_block_address(next_block.block_num), next_block.SerializeToString())) # If this is not true, something else has modified global state if deletes: if set(deletes) != set(state.delete(deletes)): raise InternalError( "Blocks should have been in state but weren't: {}".format( deletes)) if sets: addresses = set([k for k, _ in sets]) addresses_set = set(state.set([ StateEntry(address=k, data=v) for k, v in sets])) if addresses != addresses_set: raise InternalError("Failed to set addresses.") return None
def apply(self, transaction, state_store): # Deserialize the transaction and verify it is valid pt_id, pt_name, checksum, version, src_uri, licensing, label, description, action, envelope_id, category_id, supplier_id, signer = extract_transaction( transaction) if pt_id == "": raise InvalidTransaction("part Data is required") if action == "": raise InvalidTransaction("Action is required") # Checks to see if the action is valid or not if action not in ("create", "list-part", "show-part", "AddEnvelope", "AddCategory", "AddSupplier"): raise InvalidTransaction("Invalid Action '{}'".format(action)) data_address = self._namespace_prefix \ + hashlib.sha512(pt_id.encode("utf-8")).hexdigest() # Retrieve data from address state_entries = state_store.get([data_address]) # Checks to see if the list is not empty if len(state_entries) != 0: try: stored_pt_id, stored_pt_str = \ state_entries[0].data.decode().split(",",1) stored_pt = json.loads(stored_pt_str) except ValueError: raise InternalError("Failed to deserialize data.") else: stored_pt_id = stored_pt = None if action == "create" and stored_pt_id is not None: raise InvalidTransaction("Invalid Action-part already exists.") if action == "create": pt = create_part(pt_id, pt_name, checksum, version, src_uri, licensing, label, description) stored_pt_id = pt_id stored_pt = pt _display("Created a part.") if action == "AddEnvelope": if envelope_id not in stored_pt_str: pt_env = add_envelope(envelope_id, stored_pt) stored_pt = pt_env if action == "AddSupplier": if supplier_id not in stored_pt_str: pt_supp = add_supplier(supplier_id, stored_pt) stored_pt = pt_supp if action == "AddCategory": if category_id not in stored_pt_str: pt_cat = add_category(category_id, stored_pt) stored_pt = pt_cat stored_pt_str = json.dumps(stored_pt) addresses = state_store.set([ StateEntry(address=data_address, data=",".join([stored_pt_id, stored_pt_str]).encode()) ]) if len(addresses) < 1: raise InternalError("State Error")