Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 18 additions & 18 deletions aleph_message/models/execution/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import List, Optional

from pydantic import Field, model_validator
from typing_extensions import Self

from aleph_message.models.abstract import HashableModel

Expand Down Expand Up @@ -43,38 +44,37 @@ class InstanceContent(BaseExecutableContent):
)

@model_validator(mode="after")
def check_requirements(cls, values):
if values.requirements:
def check_requirements(self) -> Self:
if self.requirements:
if (
self.payment and (self.payment.is_stream or self.payment.is_credit)
) and (not self.requirements.node or not self.requirements.node.node_hash):
raise ValueError(
"Node hash assignment is needed for PAYG or Credit payments"
)
# GPU filter only supported for QEmu instances with node_hash assigned
if values.requirements.gpu:
if (
not values.requirements.node
or not values.requirements.node.node_hash
):
if self.requirements.gpu:
if not self.requirements.node or not self.requirements.node.node_hash:
raise ValueError("Node hash assignment is needed for GPU support")

if (
values.environment
and values.environment.hypervisor != HypervisorType.qemu
self.environment
and self.environment.hypervisor != HypervisorType.qemu
):
raise ValueError("GPU option is only supported for QEmu hypervisor")

# Terms and conditions filter only supported for PAYG/coco instances with node_hash assigned
if (
values.requirements.node
and values.requirements.node.terms_and_conditions
):
if not values.requirements.node.node_hash:
if self.requirements.node and self.requirements.node.terms_and_conditions:
if not self.requirements.node.node_hash:
raise ValueError(
"Terms_and_conditions field needs a requirements.node.node_hash value"
)

if (
not values.payment.is_stream
and not values.environment.trusted_execution
):
not self.payment or not self.payment.is_stream
) and not self.environment.trusted_execution:
raise ValueError(
"Only PAYG/coco instances can have a terms_and_conditions"
)

return values
return self
65 changes: 65 additions & 0 deletions aleph_message/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,71 @@ def test_validation_on_gpu_hypervisor_options():
) # Ignore "Value error, ..."


def test_validation_on_payg_payment_options():
"""Ensure that a node_hash option is required for stream payments."""
path = Path(__file__).parent / "messages/instance_gpu_machine.json"
message_dict = json.loads(path.read_text())
message_dict["content"]["requirements"]["gpu"] = None
message = create_new_message(message_dict, factory=InstanceMessage)

assert isinstance(message, InstanceMessage)
assert hash(message.content)
assert message.content.payment
assert message.content.payment.type == PaymentType.superfluid
assert message.content.environment.hypervisor == HypervisorType.qemu

message_dict["content"]["requirements"]["node"] = None
try:
_ = create_new_message(message_dict, factory=InstanceMessage)
raise AssertionError("An exception should have been raised before this point.")
except ValidationError as e:
assert e.errors()[0]["loc"] in [("content",), ("content", "__root__")]

error_msg = e.errors()[0]["msg"]
assert (
"Node hash assignment is needed for PAYG or Credit payments" in error_msg
) # Ignore "Value error, ..."


def test_validation_on_credits_payment_options():
"""Ensure that a node_hash option is required for credit payments."""
path = Path(__file__).parent / "messages/instance_gpu_machine.json"
message_dict = json.loads(path.read_text())
# Patch the gpu field with some info
message_dict["content"]["payment"]["type"] = "credit"
message_dict["content"]["payment"]["receiver"] = None
message = create_new_message(message_dict, factory=InstanceMessage)

assert isinstance(message, InstanceMessage)
assert hash(message.content)
assert message.content.payment
assert message.content.payment.type == PaymentType.credit
assert message.content.environment.hypervisor == HypervisorType.qemu

# Remove gpu field with some info
message_dict["content"]["requirements"]["gpu"] = None
message = create_new_message(message_dict, factory=InstanceMessage)

assert isinstance(message, InstanceMessage)
assert hash(message.content)
assert message.content.payment
assert message.content.payment.type == PaymentType.credit
assert message.content.environment.hypervisor == HypervisorType.qemu
assert message.content.requirements.gpu is None

message_dict["content"]["requirements"]["node"] = None
try:
_ = create_new_message(message_dict, factory=InstanceMessage)
raise AssertionError("An exception should have been raised before this point.")
except ValidationError as e:
assert e.errors()[0]["loc"] in [("content",), ("content", "__root__")]

error_msg = e.errors()[0]["msg"]
assert (
"Node hash assignment is needed for PAYG or Credit payments" in error_msg
) # Ignore "Value error, ..."


def test_message_machine_port_mapping():
message_dict = {
"chain": "ETH",
Expand Down
Loading