mirror of
https://github.com/aljazceru/python-teos.git
synced 2025-12-17 14:14:22 +01:00
gatekeeper reformats update_available_slots to add_update_appointment
- add_update_appointment handles the slot count and also keeps a copy of the appointment uuid and slots taken. - gatekeeper.appointments is turned to a dict uuid:slots so appointment updates can be computed with no further data - deleting appointment will also allow to update the slot count with no further data from both the Watcher and the Responder
This commit is contained in:
@@ -27,9 +27,9 @@ class UserInfo:
|
|||||||
self.available_slots = available_slots
|
self.available_slots = available_slots
|
||||||
self.subscription_expiry = subscription_expiry
|
self.subscription_expiry = subscription_expiry
|
||||||
|
|
||||||
# FIXME: this list is currently never wiped
|
|
||||||
if not appointments:
|
if not appointments:
|
||||||
self.appointments = []
|
# A dictionary of the form uuid:required_slots for each user appointment
|
||||||
|
self.appointments = {}
|
||||||
else:
|
else:
|
||||||
self.appointments = appointments
|
self.appointments = appointments
|
||||||
|
|
||||||
@@ -136,21 +136,20 @@ class Gatekeeper:
|
|||||||
except (InvalidParameter, InvalidKey, SignatureError):
|
except (InvalidParameter, InvalidKey, SignatureError):
|
||||||
raise AuthenticationFailure("Wrong message or signature.")
|
raise AuthenticationFailure("Wrong message or signature.")
|
||||||
|
|
||||||
def update_available_slots(self, user_id, new_appointment, old_appointment=None):
|
def add_update_appointment(self, user_id, uuid, appointment):
|
||||||
"""
|
"""
|
||||||
Updates (add/removes) slots from a user subscription.
|
Adds (or updates) an appointment to a user subscription. The user slots are updated accordingly.
|
||||||
|
|
||||||
Slots are removed if a new appointment is given, or an update is given with an appointment bigger than the
|
Slots are taken if a new appointment is given, or an update is given with an appointment bigger than the
|
||||||
old one.
|
existing one.
|
||||||
|
|
||||||
Slots are added if an update is given but the new appointment is smaller than the old one.
|
Slots are given back if an update is given but the new appointment is smaller than the existing one.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_id(:obj:`str`): the public key that identifies the user (33-bytes hex str).
|
user_id (:obj:`str`): the public key that identifies the user (33-bytes hex str).
|
||||||
new_appointment (:obj:`dict`): the summary of new appointment the user is requesting
|
uuid (:obj:`str`): the appointment uuid.
|
||||||
to add.
|
appointment (:obj:`ExtendedAppointment <teos.extended_appointment.ExtendedAppointment`): the summary of new
|
||||||
old_appointment (:obj:`dict`): the summary old appointment the user wants to replace.
|
appointment the user is requesting.
|
||||||
Optional.
|
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
:obj:`int`: the number of remaining appointment slots.
|
:obj:`int`: the number of remaining appointment slots.
|
||||||
@@ -160,18 +159,21 @@ class Gatekeeper:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self.lock.acquire()
|
self.lock.acquire()
|
||||||
if old_appointment:
|
|
||||||
# For updates the difference between the existing appointment and the update is computed.
|
# For updates the difference between the existing appointment and the update is computed.
|
||||||
used_slots = ceil(old_appointment.get("size") / ENCRYPTED_BLOB_MAX_SIZE_HEX)
|
if uuid in self.registered_users[user_id].appointments:
|
||||||
required_slots = ceil(new_appointment.get("size") / ENCRYPTED_BLOB_MAX_SIZE_HEX) - used_slots
|
used_slots = self.registered_users[user_id].appointments[uuid]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# For regular appointments 1 slot is reserved per ENCRYPTED_BLOB_MAX_SIZE_HEX block.
|
# For regular appointments 1 slot is reserved per ENCRYPTED_BLOB_MAX_SIZE_HEX block.
|
||||||
required_slots = ceil(new_appointment.get("size") / ENCRYPTED_BLOB_MAX_SIZE_HEX)
|
used_slots = 0
|
||||||
|
|
||||||
if required_slots <= self.registered_users.get(user_id).available_slots:
|
required_slots = ceil(len(appointment.encrypted_blob) / ENCRYPTED_BLOB_MAX_SIZE_HEX)
|
||||||
|
|
||||||
|
if required_slots - used_slots <= self.registered_users.get(user_id).available_slots:
|
||||||
# Filling / freeing slots depending on whether this is an update or not, and if it is bigger or smaller than
|
# Filling / freeing slots depending on whether this is an update or not, and if it is bigger or smaller than
|
||||||
# the old appointment.
|
# the old appointment.
|
||||||
self.registered_users.get(user_id).available_slots -= required_slots
|
self.registered_users.get(user_id).appointments[uuid] = required_slots
|
||||||
|
self.registered_users.get(user_id).available_slots -= required_slots - used_slots
|
||||||
else:
|
else:
|
||||||
self.lock.release()
|
self.lock.release()
|
||||||
raise NotEnoughSlots()
|
raise NotEnoughSlots()
|
||||||
@@ -189,6 +191,7 @@ class Gatekeeper:
|
|||||||
Returns:
|
Returns:
|
||||||
:obj:`list`: a list of appointment uuids that will expire at ``block_height``.
|
:obj:`list`: a list of appointment uuids that will expire at ``block_height``.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
expired_appointments = []
|
expired_appointments = []
|
||||||
# Avoiding dictionary changed size during iteration
|
# Avoiding dictionary changed size during iteration
|
||||||
for user_id in list(self.registered_users.keys()):
|
for user_id in list(self.registered_users.keys()):
|
||||||
|
|||||||
@@ -128,48 +128,47 @@ def test_identify_user_wrong(gatekeeper):
|
|||||||
gatekeeper.authenticate_user(message, signature.encode())
|
gatekeeper.authenticate_user(message, signature.encode())
|
||||||
|
|
||||||
|
|
||||||
def test_update_available_slots(gatekeeper):
|
def test_add_update_appointment(gatekeeper):
|
||||||
# update_available_slots should decrease the slot count if a new appointment is added
|
# add_update_appointment should decrease the slot count if a new appointment is added
|
||||||
# let's add a new user
|
# let's add a new user
|
||||||
sk, pk = generate_keypair()
|
sk, pk = generate_keypair()
|
||||||
user_id = Cryptographer.get_compressed_pk(pk)
|
user_id = Cryptographer.get_compressed_pk(pk)
|
||||||
gatekeeper.add_update_user(user_id)
|
gatekeeper.add_update_user(user_id)
|
||||||
|
|
||||||
# And now update the slots given an appointment
|
# And now update add a new appointment
|
||||||
appointment, _ = generate_dummy_appointment()
|
appointment, _ = generate_dummy_appointment()
|
||||||
gatekeeper.update_available_slots(user_id, appointment.get_summary())
|
appointment_uuid = get_random_value_hex(16)
|
||||||
|
remaining_slots = gatekeeper.add_update_appointment(user_id, appointment_uuid, appointment)
|
||||||
|
|
||||||
# This is a standard size appointment, so it should have reduced the slots by one
|
# This is a standard size appointment, so it should have reduced the slots by one
|
||||||
assert gatekeeper.registered_users[user_id].available_slots == config.get("DEFAULT_SLOTS") - 1
|
assert appointment_uuid in gatekeeper.registered_users[user_id].appointments
|
||||||
|
assert remaining_slots == config.get("DEFAULT_SLOTS") - 1
|
||||||
|
|
||||||
# Updates can leave the count as it, decrease it, or increase it, depending on the appointment size (modulo
|
# Updates can leave the count as is, decrease it, or increase it, depending on the appointment size (modulo
|
||||||
# ENCRYPTED_BLOB_MAX_SIZE_HEX)
|
# ENCRYPTED_BLOB_MAX_SIZE_HEX)
|
||||||
|
|
||||||
# Appointments of the same size leave it as is
|
# Appointments of the same size leave it as is
|
||||||
appointment_same_size, _ = generate_dummy_appointment()
|
appointment_same_size, _ = generate_dummy_appointment()
|
||||||
remaining_slots = gatekeeper.update_available_slots(
|
remaining_slots = gatekeeper.add_update_appointment(user_id, appointment_uuid, appointment)
|
||||||
user_id, appointment.get_summary(), appointment_same_size.get_summary()
|
assert appointment_uuid in gatekeeper.registered_users[user_id].appointments
|
||||||
)
|
|
||||||
assert remaining_slots == config.get("DEFAULT_SLOTS") - 1
|
assert remaining_slots == config.get("DEFAULT_SLOTS") - 1
|
||||||
|
|
||||||
# Bigger appointments decrease it
|
# Bigger appointments decrease it
|
||||||
appointment_x2_size = appointment_same_size
|
appointment_x2_size = appointment_same_size
|
||||||
appointment_x2_size.encrypted_blob = "A" * (ENCRYPTED_BLOB_MAX_SIZE_HEX + 1)
|
appointment_x2_size.encrypted_blob = "A" * (ENCRYPTED_BLOB_MAX_SIZE_HEX + 1)
|
||||||
remaining_slots = gatekeeper.update_available_slots(
|
remaining_slots = gatekeeper.add_update_appointment(user_id, appointment_uuid, appointment_x2_size)
|
||||||
user_id, appointment_x2_size.get_summary(), appointment.get_summary()
|
assert appointment_uuid in gatekeeper.registered_users[user_id].appointments
|
||||||
)
|
|
||||||
assert remaining_slots == config.get("DEFAULT_SLOTS") - 2
|
assert remaining_slots == config.get("DEFAULT_SLOTS") - 2
|
||||||
|
|
||||||
# Smaller appointments increase it (using the same data but flipped)
|
# Smaller appointments increase it
|
||||||
remaining_slots = gatekeeper.update_available_slots(
|
remaining_slots = gatekeeper.add_update_appointment(user_id, appointment_uuid, appointment)
|
||||||
user_id, appointment.get_summary(), appointment_x2_size.get_summary()
|
|
||||||
)
|
|
||||||
assert remaining_slots == config.get("DEFAULT_SLOTS") - 1
|
assert remaining_slots == config.get("DEFAULT_SLOTS") - 1
|
||||||
|
|
||||||
# If the appointment needs more slots than there's free, it should fail
|
# If the appointment needs more slots than there's free, it should fail
|
||||||
gatekeeper.registered_users[user_id].available_slots = 1
|
gatekeeper.registered_users[user_id].available_slots = 1
|
||||||
|
appointment_uuid = get_random_value_hex(16)
|
||||||
with pytest.raises(NotEnoughSlots):
|
with pytest.raises(NotEnoughSlots):
|
||||||
gatekeeper.update_available_slots(user_id, appointment_x2_size.get_summary())
|
gatekeeper.add_update_appointment(user_id, appointment_uuid, appointment_x2_size)
|
||||||
|
|
||||||
|
|
||||||
def test_get_expired_appointments(gatekeeper):
|
def test_get_expired_appointments(gatekeeper):
|
||||||
|
|||||||
Reference in New Issue
Block a user