Exemple #1
0
def _validate_create_role_state(create_role, state):
    state_return = get_state(
        state, [addresser.make_role_attributes_address(create_role.role_id)])

    if _role_already_exists(state_return, create_role.role_id):
        raise InvalidTransaction("Role id {} is already in state".format(
            create_role.role_id))

    users = list(create_role.admins) + list(create_role.owners)
    user_state_return = get_state(
        state, [addresser.make_user_address(u) for u in users])

    validate_list_of_user_are_users(user_state_return, users)
def validate_task_admin_or_owner(header, confirm, txn_signer_rel_address,
                                 task_rel_address, state, is_remove):
    """Validate a [ Confirm | Reject }_____Task[ Admin | Owner } transaction.

    Args:
        header (TransactionHeader): The transaction header protobuf class.:
        confirm: ConfirmAddTaskAdmin, RejectAddTaskAdmin, ...
        txn_signer_rel_address (str): The transaction signer address.
        task_rel_address (str): The task relationship address.
        state (Context): The class responsible for gets and sets of state.
        is_remove (boolean): Determines if task owner is being added or removed.

    Returns:
        (dict of addresses)

    Raises:
        InvalidTransaction
            - The transaction is invalid.
    """

    proposal_address = addresser.make_proposal_address(
        object_id=confirm.task_id, related_id=confirm.user_id)

    if not is_remove:
        state_entries = get_state(state,
                                  [txn_signer_rel_address, proposal_address])
    else:
        state_entries = get_state(
            state,
            [txn_signer_rel_address, task_rel_address, proposal_address])

    if not proposal_exists_and_open(state_entries, proposal_address,
                                    confirm.proposal_id):
        raise InvalidTransaction("The proposal {} does not exist or "
                                 "is not open".format(confirm.proposal_id))
    try:
        entry = get_state_entry(state_entries, txn_signer_rel_address)
        task_rel_container = return_task_rel_container(entry)
    except KeyError:
        raise InvalidTransaction(
            "Signer {} does not have the Task permissions "
            "to close the proposal".format(header.signer_public_key))
    if not is_in_task_rel_container(task_rel_container,
                                    task_id=confirm.task_id,
                                    identifier=header.signer_public_key):
        raise InvalidTransaction("Signer {} does not have the Task "
                                 "permissions to close the "
                                 "proposal".format(header.signer_public_key))

    return state_entries
Exemple #3
0
def _validate_state_and_return_user(header, user_proposal, state):
    """Validate that 1. There is no other open proposal for the manager change
    2. The user is a User 3. the manager is a User 4. The manager is the
    signer of the transaction.

    Args:
        header (TransactionHeader): The transaction header.
        user_proposal (ProposeUpdateUserManager): The transaction that makes
            the proposal to update the user's manager.
        state (Context): The way to set and get values from state.

    """

    prop_state_entries = _validate_unique_proposal(
        header,
        user_proposal,
        state)

    user_address = addresser.make_user_address(
        user_id=user_proposal.user_id)
    user_state_entries = get_state(
        state,
        [user_address])
    validate_identifier_is_user(
        state_entries=user_state_entries,
        identifier=user_proposal.user_id,
        address=user_address)

    manager_address = addresser.make_user_address(
        user_id=user_proposal.new_manager_id)

    manager_state_entries = get_state(
        state,
        [manager_address])

    validate_identifier_is_user(
        state_entries=manager_state_entries,
        identifier=user_proposal.new_manager_id,
        address=manager_address)

    user_state_entry = get_state_entry(
        user_state_entries,
        user_address)

    user_container = return_user_container(user_state_entry)

    _validate_manager_is_signer(header, user_container, user_proposal.user_id)

    return prop_state_entries
Exemple #4
0
def validate_role_task(header, confirm, txn_signer_rel_address, state):

    proposal_address = addresser.make_proposal_address(
        object_id=confirm.role_id, related_id=confirm.task_id)

    state_entries = get_state(state,
                              [txn_signer_rel_address, proposal_address])

    if not proposal_exists_and_open(state_entries, proposal_address,
                                    confirm.proposal_id):
        raise InvalidTransaction("The proposal {} does not exist or "
                                 "is not open".format(confirm.proposal_id))
    try:
        entry = get_state_entry(state_entries, txn_signer_rel_address)
        task_owners_container = return_task_rel_container(entry)
    except KeyError:
        raise InvalidTransaction(
            "Signer {} is not a task owner for task {}".format(
                header.signer_public_key, confirm.task_id))

    if not is_in_task_rel_container(task_owners_container, confirm.task_id,
                                    header.signer_public_key):
        raise InvalidTransaction(
            "Signer {} is not a task owner for task {} no bytes in "
            "state".format(header.signer_public_key, confirm.task_id))
    return state_entries
Exemple #5
0
def apply_user_reject(header, payload, state):
    reject_payload = user_transaction_pb2.RejectUpdateUserManager()
    reject_payload.ParseFromString(payload.content)

    proposal_address = addresser.make_proposal_address(
        object_id=reject_payload.user_id, related_id=reject_payload.manager_id)

    state_entries = get_state(state, [proposal_address])

    if not proposal_exists_and_open(state_entries=state_entries,
                                    proposal_address=proposal_address,
                                    proposal_id=reject_payload.proposal_id):
        raise InvalidTransaction("Proposal {} is not open or does not "
                                 "exist".format(reject_payload.proposal_id))

    entry = get_state_entry(state_entries, proposal_address)

    proposal_container = return_prop_container(entry)

    if not reject_payload.manager_id == header.signer_pubkey:
        raise InvalidTransaction("Proposal expected closer to be {} while txn "
                                 "signer was {}".format(
                                     reject_payload.manager_id,
                                     header.signer_pubkey))

    proposal = get_prop_from_container(proposal_container,
                                       reject_payload.proposal_id)

    handle_reject_state_set(container=proposal_container,
                            proposal=proposal,
                            closer=header.signer_pubkey,
                            reason=reject_payload.reason,
                            address=proposal_address,
                            state=state)
def validate_task_rel_proposal(header, propose, rel_address, state):
    """Validates that the User exists, the Task exists, and the User is not
    in the Task's relationship specified by rel_address.

    Args:
        header (TransactionHeader): The transaction header.
        propose (ProposeAddTask_____): The Task relationship proposal.
        rel_address (str): The Task relationship address produced by the Task
            and the User.
        state (sawtooth_sdk.Context): The way to communicate to the validator
            the state gets and sets.

    Returns:
        (dict of addresses)
    """

    user_address = addresser.make_user_address(propose.user_id)
    task_address = addresser.make_task_attributes_address(propose.task_id)
    proposal_address = addresser.make_proposal_address(
        object_id=propose.task_id,
        related_id=propose.user_id)

    state_entries = get_state(state, [user_address,
                                      task_address,
                                      proposal_address,
                                      rel_address])
    validate_identifier_is_user(state_entries,
                                identifier=propose.user_id,
                                address=user_address)
    user_entry = get_state_entry(state_entries, user_address)
    user = get_user_from_container(
        return_user_container(user_entry),
        propose.user_id)

    if header.signer_public_key not in [user.user_id, user.manager_id]:
        raise InvalidTransaction(
            "Txn signer {} is not the user or the user's "
            "manager {}".format(header.signer_public_key,
                                [user.user_id, user.manager_id]))

    validate_identifier_is_task(state_entries,
                                identifier=propose.task_id,
                                address=task_address)

    try:
        task_admins_entry = get_state_entry(state_entries, rel_address)
        task_rel_container = return_task_rel_container(task_admins_entry)
        if is_in_task_rel_container(
                task_rel_container,
                propose.task_id,
                propose.user_id):
            raise InvalidTransaction(
                "User {} is already in the Role {} "
                "relationship".format(propose.user_id,
                                      propose.task_id))
    except KeyError:
        # The task rel container doesn't exist so no task relationship exists
        pass

    return state_entries
Exemple #7
0
def handle_confirm_state_set(container,
                             proposal,
                             closer,
                             reason,
                             address,
                             user_id,
                             new_manager_id,
                             state):
    proposal.status = proposal_state_pb2.Proposal.CONFIRMED
    proposal.closer = closer
    proposal.close_reason = reason

    set_state(state, {
        address: container.SerializeToString()
    })

    user_address = addresser.make_user_address(user_id)
    state_entries = get_state(state, [user_address])
    state_entry = get_state_entry(
        state_entries=state_entries,
        address=user_address)
    user_container = return_user_container(state_entry)
    user = get_user_from_container(user_container, user_id)
    user.manager_id = new_manager_id

    set_state(state, {
        user_address: user_container.SerializeToString()
    })
def validate_task_rel_del_proposal(header, propose, rel_address, state):
    """Validates that the User exists, the Task exists, and the User is in
    the Tasks's relationship specified by the rel_address.

    Args:
        header (TransactionHeader): The transaction header.
        propose (ProposeRemoveTask____): The Task Remove relationship proposal
        rel_address (str): The task relationship address.
        state (Context:: The way to communicate to the validator State gets
            and sets.

    Returns:
        (list of StateEntry)
    """

    user_address = addresser.make_user_address(propose.user_id)
    task_address = addresser.make_task_attributes_address(propose.task_id)

    proposal_address = addresser.make_proposal_address(
        object_id=propose.task_id, related_id=propose.user_id)

    state_entries = get_state(
        state, [user_address, task_address, proposal_address, rel_address])

    validate_identifier_is_user(state_entries,
                                identifier=propose.user_id,
                                address=user_address)

    user_entry = get_state_entry(state_entries, user_address)

    user = get_user_from_container(return_user_container(user_entry),
                                   propose.user_id)

    if header.signer_pubkey not in [user.user_id, user.manager_id]:
        raise InvalidTransaction(
            "Txn signer {} is not the user {} or the user's manager {}".format(
                header.signer_pubkey, user.user_id, user.manager_id))

    validate_identifier_is_task(state_entries,
                                identifier=propose.task_id,
                                address=task_address)

    try:
        task_rel_entry = get_state_entry(state_entries, rel_address)
        task_rel_container = return_task_rel_container(task_rel_entry)
        if not is_in_task_rel_container(task_rel_container, propose.task_id,
                                        propose.user_id):
            raise InvalidTransaction("User {} isn't in the Task {} "
                                     "relationship".format(
                                         propose.user_id, propose.task_id))
    except KeyError:
        raise InvalidTransaction(
            "User {} isn't in the Task {} relationship, "
            "since there isn't a container at the address".format(
                propose.user_id, propose.task_id))

    return state_entries
Exemple #9
0
def _handle_role_state_set(create_role, state):
    role_container = role_state_pb2.RoleAttributesContainer()
    role = role_container.role_attributes.add()
    role.role_id = create_role.role_id
    role.name = create_role.name
    role.metadata = create_role.metadata

    entries_to_set = [
        StateEntry(address=addresser.make_role_attributes_address(
            create_role.role_id),
                   data=role_container.SerializeToString())
    ]

    pubkeys_by_address = {}

    for admin in list(create_role.admins):
        admin_address = addresser.make_role_admins_address(
            role_id=create_role.role_id, user_id=admin)

        if admin_address in pubkeys_by_address:
            pubkeys_by_address[admin_address].append(admin)
        else:
            pubkeys_by_address[admin_address] = [admin]

    for owner in list(create_role.owners):
        owner_address = addresser.make_role_owners_address(
            role_id=create_role.role_id, user_id=owner)

        if owner_address in pubkeys_by_address:
            pubkeys_by_address[owner_address].append(owner)
        else:
            pubkeys_by_address[owner_address] = [owner]

    state_returns = get_state(state, [
        addresser.make_role_admins_address(role_id=create_role.role_id,
                                           user_id=a)
        for a in create_role.admins
    ] + [
        addresser.make_role_owners_address(role_id=create_role.role_id,
                                           user_id=o)
        for o in create_role.owners
    ])

    for addr, pubkeys in pubkeys_by_address.items():
        try:
            state_entry = get_state_entry(state_returns, addr)
            container = role_state_pb2.RoleRelationshipContainer()
            container.ParseFromString(state_entry.data)
        except KeyError:
            container = role_state_pb2.RoleRelationshipContainer()

        _add_role_rel_to_container(container, create_role.role_id, pubkeys)

        entries_to_set.append(
            StateEntry(address=addr, data=container.SerializeToString()))
    set_state(state, entries_to_set)
Exemple #10
0
def _validate_unique_proposal(header, user_proposal, state):
    proposal_address = addresser.make_proposal_address(
        object_id=user_proposal.user_id,
        related_id=user_proposal.new_manager_id)
    state_return = get_state(state, [proposal_address])
    if not no_open_proposal(
            state_return,
            proposal_address,
            user_proposal.user_id,
            user_proposal.new_manager_id,
            proposal_type=proposal_state_pb2.Proposal.UPDATE_USER_MANAGER):
        raise InvalidTransaction("There is already a ProposeUpdateUserManager "
                                 "proposal for this user and manager.")

    return state_return
def validate_user_state(header, create_user, state):
    user_entries = get_state(
        state, [addresser.make_user_address(create_user.user_id)])
    if user_entries:
        # this is necessary for state collisions.
        try:
            user_container = return_user_container(user_entries[0])
            _index_of_user_in_container(user_container, create_user.user_id)
            raise InvalidTransaction(
                "User with user_id {} already exists.".format(
                    create_user.user_id))
        except KeyError:
            # The user does not exist yet in state and so the transaction
            # is valid.
            pass
def validate_manager_state(header, create_user, state):

    manager_entries = get_state(
        state, [addresser.make_user_address(create_user.manager_id)])
    if not manager_entries:
        raise InvalidTransaction("User id {} listed as manager is not "
                                 "in state.".format(create_user.manager_id))

    state_entry = get_state_entry(
        manager_entries,
        addresser.make_user_address(user_id=create_user.manager_id))
    manager_container = return_user_container(state_entry)
    if not is_in_user_container(manager_container, create_user.manager_id):
        raise InvalidTransaction(
            "user id {} listed as manager is not within the User container "
            "in state".format(create_user.manager_id))
Exemple #13
0
def validate_role_admin_or_owner(header,
                                 confirm,
                                 txn_signer_rel_address,
                                 state):
    """Validate a [ Confirm | Reject }_____Role[ Admin | Owner } transaction.

    Args:
        header (TransactionHeader): The transaction header protobuf class.:
        confirm: ConfirmAddRoleAdmin, RejectAddRoleAdmin, ...
        state (Context): The class responsible for gets and sets of state.

    Returns:
        (dict of addresses)
    """

    proposal_address = addresser.make_proposal_address(
        object_id=confirm.role_id,
        related_id=confirm.user_id)

    state_entries = get_state(
        state,
        [txn_signer_rel_address, proposal_address])

    if not proposal_exists_and_open(
            state_entries,
            proposal_address,
            confirm.proposal_id):
        raise InvalidTransaction("The proposal {} does not exist or "
                                 "is not open".format(confirm.proposal_id))
    try:
        entry = get_state_entry(state_entries, txn_signer_rel_address)
        role_rel_container = return_role_rel_container(entry)
    except KeyError:
        raise InvalidTransaction(
            "Signer {} does not have the Role permissions "
            "to close the proposal".format(header.signer_public_key))
    if not is_in_role_rel_container(
            role_rel_container,
            role_id=confirm.role_id,
            identifier=header.signer_public_key):
        raise InvalidTransaction("Signer {} does not have the Role "
                                 "permissions to close the "
                                 "proposal".format(header.signer_public_key))

    return state_entries
Exemple #14
0
def apply_user_confirm(header, payload, state):
    confirm_payload = user_transaction_pb2.ConfirmUpdateUserManager()
    confirm_payload.ParseFromString(payload.content)

    proposal_address = addresser.make_proposal_address(
        object_id=confirm_payload.user_id,
        related_id=confirm_payload.manager_id)

    proposal_entries = get_state(state, [proposal_address])

    if not proposal_exists_and_open(
            state_entries=proposal_entries,
            proposal_address=proposal_address,
            proposal_id=confirm_payload.proposal_id):
        raise InvalidTransaction(
            "Proposal id {} does not exist or is not open.".format(
                confirm_payload.proposal_id))

    entry = get_state_entry(proposal_entries, proposal_address)
    proposal_container = return_prop_container(entry)
    proposal = get_prop_from_container(
        container=proposal_container,
        proposal_id=confirm_payload.proposal_id)

    if not proposal.target_id == header.signer_public_key:
        raise InvalidTransaction(
            "Confirm update manager txn signed by {} while "
            "proposal expecting {}".format(
                header.signer_public_key,
                proposal.target_id))

    handle_confirm_state_set(
        container=proposal_container,
        proposal=proposal,
        closer=header.signer_public_key,
        reason=confirm_payload.reason,
        address=proposal_address,
        user_id=confirm_payload.user_id,
        new_manager_id=confirm_payload.manager_id,
        state=state)
Exemple #15
0
def apply_create_task(header, payload, state):
    create_payload = task_transaction_pb2.CreateTask()
    create_payload.ParseFromString(payload.content)

    addresses = [
        addresser.make_task_attributes_address(create_payload.task_id)
    ]
    if not create_payload.admins:
        raise InvalidTransaction("New tasks must have administrators.")

    if not create_payload.owners:
        raise InvalidTransaction("New tasks must have owners.")

    if create_payload.admins:
        addresses.extend(
            [addresser.make_user_address(u) for u in create_payload.admins])

        addresses.extend([
            addresser.make_task_admins_address(task_id=create_payload.task_id,
                                               user_id=u)
            for u in create_payload.admins
        ])

    if create_payload.owners:
        addresses.extend(
            [addresser.make_user_address(u) for u in create_payload.owners])
        addresses.extend([
            addresser.make_task_owners_address(create_payload.task_id,
                                               user_id=u)
            for u in create_payload.owners
        ])

    state_entries = get_state(state, addresses)

    validate_create_task_state(state_entries=state_entries,
                               payload=create_payload)

    handle_create_task(state_entries, create_payload, state)
Exemple #16
0
def validate_role_task_proposal(header, propose, state):
    """Applies state validation rules for ADDRoleTaskProposal.
        - The Role exists.
        - The Task exists.
        - The Transaction was signed by a Role Owner.
        - There is no open Proposal for the same change.
        - The task is not already part of the Role.

    Args:
        header (TransactionHeader): The propobuf transaction header.
        propose (ProposeAddRoleTask): The protobuf transaction.
        state (Context): A connection to the validator to ask about state.

    Returns:
        (list of StateEntry)

    """

    role_address = addresser.make_role_attributes_address(propose.role_id)

    task_address = addresser.make_task_attributes_address(propose.task_id)

    proposal_address = addresser.make_proposal_address(
        propose.role_id,
        propose.task_id)

    txn_signer_role_owner_address = addresser.make_role_owners_address(
        role_id=propose.role_id,
        user_id=header.signer_pubkey)

    role_tasks_address = addresser.make_role_tasks_address(propose.role_id,
                                                           propose.task_id)

    state_entries = get_state(
        state=state,
        addresses=[role_address,
                   task_address,
                   proposal_address,
                   role_tasks_address,
                   txn_signer_role_owner_address])

    validate_identifier_is_role(
        state_entries=state_entries,
        address=role_address,
        identifier=propose.role_id)

    validate_identifier_is_task(
        state_entries=state_entries,
        identifier=propose.task_id,
        address=task_address)
    try:
        role_task_entry = get_state_entry(state_entries, role_tasks_address)
        role_task_container = return_role_rel_container(role_task_entry)
        if is_in_role_rel_container(role_task_container,
                                    role_id=propose.role_id,
                                    identifier=propose.task_id):
            raise InvalidTransaction("Role {} already contains task {}".format(
                propose.role_id,
                propose.task_id))
    except KeyError:
        # The Task is not in the RoleTask state
        pass

    try:
        role_owner_entry = get_state_entry(
            state_entries,
            txn_signer_role_owner_address)
        role_owner_container = return_role_rel_container(role_owner_entry)

        if not is_in_role_rel_container(role_owner_container,
                                        role_id=propose.role_id,
                                        identifier=header.signer_pubkey):
            raise InvalidTransaction(
                "Txn signer {} is not a role owner".format(
                    header.signer_pubkey))
    except KeyError:
        raise InvalidTransaction(
            "Txn signer {} is not a role owner.".format(header.signer_pubkey))

    if not no_open_proposal(
            state_entries=state_entries,
            object_id=propose.role_id,
            related_id=propose.task_id,
            proposal_address=proposal_address,
            proposal_type=proposal_state_pb2.Proposal.ADD_ROLE_TASKS):
        raise InvalidTransaction(
            "There is already an open proposal to add task {} to "
            "role {}".format(propose.task_id, propose.role_id))
    return state_entries