diff --git a/glsim/README.md b/glsim/README.md index 4053253..47ba9ac 100644 --- a/glsim/README.md +++ b/glsim/README.md @@ -145,9 +145,9 @@ Contracts that read sibling files via `open("/contract/OtherModule.py")` work ### Cross-Contract Calls Contracts using `gl.contract.deploy()`, `gl.contract.get_at().view()`, and `gl.contract.get_at().emit()` work. glsim handles: -- **DeployContract** — deploys child contract with isolated storage +- **EmitInternalDeployMessage** — deploys child contract with isolated storage - **CallContract** — calls method on deployed contract, returns result -- **PostMessage** — fire-and-forget call (no return value) +- **EmitInternalMessage** — fire-and-forget call (no return value) ### GenVM Library Stubs diff --git a/glsim/engine.py b/glsim/engine.py index 4c62021..9693134 100644 --- a/glsim/engine.py +++ b/glsim/engine.py @@ -614,14 +614,22 @@ def _install_live_handlers(self) -> None: self.vm._live_llm_handler = self._llm_handler def install_cross_contract_hook(self) -> None: - """Install gl_call hook for cross-contract calls (DeployContract, CallContract, PostMessage).""" + """Install gl_call hooks for current and rc7 cross-contract calls.""" engine = self def hook(vm, request): + if "EmitInternalDeployMessage" in request: + return engine._handle_deploy_in_contract( + vm, request["EmitInternalDeployMessage"] + ) if "DeployContract" in request: return engine._handle_deploy_in_contract(vm, request["DeployContract"]) if "CallContract" in request: return engine._handle_call_in_contract(vm, request["CallContract"]) + if "EmitInternalMessage" in request: + return engine._handle_post_in_contract( + vm, request["EmitInternalMessage"] + ) if "PostMessage" in request: return engine._handle_post_in_contract(vm, request["PostMessage"]) return None diff --git a/gltest/direct/sdk_loader.py b/gltest/direct/sdk_loader.py index b6a5914..d463270 100644 --- a/gltest/direct/sdk_loader.py +++ b/gltest/direct/sdk_loader.py @@ -11,6 +11,7 @@ import json import shutil import tarfile +import zipfile import platform import tempfile import urllib.error @@ -42,6 +43,9 @@ def _host_release_asset() -> str: GENVM_VERSION_ENV = "GENVM_VERSION" FALLBACK_VERSION = "v0.6.0-rc0" +# v0.3 runner trees use .zip; the v0.2 legacy-runners tree uses .tar. +RUNNER_ARCHIVE_EXTS = (".tar", ".zip") + RUNNER_TYPE = "py-genlayer" STD_LIB_TYPE = "py-lib-genlayer-std" EMBEDDINGS_TYPE = "py-lib-genlayer-embeddings" @@ -179,21 +183,33 @@ def _extract_local_runner( root: Path, runner_type: str, runner_hash: Optional[str] ) -> Path: """Extract a runner from a local prebuilt GenVM tree (GENVM_PREBUILT_DIR); globs - any *runners* dir so runners/ and executor//legacy-runners/ both match.""" + any *runners* dir so runners/ and executor//legacy-runners/ both match. + v0.3 runners ship as .zip, the v0.2 legacy tree still ships .tar.""" sub = ( - f"{runner_hash[:2]}/{runner_hash[2:]}.tar" + f"{runner_hash[:2]}/{runner_hash[2:]}" if runner_hash and runner_hash.lower() != "latest" - else "*/*.tar" + else "*/*" + ) + hits = sorted( + hit + for ext in RUNNER_ARCHIVE_EXTS + for hit in root.glob(f"**/*runners*/{runner_type}/{sub}{ext}") ) - hits = sorted(root.glob(f"**/*runners*/{runner_type}/{sub}")) if not hits: raise FileNotFoundError(f"runner {runner_type}:{runner_hash} not under {root}") - tar = hits[-1] - dest = CACHE_DIR / "extracted" / "local" / runner_type / (tar.parent.name + tar.stem) + archive = hits[-1] + dest = ( + CACHE_DIR / "extracted" / "local" / runner_type + / (archive.parent.name + archive.stem) + ) if not dest.exists(): dest.mkdir(parents=True, exist_ok=True) - with tarfile.open(tar, "r:") as inner: - inner.extractall(dest, filter="data") + if archive.suffix == ".zip": + with zipfile.ZipFile(archive) as inner: + inner.extractall(dest) + else: + with tarfile.open(archive, "r:") as inner: + inner.extractall(dest, filter="data") return dest diff --git a/gltest/direct/vm.py b/gltest/direct/vm.py index a88f5af..c54e113 100644 --- a/gltest/direct/vm.py +++ b/gltest/direct/vm.py @@ -202,7 +202,7 @@ class VMContext: _live_web_handler: Optional[Any] = None _live_llm_handler: Optional[Any] = None - # Cross-contract call hook (for glsim — handles DeployContract/CallContract/PostMessage) + # Cross-contract call hook (glsim accepts current and rc7 request names). _gl_call_hook: Optional[Any] = None # Debug tracing diff --git a/gltest/direct/wasi_mock.py b/gltest/direct/wasi_mock.py index 5c490e2..e463210 100644 --- a/gltest/direct/wasi_mock.py +++ b/gltest/direct/wasi_mock.py @@ -84,7 +84,15 @@ def get_self_balance() -> int: return vm._balances.get(addr_bytes, 0) -_CROSS_CONTRACT_OPS = frozenset({"DeployContract", "CallContract", "PostMessage"}) +_CROSS_CONTRACT_OPS = frozenset( + { + "DeployContract", + "EmitInternalDeployMessage", + "CallContract", + "PostMessage", + "EmitInternalMessage", + } +) def gl_call(data: bytes, /) -> int: diff --git a/tests/examples/contracts/intelligent_oracle_factory.py b/tests/examples/contracts/intelligent_oracle_factory.py index c49e335..f92adf4 100644 --- a/tests/examples/contracts/intelligent_oracle_factory.py +++ b/tests/examples/contracts/intelligent_oracle_factory.py @@ -38,7 +38,7 @@ def create_new_prediction_market( earliest_resolution_date, ], salt_nonce=registered_contracts + 1, - on="accepted", + on="decided", ) print("contract_address", contract_address) print("contract_address type", type(contract_address)) diff --git a/tests/examples/contracts/log_indexer.py b/tests/examples/contracts/log_indexer.py index 5637eb7..e2a78ba 100644 --- a/tests/examples/contracts/log_indexer.py +++ b/tests/examples/contracts/log_indexer.py @@ -23,7 +23,9 @@ class StoreValue: # contract class class LogIndexer(gl.contract.Contract): - vector_store: gle.VecDB[np.float32, typing.Literal[384], StoreValue] + vector_store: gle.VecDB[ + np.float32, typing.Literal[384], StoreValue, gle.EuclideanDistance + ] def __init__(self): pass diff --git a/tests/examples/contracts/multi_file_contract/__init__.py b/tests/examples/contracts/multi_file_contract/__init__.py index 8927ab5..9d23dcb 100644 --- a/tests/examples/contracts/multi_file_contract/__init__.py +++ b/tests/examples/contracts/multi_file_contract/__init__.py @@ -12,7 +12,7 @@ def __init__(self): args=["123"], salt_nonce=1, value=0, - on="accepted", + on="decided", ) @gl.public.write diff --git a/tests/examples/contracts/multi_tenant_storage.py b/tests/examples/contracts/multi_tenant_storage.py index 2bcd15d..a1bcd75 100644 --- a/tests/examples/contracts/multi_tenant_storage.py +++ b/tests/examples/contracts/multi_tenant_storage.py @@ -46,6 +46,6 @@ def update_storage(self, new_storage: str) -> None: self.available_storage_contracts.pop() contract_to_use = self.mappings[gl.message.sender_address] - gl.contract.get_at(contract_to_use).emit(on="accepted").update_storage( + gl.contract.get_at(contract_to_use).emit(on="decided").update_storage( new_storage ) diff --git a/tests/glsim/deterministic_factory_contract.py b/tests/glsim/deterministic_factory_contract.py index ef51fcf..87db3f5 100644 --- a/tests/glsim/deterministic_factory_contract.py +++ b/tests/glsim/deterministic_factory_contract.py @@ -25,7 +25,7 @@ def deploy_child(self, salt: int) -> str: args=[], kwargs={}, salt_nonce=salt, - on="accepted", + on="decided", ) self.child_address = child_address.as_hex return self.child_address diff --git a/tests/gltest_direct/test_direct_runner.py b/tests/gltest_direct/test_direct_runner.py index 42f0036..95baab3 100644 --- a/tests/gltest_direct/test_direct_runner.py +++ b/tests/gltest_direct/test_direct_runner.py @@ -250,7 +250,8 @@ class TestNondetRestrictions: """Tests that cross-contract calls are forbidden inside nondet context. GenVM raises SystemError: 6 (forbidden) when contract code attempts - cross-contract calls (DeployContract, CallContract, PostMessage) inside + cross-contract calls (EmitInternalDeployMessage, CallContract, + EmitInternalMessage) inside eq_principle/run_nondet. These tests verify gltest enforces the same restriction in direct mode. """ @@ -278,7 +279,7 @@ def bad_leader(): gl_vm.run_nondet(bad_leader, lambda r: True) def test_deploy_contract_forbidden_in_nondet(self, direct_vm, direct_deploy): - """DeployContract inside run_nondet raises RuntimeError.""" + """EmitInternalDeployMessage inside run_nondet raises RuntimeError.""" direct_deploy(str(CONTRACTS_DIR / "storage.py"), "v") import genlayer.vm as gl_vm @@ -286,7 +287,7 @@ def test_deploy_contract_forbidden_in_nondet(self, direct_vm, direct_deploy): from gltest.direct import wasi_mock def bad_leader(): - request = {"DeployContract": {"code": b"pass", "calldata": {}}} + request = {"EmitInternalDeployMessage": {"code": b"pass", "calldata": {}}} wasi_mock.gl_call(calldata.encode(request)) return "should not reach" @@ -294,7 +295,7 @@ def bad_leader(): gl_vm.run_nondet(bad_leader, lambda r: True) def test_post_message_forbidden_in_nondet(self, direct_vm, direct_deploy): - """PostMessage inside run_nondet raises RuntimeError.""" + """EmitInternalMessage inside run_nondet raises RuntimeError.""" direct_deploy(str(CONTRACTS_DIR / "storage.py"), "v") import genlayer.vm as gl_vm @@ -303,7 +304,7 @@ def test_post_message_forbidden_in_nondet(self, direct_vm, direct_deploy): def bad_leader(): request = { - "PostMessage": { + "EmitInternalMessage": { "address": b"\x00" * 20, "calldata": {"method": "bar", "args": []}, }