Skip to content

Commit

Permalink
Internal: use NewType for ID objects
Browse files Browse the repository at this point in the history
Problem: ID objects (request ID, execution ID, nonce) all use raw
string/int objects. This could lead to using the wrong object in the
wrong place without noticing.

Solution: defined dedicated types for each object. Note that
request/execution IDs are now typed as UUID.
  • Loading branch information
odesenfans committed Sep 22, 2023
1 parent c6fee83 commit c47b29c
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 30 deletions.
9 changes: 5 additions & 4 deletions src/aleph_vrf/coordinator/vrf.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
PublishedVRFRandomBytes,
)
from aleph_vrf.settings import settings
from aleph_vrf.types import RequestId, Nonce
from aleph_vrf.utils import (
binary_to_bytes,
bytes_to_int,
Expand Down Expand Up @@ -132,7 +133,7 @@ async def generate_vrf(account: ETHAccount) -> VRFResponse:
nb_executors=nb_executors,
nonce=nonce,
vrf_function=ItemHash(settings.FUNCTION),
request_id=str(uuid4()),
request_id=RequestId(uuid4()),
node_list_hash=sha3_256(selected_node_list).hexdigest(),
)

Expand Down Expand Up @@ -179,8 +180,8 @@ async def generate_vrf(account: ETHAccount) -> VRFResponse:

async def send_generate_requests(
selected_nodes: List[Node],
request_item_hash: str,
request_id: str,
request_item_hash: ItemHash,
request_id: RequestId,
) -> Dict[str, PublishedVRFResponseHash]:
generate_tasks = []
nodes: List[str] = []
Expand Down Expand Up @@ -233,7 +234,7 @@ async def send_publish_requests(

def generate_final_vrf(
nb_executors: int,
nonce: int,
nonce: Nonce,
vrf_generated_result: Dict[str, PublishedVRFResponseHash],
vrf_publish_result: Dict[str, PublishedVRFRandomBytes],
vrf_request: VRFRequest,
Expand Down
42 changes: 22 additions & 20 deletions src/aleph_vrf/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from aleph_message.models import ItemHash, PostMessage
from pydantic import BaseModel

from aleph_vrf.types import Nonce, RequestId, ExecutionId


class Node(BaseModel):
hash: str
Expand All @@ -14,17 +16,17 @@ class Node(BaseModel):
class VRFRequest(BaseModel):
nb_bytes: int
nb_executors: int
nonce: int
nonce: Nonce
vrf_function: ItemHash
request_id: str
request_id: RequestId
node_list_hash: str


class VRFGenerationRequest(BaseModel):
nb_bytes: int
nonce: int
request_id: str
execution_id: str
nonce: Nonce
request_id: RequestId
execution_id: ExecutionId
vrf_function: ItemHash


Expand All @@ -34,16 +36,16 @@ def generate_request_from_message(message: PostMessage) -> VRFGenerationRequest:
nb_bytes=content["nb_bytes"],
nonce=content["nonce"],
request_id=content["request_id"],
execution_id=str(uuid4()),
execution_id=ExecutionId(uuid4()),
vrf_function=ItemHash(content["vrf_function"]),
)


class VRFResponseHash(BaseModel):
nb_bytes: int
nonce: int
request_id: str
execution_id: str
nonce: Nonce
request_id: RequestId
execution_id: ExecutionId
vrf_request: ItemHash
random_bytes_hash: str

Expand All @@ -58,7 +60,7 @@ class PublishedVRFResponseHash(VRFResponseHash):

@classmethod
def from_vrf_response_hash(
cls, vrf_response_hash: VRFResponseHash, message_hash: ItemHash
cls, vrf_response_hash: VRFResponseHash, message_hash: ItemHash
) -> "PublishedVRFResponseHash":
return cls(
nb_bytes=vrf_response_hash.nb_bytes,
Expand All @@ -72,7 +74,7 @@ def from_vrf_response_hash(


def generate_response_hash_from_message(
message: PostMessage,
message: PostMessage,
) -> PublishedVRFResponseHash:
content = message.content.content
return PublishedVRFResponseHash(
Expand All @@ -87,8 +89,8 @@ def generate_response_hash_from_message(


class VRFRandomBytes(BaseModel):
request_id: str
execution_id: str
request_id: RequestId
execution_id: ExecutionId
vrf_request: ItemHash
random_bytes: str
random_bytes_hash: str
Expand All @@ -100,7 +102,7 @@ class PublishedVRFRandomBytes(VRFRandomBytes):

@classmethod
def from_vrf_random_bytes(
cls, vrf_random_bytes: VRFRandomBytes, message_hash: ItemHash
cls, vrf_random_bytes: VRFRandomBytes, message_hash: ItemHash
) -> "PublishedVRFRandomBytes":
return cls(
request_id=vrf_random_bytes.request_id,
Expand All @@ -115,23 +117,23 @@ def from_vrf_random_bytes(

class CRNVRFResponse(BaseModel):
url: str
execution_id: str
execution_id: ExecutionId
random_number: str
random_bytes: str
random_bytes_hash: str
generation_message_hash: str
publish_message_hash: str
generation_message_hash: ItemHash
publish_message_hash: ItemHash


class VRFResponse(BaseModel):
nb_bytes: int
nb_executors: int
nonce: int
nonce: Nonce
vrf_function: ItemHash
request_id: str
request_id: RequestId
nodes: List[CRNVRFResponse]
random_number: str
message_hash: Optional[str] = None
message_hash: Optional[ItemHash] = None


class APIResponse(BaseModel):
Expand Down
8 changes: 5 additions & 3 deletions src/aleph_vrf/settings.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pydantic import BaseSettings, Field
from pydantic import BaseSettings, Field, HttpUrl


class Settings(BaseSettings):
API_HOST: str = Field(
API_HOST: HttpUrl = Field(
default="https://api2.aleph.im",
description="URL of the reference aleph.im Core Channel Node.",
)
Expand All @@ -17,7 +17,9 @@ class Settings(BaseSettings):
default="4992b4127d296b240bbb73058daea9bca09f717fa94767d6f4dc3ef53b4ef5ce",
description="VRF function to use.",
)
NB_EXECUTORS: int = Field(default=32, description="Number of executors to use.")
NB_EXECUTORS: int = Field(
default=32, description="Number of executors to use."
)
NB_BYTES: int = Field(
default=32, description="Number of bytes of the generated random number."
)
Expand Down
6 changes: 6 additions & 0 deletions src/aleph_vrf/types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from typing import NewType
from uuid import UUID

Nonce = NewType("Nonce", int)
RequestId = NewType("RequestId", UUID)
ExecutionId = NewType("ExecutionId", UUID)
8 changes: 5 additions & 3 deletions src/aleph_vrf/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

from utilitybelt import dev_urandom_entropy

from aleph_vrf.types import Nonce


def xor_all(x: List[bytes]) -> bytes:
"""XORs all the bytes in the list together."""
Expand Down Expand Up @@ -33,12 +35,12 @@ def binary_to_bytes(s: str):
return int(s, 2).to_bytes((len(s) + 7) // 8, byteorder="big")


def generate_nonce() -> int:
def generate_nonce() -> Nonce:
"""Generates pseudo-random nonce number."""
return randint(0, 100000000)
return Nonce(randint(0, 100000000))


def generate(n: int, nonce: int) -> Tuple[bytes, str]:
def generate(n: int, nonce: Nonce) -> Tuple[bytes, str]:
"""Generates a number of random bytes and hashes them with the nonce."""
random_bytes: bytes = dev_urandom_entropy(n)
random_hash = sha3_256(random_bytes + int_to_bytes(nonce)).hexdigest()
Expand Down

0 comments on commit c47b29c

Please sign in to comment.