Actor now uses cached Ritual object whenever available which has aggregated transcript bytes on it - this saves more RPC calls for already completed/active Ritual whose values (that we care about) don't change at the moment.

Aggregated transcript is no longer cached separately (but as part of cached Ritual object) so update code/tests accordingly.
remotes/origin/v7.4.x
derekpierre 2024-02-02 11:13:14 -05:00 committed by Derek Pierre
parent 635238f5a6
commit c5b86572c9
3 changed files with 29 additions and 46 deletions

View File

@ -293,6 +293,17 @@ class Operator(BaseActor):
return providers
def _resolve_ritual(self, ritual_id: int) -> Coordinator.Ritual:
if not self.coordinator_agent.is_ritual_active(ritual_id=ritual_id):
raise self.ActorError(f"Ritual #{ritual_id} is not active.")
ritual = self.dkg_storage.get_active_ritual(ritual_id)
if not ritual:
ritual = self.coordinator_agent.get_ritual(ritual_id)
self.dkg_storage.store_active_ritual(active_ritual=ritual)
return ritual
def _resolve_validators(
self,
ritual: Coordinator.Ritual,
@ -559,11 +570,6 @@ class Operator(BaseActor):
)
raise e
# store the DKG artifacts for later optimized reads
self.dkg_storage.store_aggregated_transcript(
ritual_id=ritual.id, aggregated_transcript=aggregated_transcript
)
# publish the transcript with network-wide jitter to avoid tx congestion
time.sleep(random.randint(0, self.AGGREGATION_SUBMISSION_MAX_DELAY))
tx_hash = self.publish_aggregated_transcript(
@ -592,21 +598,13 @@ class Operator(BaseActor):
aad: bytes,
variant: FerveoVariant,
) -> Union[DecryptionShareSimple, DecryptionSharePrecomputed]:
if not self.coordinator_agent.is_ritual_active(ritual_id=ritual_id):
raise self.ActorError(f"Ritual #{ritual_id} is not active.")
ritual = self.coordinator_agent.get_ritual(ritual_id)
ritual = self._resolve_ritual(ritual_id)
validators = self._resolve_validators(ritual)
aggregated_transcript = self.dkg_storage.get_aggregated_transcript(ritual_id)
if not aggregated_transcript:
aggregated_transcript = AggregatedTranscript.from_bytes(
bytes(ritual.aggregated_transcript)
)
self.dkg_storage.store_aggregated_transcript(
ritual_id, aggregated_transcript
)
aggregated_transcript = AggregatedTranscript.from_bytes(
bytes(ritual.aggregated_transcript)
)
decryption_share = self.ritual_power.derive_decryption_share(
nodes=validators,

View File

@ -316,14 +316,11 @@ def test_ursula_ritualist(
def check_decrypt_without_any_cached_values(threshold_message_kit):
print("==================== DKG DECRYPTION NO CACHE ====================")
original_validators = cohort[0].dkg_storage.get_validators(RITUAL_ID)
original_aggregated_transcript = cohort[
0
].dkg_storage.get_aggregated_transcript(RITUAL_ID)
for ursula in cohort:
ursula.dkg_storage.clear(RITUAL_ID)
assert ursula.dkg_storage.get_validators(RITUAL_ID) is None
assert ursula.dkg_storage.get_aggregated_transcript(RITUAL_ID) is None
assert ursula.dkg_storage.get_active_ritual(RITUAL_ID) is None
bob.start_learning_loop(now=True)
cleartext = bob.threshold_decrypt(
@ -334,22 +331,18 @@ def test_ursula_ritualist(
ritual = coordinator_agent.get_ritual(RITUAL_ID)
num_used_ursulas = 0
for ursula_index, ursula in enumerate(cohort):
stored_validators = ursula.dkg_storage.get_validators(RITUAL_ID)
if not stored_validators:
stored_ritual = ursula.dkg_storage.get_active_ritual(RITUAL_ID)
if not stored_ritual:
# this ursula was not used for threshold decryption; skip
continue
assert stored_ritual == ritual
stored_validators = ursula.dkg_storage.get_validators(RITUAL_ID)
num_used_ursulas += 1
for v_index, v in enumerate(stored_validators):
assert v.address == original_validators[v_index].address
assert v.public_key == original_validators[v_index].public_key
cached_aggregated_transcript = ursula.dkg_storage.get_aggregated_transcript(
RITUAL_ID
)
assert bytes(cached_aggregated_transcript) == bytes(
original_aggregated_transcript
)
assert bytes(cached_aggregated_transcript) == ritual.aggregated_transcript
assert num_used_ursulas >= ritual.threshold
print("===================== DECRYPTION SUCCESSFUL =====================")

View File

@ -304,14 +304,11 @@ def test_ursula_ritualist(
def decrypt_without_any_cached_values(threshold_message_kit):
print("==================== DKG DECRYPTION NO CACHE ====================")
original_validators = cohort[0].dkg_storage.get_validators(ritual_id)
original_aggregated_transcript = cohort[
0
].dkg_storage.get_aggregated_transcript(ritual_id)
for ursula in cohort:
ursula.dkg_storage.clear(ritual_id)
assert ursula.dkg_storage.get_validators(ritual_id) is None
assert ursula.dkg_storage.get_aggregated_transcript(ritual_id) is None
assert ursula.dkg_storage.get_active_ritual(ritual_id) is None
bob.start_learning_loop(now=True)
cleartext = bob.threshold_decrypt(
@ -322,25 +319,20 @@ def test_ursula_ritualist(
ritual = mock_coordinator_agent.get_ritual(ritual_id)
num_used_ursulas = 0
for ursula_index, ursula in enumerate(cohort):
stored_validators = ursula.dkg_storage.get_validators(ritual_id)
if not stored_validators:
stored_ritual = ursula.dkg_storage.get_active_ritual(ritual_id)
if not stored_ritual:
# this ursula was not used for threshold decryption; skip
continue
assert stored_ritual == ritual
stored_validators = ursula.dkg_storage.get_validators(ritual_id)
num_used_ursulas += 1
for v_index, v in enumerate(stored_validators):
assert v.address == original_validators[v_index].address
assert v.public_key == original_validators[v_index].public_key
cached_aggregated_transcript = (
ursula.dkg_storage.get_aggregated_transcript(ritual_id)
)
assert bytes(cached_aggregated_transcript) == bytes(
original_aggregated_transcript
)
assert (
bytes(cached_aggregated_transcript) == ritual.aggregated_transcript
)
assert num_used_ursulas >= threshold
assert num_used_ursulas >= ritual.threshold
print("===================== DECRYPTION SUCCESSFUL =====================")
def error_handler(e):