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
20 changes: 19 additions & 1 deletion gltest/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@


ACCEPTED_STATUSES = {"ACCEPTED", "FINALIZED", "5", "7"}
ACCEPTED_LIFECYCLE_OUTCOMES = {None, "accepted"}
SUCCESS_RESULTS = {"FINISHED_WITH_RETURN", "1"}


Expand All @@ -19,9 +20,26 @@ def _string_value(value: Any) -> Optional[str]:
return str(enum_value)


def _accepted_lifecycle(result: GenLayerTransaction) -> Optional[bool]:
"""Read the layered lifecycle, or None when the receipt has none."""
lifecycle = result.get("lifecycle")
if not isinstance(lifecycle, dict):
return None
state = lifecycle.get("state")
if state == "decided":
return lifecycle.get("outcome") == "accepted"
if state == "finalized":
return lifecycle.get("outcome") in ACCEPTED_LIFECYCLE_OUTCOMES
return False


def _has_accepted_status(result: GenLayerTransaction) -> bool:
accepted_lifecycle = _accepted_lifecycle(result)
if accepted_lifecycle is not None:
return accepted_lifecycle
# Receipts from a pre-lifecycle SDK still carry a flat status.
status = _string_value(result.get("status_name", result.get("status")))
return status in ACCEPTED_STATUSES
return status is not None and status.upper() in ACCEPTED_STATUSES


def _leader_receipt(result: GenLayerTransaction) -> Optional[dict]:
Expand Down
8 changes: 4 additions & 4 deletions gltest/contracts/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from gltest.types import (
CalldataEncodable,
GenLayerTransaction,
TransactionStatus,
ProtocolTransactionStatus,
TransactionHashVariant,
TransactionContext,
)
Expand Down Expand Up @@ -88,11 +88,11 @@ def transact_method(
fees: Optional[Dict[str, Any]] = None,
fee_value: Optional[int] = None,
wait_until: Optional[Literal["decided", "finalized"]] = None,
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_transaction_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
wait_interval: Optional[int] = None,
wait_retries: Optional[int] = None,
wait_triggered_transactions: bool = False,
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_triggered_transactions_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
transaction_context: Optional[TransactionContext] = None,
):
"""
Expand Down Expand Up @@ -252,7 +252,7 @@ def appeal(
self,
tx_hash: str,
value: int = 0,
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_transaction_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
wait_until: Optional[Literal["decided", "finalized"]] = None,
wait_interval: Optional[int] = None,
wait_retries: Optional[int] = None,
Expand Down
14 changes: 9 additions & 5 deletions gltest/contracts/contract_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
from genlayer_py.types import SimConfig
from .contract import Contract
from gltest.logging import logger
from gltest.types import TransactionStatus, GenLayerTransaction, CalldataEncodable
from gltest.types import (
ProtocolTransactionStatus,
GenLayerTransaction,
CalldataEncodable,
)
from gltest.assertions import tx_execution_failed
from gltest.exceptions import DeploymentError
from gltest_cli.config.general import get_general_config
Expand Down Expand Up @@ -130,9 +134,9 @@ def deploy(
wait_until: Optional[Literal["decided", "finalized"]] = None,
wait_interval: Optional[int] = None,
wait_retries: Optional[int] = None,
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_transaction_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
wait_triggered_transactions: bool = False,
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_triggered_transactions_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
transaction_context: Optional[TransactionContext] = None,
) -> Contract:
"""
Expand Down Expand Up @@ -172,9 +176,9 @@ def deploy_contract_tx(
wait_until: Optional[Literal["decided", "finalized"]] = None,
wait_interval: Optional[int] = None,
wait_retries: Optional[int] = None,
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_transaction_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
wait_triggered_transactions: bool = False,
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_triggered_transactions_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
transaction_context: Optional[TransactionContext] = None,
) -> GenLayerTransaction:
"""
Expand Down
10 changes: 7 additions & 3 deletions gltest/contracts/contract_functions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from dataclasses import dataclass
from typing import Callable, Optional, Dict, Any, Literal
from gltest.types import TransactionStatus, TransactionHashVariant, TransactionContext
from gltest.types import (
ProtocolTransactionStatus,
TransactionHashVariant,
TransactionContext,
)


@dataclass
Expand Down Expand Up @@ -31,11 +35,11 @@ def transact(
fees: Optional[Dict[str, Any]] = None,
fee_value: Optional[int] = None,
wait_until: Optional[Literal["decided", "finalized"]] = None,
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_transaction_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
wait_interval: Optional[int] = None,
wait_retries: Optional[int] = None,
wait_triggered_transactions: bool = False,
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
wait_triggered_transactions_status: ProtocolTransactionStatus = ProtocolTransactionStatus.ACCEPTED,
transaction_context: Optional[TransactionContext] = None,
):
"""Executes a state-changing contract method through consensus. Returns the transaction receipt."""
Expand Down
17 changes: 11 additions & 6 deletions gltest/contracts/wait.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import inspect
from typing import Callable, Literal
from typing import Any, Callable, Literal

from gltest.types import TransactionStatus
from gltest.types import ProtocolTransactionStatus


def _status_text(status: Any) -> str:
"""Normalize an enum member, its value, or a bare string to one form."""
return str(getattr(status, "value", status)).upper()


def wait_until_from_status(
status: TransactionStatus,
status: ProtocolTransactionStatus,
) -> Literal["decided", "finalized"]:
if status == TransactionStatus.FINALIZED:
if _status_text(status) == _status_text(ProtocolTransactionStatus.FINALIZED):
return "finalized"
return "decided"


def _status_from_wait_until(wait_until: Literal["decided", "finalized"]):
if wait_until == "finalized":
return TransactionStatus.FINALIZED
return TransactionStatus.ACCEPTED
return ProtocolTransactionStatus.FINALIZED
return ProtocolTransactionStatus.ACCEPTED


def _accepts_var_kwargs(call: Callable) -> bool:
Expand Down
17 changes: 16 additions & 1 deletion gltest/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@
from genlayer_py.types import (
CalldataAddress,
GenLayerTransaction,
TransactionStatus,
CalldataEncodable,
TransactionHashVariant,
)
from typing import List, TypedDict, Dict, Any

try:
# genlayer-py layers the consumer lifecycle over the raw protocol status.
from genlayer_py.types.transactions import ProtocolTransactionStatus
except ImportError: # genlayer-py before the lifecycle layering
from genlayer_py.types import TransactionStatus as ProtocolTransactionStatus

try:
from genlayer_py.types import TransactionLifecycle
except ImportError: # genlayer-py before the lifecycle layering
TransactionLifecycle = Dict[str, Any]

# gltest keeps `TransactionStatus` as part of its own public API for the test
# suites that already pass it to `wait_transaction_status`. Internal code uses
# the protocol name; new code should express waits with `wait_until` instead.
TransactionStatus = ProtocolTransactionStatus


class MockedLLMResponse(TypedDict):
"""Maps prompts to responses"""
Expand Down
41 changes: 41 additions & 0 deletions tests/gltest/assertions/test_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,47 @@ def test_undetermined_transaction_is_not_successful():
assert tx_execution_failed(transaction) is True


def test_decided_lifecycle_transaction_is_successful():
transaction = {
"lifecycle": {"state": "decided", "outcome": "accepted"},
"tx_execution_result_name": "FINISHED_WITH_RETURN",
}

assert tx_execution_succeeded(transaction) is True
assert tx_execution_failed(transaction) is False


def test_finalized_lifecycle_transaction_is_successful():
transaction = {
"lifecycle": {"state": "finalized", "outcome": "accepted"},
"consensus_data": {"leader_receipt": [{"execution_result": "SUCCESS"}]},
}

assert tx_execution_succeeded(transaction) is True
assert tx_execution_failed(transaction) is False


def test_undetermined_lifecycle_transaction_is_not_successful():
transaction = {
"lifecycle": {"state": "decided", "outcome": "undetermined"},
"tx_execution_result_name": "FINISHED_WITH_RETURN",
"consensus_data": {"leader_receipt": [{"execution_result": "SUCCESS"}]},
}

assert tx_execution_succeeded(transaction) is False
assert tx_execution_failed(transaction) is True


def test_processing_lifecycle_transaction_is_not_successful():
transaction = {
"lifecycle": {"state": "processing", "phase": "revealing"},
"tx_execution_result_name": "FINISHED_WITH_RETURN",
}

assert tx_execution_succeeded(transaction) is False
assert tx_execution_failed(transaction) is True


def test_error_transaction_is_not_successful():
transaction = {
"status": "ACCEPTED",
Expand Down
Loading