zexus 1.6.8 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/README.md +12 -5
  2. package/package.json +1 -1
  3. package/src/__init__.py +7 -0
  4. package/src/zexus/__init__.py +1 -1
  5. package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
  6. package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
  7. package/src/zexus/__pycache__/debug_sanitizer.cpython-312.pyc +0 -0
  8. package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
  9. package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
  10. package/src/zexus/__pycache__/input_validation.cpython-312.pyc +0 -0
  11. package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
  12. package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
  13. package/src/zexus/__pycache__/module_manager.cpython-312.pyc +0 -0
  14. package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
  15. package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
  16. package/src/zexus/__pycache__/security_enforcement.cpython-312.pyc +0 -0
  17. package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
  18. package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  19. package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
  20. package/src/zexus/access_control_system/__pycache__/__init__.cpython-312.pyc +0 -0
  21. package/src/zexus/access_control_system/__pycache__/access_control.cpython-312.pyc +0 -0
  22. package/src/zexus/advanced_types.py +17 -2
  23. package/src/zexus/blockchain/__init__.py +411 -0
  24. package/src/zexus/blockchain/accelerator.py +1160 -0
  25. package/src/zexus/blockchain/chain.py +660 -0
  26. package/src/zexus/blockchain/consensus.py +821 -0
  27. package/src/zexus/blockchain/contract_vm.py +1019 -0
  28. package/src/zexus/blockchain/crypto.py +79 -14
  29. package/src/zexus/blockchain/events.py +526 -0
  30. package/src/zexus/blockchain/loadtest.py +721 -0
  31. package/src/zexus/blockchain/monitoring.py +350 -0
  32. package/src/zexus/blockchain/mpt.py +716 -0
  33. package/src/zexus/blockchain/multichain.py +951 -0
  34. package/src/zexus/blockchain/multiprocess_executor.py +338 -0
  35. package/src/zexus/blockchain/network.py +886 -0
  36. package/src/zexus/blockchain/node.py +666 -0
  37. package/src/zexus/blockchain/rpc.py +1203 -0
  38. package/src/zexus/blockchain/rust_bridge.py +421 -0
  39. package/src/zexus/blockchain/storage.py +423 -0
  40. package/src/zexus/blockchain/tokens.py +750 -0
  41. package/src/zexus/blockchain/upgradeable.py +1004 -0
  42. package/src/zexus/blockchain/verification.py +1602 -0
  43. package/src/zexus/blockchain/wallet.py +621 -0
  44. package/src/zexus/capability_system.py +184 -9
  45. package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
  46. package/src/zexus/cli/main.py +383 -34
  47. package/src/zexus/cli/zpm.py +1 -1
  48. package/src/zexus/compiler/__pycache__/bytecode.cpython-312.pyc +0 -0
  49. package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
  50. package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
  51. package/src/zexus/compiler/__pycache__/semantic.cpython-312.pyc +0 -0
  52. package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
  53. package/src/zexus/compiler/bytecode.py +124 -7
  54. package/src/zexus/compiler/compat_runtime.py +6 -2
  55. package/src/zexus/compiler/lexer.py +16 -5
  56. package/src/zexus/compiler/parser.py +108 -7
  57. package/src/zexus/compiler/semantic.py +18 -19
  58. package/src/zexus/compiler/zexus_ast.py +26 -1
  59. package/src/zexus/concurrency_system.py +79 -0
  60. package/src/zexus/config.py +54 -0
  61. package/src/zexus/crypto_bridge.py +244 -8
  62. package/src/zexus/dap/__init__.py +10 -0
  63. package/src/zexus/dap/__main__.py +4 -0
  64. package/src/zexus/dap/dap_server.py +391 -0
  65. package/src/zexus/dap/debug_engine.py +298 -0
  66. package/src/zexus/environment.py +112 -9
  67. package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
  68. package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
  69. package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
  70. package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
  71. package/src/zexus/evaluator/__pycache__/resource_limiter.cpython-312.pyc +0 -0
  72. package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
  73. package/src/zexus/evaluator/__pycache__/unified_execution.cpython-312.pyc +0 -0
  74. package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
  75. package/src/zexus/evaluator/bytecode_compiler.py +457 -37
  76. package/src/zexus/evaluator/core.py +644 -50
  77. package/src/zexus/evaluator/expressions.py +358 -62
  78. package/src/zexus/evaluator/functions.py +458 -20
  79. package/src/zexus/evaluator/resource_limiter.py +4 -4
  80. package/src/zexus/evaluator/statements.py +774 -122
  81. package/src/zexus/evaluator/unified_execution.py +573 -72
  82. package/src/zexus/evaluator/utils.py +14 -2
  83. package/src/zexus/evaluator_original.py +1 -1
  84. package/src/zexus/event_loop.py +186 -0
  85. package/src/zexus/lexer.py +742 -458
  86. package/src/zexus/lsp/__init__.py +1 -1
  87. package/src/zexus/lsp/definition_provider.py +163 -9
  88. package/src/zexus/lsp/server.py +22 -8
  89. package/src/zexus/lsp/symbol_provider.py +182 -9
  90. package/src/zexus/module_cache.py +239 -9
  91. package/src/zexus/module_manager.py +129 -1
  92. package/src/zexus/object.py +76 -6
  93. package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
  94. package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
  95. package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
  96. package/src/zexus/parser/parser.py +1349 -408
  97. package/src/zexus/parser/strategy_context.py +755 -58
  98. package/src/zexus/parser/strategy_structural.py +121 -21
  99. package/src/zexus/persistence.py +15 -1
  100. package/src/zexus/renderer/__init__.py +61 -0
  101. package/src/zexus/renderer/__pycache__/__init__.cpython-312.pyc +0 -0
  102. package/src/zexus/renderer/__pycache__/backend.cpython-312.pyc +0 -0
  103. package/src/zexus/renderer/__pycache__/canvas.cpython-312.pyc +0 -0
  104. package/src/zexus/renderer/__pycache__/color_system.cpython-312.pyc +0 -0
  105. package/src/zexus/renderer/__pycache__/layout.cpython-312.pyc +0 -0
  106. package/src/zexus/renderer/__pycache__/main_renderer.cpython-312.pyc +0 -0
  107. package/src/zexus/renderer/__pycache__/painter.cpython-312.pyc +0 -0
  108. package/src/zexus/renderer/backend.py +261 -0
  109. package/src/zexus/renderer/canvas.py +78 -0
  110. package/src/zexus/renderer/color_system.py +201 -0
  111. package/src/zexus/renderer/graphics.py +31 -0
  112. package/src/zexus/renderer/layout.py +222 -0
  113. package/src/zexus/renderer/main_renderer.py +66 -0
  114. package/src/zexus/renderer/painter.py +30 -0
  115. package/src/zexus/renderer/tk_backend.py +208 -0
  116. package/src/zexus/renderer/web_backend.py +260 -0
  117. package/src/zexus/runtime/__init__.py +10 -2
  118. package/src/zexus/runtime/__pycache__/__init__.cpython-312.pyc +0 -0
  119. package/src/zexus/runtime/__pycache__/async_runtime.cpython-312.pyc +0 -0
  120. package/src/zexus/runtime/__pycache__/load_manager.cpython-312.pyc +0 -0
  121. package/src/zexus/runtime/file_flags.py +137 -0
  122. package/src/zexus/runtime/load_manager.py +368 -0
  123. package/src/zexus/safety/__pycache__/__init__.cpython-312.pyc +0 -0
  124. package/src/zexus/safety/__pycache__/memory_safety.cpython-312.pyc +0 -0
  125. package/src/zexus/security.py +424 -34
  126. package/src/zexus/stdlib/fs.py +23 -18
  127. package/src/zexus/stdlib/http.py +289 -186
  128. package/src/zexus/stdlib/sockets.py +207 -163
  129. package/src/zexus/stdlib/websockets.py +282 -0
  130. package/src/zexus/stdlib_integration.py +369 -2
  131. package/src/zexus/strategy_recovery.py +6 -3
  132. package/src/zexus/type_checker.py +423 -0
  133. package/src/zexus/virtual_filesystem.py +189 -2
  134. package/src/zexus/vm/__init__.py +113 -3
  135. package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
  136. package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
  137. package/src/zexus/vm/__pycache__/bytecode_converter.cpython-312.pyc +0 -0
  138. package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
  139. package/src/zexus/vm/__pycache__/compiler.cpython-312.pyc +0 -0
  140. package/src/zexus/vm/__pycache__/gas_metering.cpython-312.pyc +0 -0
  141. package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
  142. package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
  143. package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
  144. package/src/zexus/vm/async_optimizer.py +80 -6
  145. package/src/zexus/vm/binary_bytecode.py +659 -0
  146. package/src/zexus/vm/bytecode.py +59 -11
  147. package/src/zexus/vm/bytecode_converter.py +26 -12
  148. package/src/zexus/vm/cabi.c +1985 -0
  149. package/src/zexus/vm/cabi.cpython-312-x86_64-linux-gnu.so +0 -0
  150. package/src/zexus/vm/cabi.h +127 -0
  151. package/src/zexus/vm/cache.py +561 -17
  152. package/src/zexus/vm/compiler.py +818 -51
  153. package/src/zexus/vm/fastops.c +15743 -0
  154. package/src/zexus/vm/fastops.cpython-312-x86_64-linux-gnu.so +0 -0
  155. package/src/zexus/vm/fastops.pyx +288 -0
  156. package/src/zexus/vm/gas_metering.py +50 -9
  157. package/src/zexus/vm/jit.py +364 -20
  158. package/src/zexus/vm/native_jit_backend.py +1816 -0
  159. package/src/zexus/vm/native_runtime.cpp +1388 -0
  160. package/src/zexus/vm/native_runtime.cpython-312-x86_64-linux-gnu.so +0 -0
  161. package/src/zexus/vm/optimizer.py +161 -11
  162. package/src/zexus/vm/parallel_vm.py +140 -45
  163. package/src/zexus/vm/peephole_optimizer.py +82 -4
  164. package/src/zexus/vm/profiler.py +38 -18
  165. package/src/zexus/vm/register_allocator.py +16 -5
  166. package/src/zexus/vm/register_vm.py +8 -5
  167. package/src/zexus/vm/vm.py +3581 -531
  168. package/src/zexus/vm/wasm_compiler.py +658 -0
  169. package/src/zexus/zexus_ast.py +137 -11
  170. package/src/zexus/zexus_token.py +16 -5
  171. package/src/zexus/zpm/installer.py +55 -15
  172. package/src/zexus/zpm/package_manager.py +1 -1
  173. package/src/zexus/zpm/registry.py +257 -28
  174. package/src/zexus.egg-info/PKG-INFO +16 -6
  175. package/src/zexus.egg-info/SOURCES.txt +129 -17
  176. package/src/zexus.egg-info/entry_points.txt +1 -0
  177. package/src/zexus.egg-info/requires.txt +4 -0
@@ -13,6 +13,8 @@ import uuid
13
13
  import sqlite3
14
14
  import time
15
15
  import hashlib
16
+ import threading
17
+ from zexus.config import config as zexus_config
16
18
 
17
19
  # Try importing advanced database drivers
18
20
  try:
@@ -27,16 +29,49 @@ try:
27
29
  except ImportError:
28
30
  _ROCKSDB_AVAILABLE = False
29
31
 
30
- from .object import (
32
+ from zexus.object import (
31
33
  Environment, Map, String, Integer, Float, Boolean as BooleanObj,
32
34
  Builtin, List, Null, EvaluationError as ObjectEvaluationError, NULL
33
35
  )
34
36
 
35
37
  try:
36
- from .object import ContractReference
38
+ from zexus.object import ContractReference
37
39
  except ImportError: # Fallback if optional type missing
38
40
  ContractReference = None
39
41
 
42
+ # =============================================
43
+ # Shared Evaluator Cache for Performance
44
+ # =============================================
45
+ # Creating a new Evaluator() for every contract method call is expensive
46
+ # This cache provides thread-local evaluators that can be reused
47
+
48
+ _evaluator_cache = threading.local()
49
+ _vm_action_context = threading.local()
50
+
51
+ def _get_vm_action_context() -> bool:
52
+ return bool(getattr(_vm_action_context, 'disable_vm', False))
53
+
54
+ def _set_vm_action_context(flag: bool) -> None:
55
+ _vm_action_context.disable_vm = bool(flag)
56
+
57
+ def _get_cached_evaluator():
58
+ """Get a cached evaluator instance for the current thread.
59
+
60
+ This significantly improves performance for contract method calls
61
+ by avoiding repeated Evaluator() initialization overhead.
62
+ """
63
+ if not hasattr(_evaluator_cache, 'evaluator'):
64
+ from zexus.evaluator.core import Evaluator
65
+ _evaluator_cache.evaluator = Evaluator()
66
+ return _evaluator_cache.evaluator
67
+
68
+ def _clear_evaluator_cache():
69
+ """Clear the evaluator cache (useful for testing)."""
70
+ if hasattr(_evaluator_cache, 'evaluator'):
71
+ del _evaluator_cache.evaluator
72
+
73
+ # =============================================
74
+
40
75
  # Ensure storage directory exists
41
76
  STORAGE_DIR = "chain_data"
42
77
  if not os.path.exists(STORAGE_DIR):
@@ -664,10 +699,8 @@ class EntityInstance:
664
699
  param_name = str(param)
665
700
  method_env.set(param_name, args[i])
666
701
 
667
- # Import evaluator to execute the method body
668
- # Avoid circular import by importing here
669
- from zexus.evaluator.core import Evaluator
670
- evaluator = Evaluator()
702
+ # Use cached evaluator for performance (avoids repeated Evaluator() initialization)
703
+ evaluator = _get_cached_evaluator()
671
704
 
672
705
  # Execute the method body with stack trace
673
706
  result = evaluator.eval_node(method.body, method_env, stack_trace=[])
@@ -881,6 +914,66 @@ class RocksDBBackend(StorageBackend):
881
914
  # CONTRACT SYSTEM - Blockchain State & Logic
882
915
  # ===============================================
883
916
 
917
+ class TrackingList(list):
918
+ def __init__(self, owner, iterable=None):
919
+ super().__init__(iterable or [])
920
+ self.owner = owner
921
+
922
+ def __setitem__(self, key, value):
923
+ super().__setitem__(key, value)
924
+ self.owner.mark_dirty(key)
925
+
926
+ def append(self, item):
927
+ idx = len(self)
928
+ super().append(item)
929
+ self.owner.mark_dirty(idx)
930
+
931
+ def extend(self, iterable):
932
+ start_idx = len(self)
933
+ super().extend(iterable)
934
+ end_idx = len(self)
935
+ for i in range(start_idx, end_idx):
936
+ self.owner.mark_dirty(i)
937
+
938
+ class StorageList(List):
939
+ """List wrapper for persistent storage"""
940
+ __slots__ = ('_dirty_indices', '_var_name', '_orig_elements')
941
+
942
+ def __init__(self, elements, var_name):
943
+ # We wrap elements in TrackingList
944
+ tracked = TrackingList(self, elements)
945
+ super().__init__(tracked)
946
+ self._dirty_indices = set()
947
+ self._var_name = var_name
948
+
949
+ def mark_dirty(self, index):
950
+ self._dirty_indices.add(index)
951
+
952
+ def mark_all_dirty(self):
953
+ # Mark all current indices as dirty
954
+ self._dirty_indices = set(range(len(self.elements)))
955
+
956
+ def mark_clean(self):
957
+ self._dirty_indices.clear()
958
+
959
+ @property
960
+ def dirty_indices(self):
961
+ return self._dirty_indices
962
+
963
+ def set(self, index, value):
964
+ """Set value at index, mirroring list item assignment."""
965
+ try:
966
+ idx = index.value if hasattr(index, 'value') else int(index)
967
+ except Exception:
968
+ raise ObjectEvaluationError(f"Invalid index for assignment: {index}")
969
+
970
+ if idx < 0 or idx >= len(self.elements):
971
+ raise ObjectEvaluationError(f"Index out of range: {idx}")
972
+
973
+ self.elements[idx] = value
974
+ self.mark_dirty(idx)
975
+ return value
976
+
884
977
  class StorageMap(Map):
885
978
  """Map wrapper that tracks dirty entries for persistent storage"""
886
979
 
@@ -924,25 +1017,39 @@ class StorageMap(Map):
924
1017
  return self._var_name
925
1018
 
926
1019
  class ContractStorage:
927
- """Persistent storage for contract state with DB selection"""
1020
+ """Persistent storage for contract state with DB selection
1021
+
1022
+ Storage Engine Priority:
1023
+ 1. Explicit db_type parameter
1024
+ 2. ZEXUS_STORAGE_ENGINE environment variable
1025
+ 3. Default: 'memory' for maximum performance
1026
+
1027
+ Set ZEXUS_STORAGE_ENGINE=sqlite for persistence in production.
1028
+ """
928
1029
 
929
- def __init__(self, contract_id, db_type="sqlite"):
1030
+ def __init__(self, contract_id, db_type=None):
930
1031
  self.transaction_log = []
1032
+
1033
+ # Determine storage type: explicit > env var > default (memory)
1034
+ if db_type is None:
1035
+ db_type = os.environ.get("ZEXUS_STORAGE_ENGINE", "memory")
931
1036
  self.db_type = db_type
932
1037
  self._map_meta_cache = {}
933
1038
 
934
1039
  # Determine strict path
935
1040
  base_path = os.path.join(STORAGE_DIR, f"{contract_id}")
936
1041
 
937
- # Initialize Backend
938
- if db_type == "leveldb" and _LEVELDB_AVAILABLE:
1042
+ # Initialize Backend - memory is now first for performance
1043
+ if db_type == "memory":
1044
+ self.backend = InMemoryBackend()
1045
+ elif db_type == "leveldb" and _LEVELDB_AVAILABLE:
939
1046
  self.backend = LevelDBBackend(base_path)
940
1047
  elif db_type == "rocksdb" and _ROCKSDB_AVAILABLE:
941
1048
  self.backend = RocksDBBackend(f"{base_path}.rdb")
942
1049
  elif db_type == "sqlite":
943
1050
  self.backend = SQLiteBackend(f"{base_path}.sqlite")
944
1051
  else:
945
- print(f" ⚠️ Storage Warning: '{db_type}' unavailable or unknown. Falling back to In-Memory.")
1052
+ # Unknown type, fall back to memory
946
1053
  self.backend = InMemoryBackend()
947
1054
 
948
1055
  self._cache_enabled = False
@@ -983,6 +1090,36 @@ class ContractStorage:
983
1090
  self._action_cache[key] = storage_map
984
1091
  self._persistent_cache[key] = storage_map
985
1092
  return storage_map
1093
+
1094
+ if isinstance(meta, dict) and meta.get("__kind") == "list":
1095
+ entries = self.backend.scan(self._list_entry_prefix(key))
1096
+ items = {}
1097
+ max_idx = -1
1098
+ prefix_len = len(self._list_entry_prefix(key))
1099
+
1100
+ for entry_key, payload in entries:
1101
+ idx_str = entry_key[prefix_len:]
1102
+ try:
1103
+ idx = int(idx_str)
1104
+ val = self._deserialize_recursive(json.loads(payload))
1105
+ items[idx] = val
1106
+ if idx > max_idx: max_idx = idx
1107
+ except ValueError:
1108
+ continue
1109
+
1110
+ length = meta.get("length", max_idx + 1)
1111
+ final_list = []
1112
+ for i in range(length):
1113
+ # We use NULL for missing items (should not happen in valid state)
1114
+ final_list.append(items.get(i, NULL))
1115
+
1116
+ storage_list = StorageList(final_list, key)
1117
+ storage_list.mark_clean()
1118
+
1119
+ if self._cache_enabled and self._action_cache is not None:
1120
+ self._action_cache[key] = storage_list
1121
+ self._persistent_cache[key] = storage_list
1122
+ return storage_list
986
1123
  except json.JSONDecodeError:
987
1124
  pass
988
1125
 
@@ -1011,6 +1148,19 @@ class ContractStorage:
1011
1148
  self._store_map(key, storage_map)
1012
1149
  return
1013
1150
 
1151
+ if isinstance(value, List):
1152
+ if isinstance(value, StorageList):
1153
+ storage_list = value
1154
+ else:
1155
+ storage_list = StorageList(value.elements, key)
1156
+ storage_list.mark_all_dirty()
1157
+
1158
+ if self._cache_enabled and self._action_cache is not None:
1159
+ self._action_cache[key] = storage_list
1160
+ self._persistent_cache[key] = storage_list
1161
+ self._store_list(key, storage_list)
1162
+ return
1163
+
1014
1164
  serialized = self._serialize(value)
1015
1165
  self.backend.set(key, serialized)
1016
1166
  if self._cache_enabled and self._action_cache is not None:
@@ -1102,6 +1252,39 @@ class ContractStorage:
1102
1252
  if isinstance(map_obj, StorageMap):
1103
1253
  map_obj.mark_clean()
1104
1254
 
1255
+ def _list_entry_prefix(self, storage_key):
1256
+ return f"{storage_key}:L:"
1257
+
1258
+ def _list_entry_key(self, storage_key, index):
1259
+ return f"{self._list_entry_prefix(storage_key)}{index}"
1260
+
1261
+ def _store_list(self, storage_key, list_obj):
1262
+ meta = {"__kind": "list", "version": 1, "length": len(list_obj.elements)}
1263
+ self.backend.set(storage_key, json.dumps(meta))
1264
+
1265
+ is_storage_list = isinstance(list_obj, StorageList)
1266
+
1267
+ if is_storage_list:
1268
+ indices_to_write = list_obj.dirty_indices
1269
+ else:
1270
+ # Full rewrite
1271
+ self._delete_list_entries(storage_key)
1272
+ indices_to_write = range(len(list_obj.elements))
1273
+
1274
+ for i in indices_to_write:
1275
+ if i < len(list_obj.elements):
1276
+ val = list_obj.elements[i]
1277
+ entry_payload = json.dumps(self._serialize_val_recursive(val))
1278
+ entry_key = self._list_entry_key(storage_key, i)
1279
+ self.backend.set(entry_key, entry_payload)
1280
+
1281
+ if is_storage_list:
1282
+ list_obj.mark_clean()
1283
+
1284
+ def _delete_list_entries(self, storage_key):
1285
+ for entry_key, _ in self.backend.scan(self._list_entry_prefix(storage_key)):
1286
+ self.backend.delete(entry_key)
1287
+
1105
1288
  summary = {
1106
1289
  "dirty": len(dirty_keys),
1107
1290
  "deleted": len(deleted_keys)
@@ -1112,6 +1295,19 @@ class ContractStorage:
1112
1295
  for entry_key, _ in self.backend.scan(self._map_entry_prefix(storage_key)):
1113
1296
  self.backend.delete(entry_key)
1114
1297
 
1298
+ def _key_to_str(self, key):
1299
+ """Convert a Zexus object key to a Python string for JSON serialization."""
1300
+ if key.__class__ is String:
1301
+ return key.value
1302
+ if key.__class__ is Integer:
1303
+ return str(key.value)
1304
+ if key.__class__ is Float:
1305
+ return str(key.value)
1306
+ if key.__class__ is BooleanObj:
1307
+ return str(key.value)
1308
+ # Fallback for other types
1309
+ return str(key)
1310
+
1115
1311
  def _serialize(self, obj):
1116
1312
  """Convert Zexus Object -> JSON String"""
1117
1313
  cls = obj.__class__
@@ -1134,7 +1330,8 @@ class ContractStorage:
1134
1330
  serialized_list = [self._serialize_val_recursive(e) for e in obj.elements]
1135
1331
  return json.dumps({"type": "list", "val": serialized_list})
1136
1332
  if cls is Map or cls is StorageMap:
1137
- serialized_map = {k: self._serialize_val_recursive(v) for k, v in obj.pairs.items()}
1333
+ # Convert Zexus String keys to Python strings for JSON compatibility
1334
+ serialized_map = {self._key_to_str(k): self._serialize_val_recursive(v) for k, v in obj.pairs.items()}
1138
1335
  return json.dumps({"type": "map", "val": serialized_map})
1139
1336
 
1140
1337
  if obj is NULL or obj is None:
@@ -1161,7 +1358,8 @@ class ContractStorage:
1161
1358
  if cls is List:
1162
1359
  return {"type": "list", "val": [self._serialize_val_recursive(e) for e in obj.elements]}
1163
1360
  if cls is Map or cls is StorageMap:
1164
- return {"type": "map", "val": {k: self._serialize_val_recursive(v) for k, v in obj.pairs.items()}}
1361
+ # Convert Zexus String keys to Python strings for JSON compatibility
1362
+ return {"type": "map", "val": {self._key_to_str(k): self._serialize_val_recursive(v) for k, v in obj.pairs.items()}}
1165
1363
  if obj is NULL:
1166
1364
  return {"type": "null", "val": None}
1167
1365
 
@@ -1253,6 +1451,66 @@ def lookup_contract(address):
1253
1451
  class SmartContract:
1254
1452
  """Represents a smart contract with persistent storage"""
1255
1453
 
1454
+ @staticmethod
1455
+ def _clone_storage_value(value, var_name=None):
1456
+ """Deep clone storage values to keep instances isolated."""
1457
+ from zexus.object import (
1458
+ Integer as ZInteger,
1459
+ Float as ZFloat,
1460
+ Boolean as ZBoolean,
1461
+ String as ZString,
1462
+ List as ZList,
1463
+ Map as ZMap,
1464
+ )
1465
+
1466
+ if isinstance(value, StorageList):
1467
+ target_name = var_name or getattr(value, "_var_name", "")
1468
+ cloned_elements = [SmartContract._clone_storage_value(item) for item in value.elements]
1469
+ cloned_list = StorageList(cloned_elements, target_name)
1470
+ cloned_list.mark_clean()
1471
+ return cloned_list
1472
+
1473
+ if isinstance(value, ZList):
1474
+ return ZList([SmartContract._clone_storage_value(item) for item in value.elements])
1475
+
1476
+ if isinstance(value, StorageMap):
1477
+ target_name = var_name or getattr(value, "_var_name", "")
1478
+ cloned_pairs = {}
1479
+ for key, stored_val in value.pairs.items():
1480
+ cloned_pairs[key] = SmartContract._clone_storage_value(stored_val)
1481
+ cloned_map = StorageMap(cloned_pairs, target_name)
1482
+ cloned_map.mark_clean()
1483
+ return cloned_map
1484
+
1485
+ if isinstance(value, ZMap):
1486
+ cloned_pairs = {}
1487
+ for key, stored_val in value.pairs.items():
1488
+ cloned_pairs[key] = SmartContract._clone_storage_value(stored_val)
1489
+ return ZMap(cloned_pairs)
1490
+
1491
+ if isinstance(value, ZString):
1492
+ return ZString(value.value, sanitized_for=value.sanitized_for, is_trusted=value.is_trusted)
1493
+
1494
+ if isinstance(value, ZInteger):
1495
+ return ZInteger(value.value)
1496
+
1497
+ if isinstance(value, ZFloat):
1498
+ return ZFloat(value.value)
1499
+
1500
+ if isinstance(value, ZBoolean):
1501
+ return ZBoolean(value.value)
1502
+
1503
+ if isinstance(value, list):
1504
+ return [SmartContract._clone_storage_value(item) for item in value]
1505
+
1506
+ if isinstance(value, tuple):
1507
+ return tuple(SmartContract._clone_storage_value(item) for item in value)
1508
+
1509
+ if isinstance(value, dict):
1510
+ return {key: SmartContract._clone_storage_value(val) for key, val in value.items()}
1511
+
1512
+ return value
1513
+
1256
1514
  def __init__(self, name, storage_vars, actions, blockchain_config=None, address=None):
1257
1515
  self.name = name
1258
1516
  self.storage_vars = storage_vars or []
@@ -1262,8 +1520,10 @@ class SmartContract:
1262
1520
  # Generate a unique address/ID for this specific instance if not provided
1263
1521
  self.address = address or str(uuid.uuid4())[:8]
1264
1522
 
1265
- # Default to SQLite, can be configured via blockchain_config
1266
- db_pref = (blockchain_config or {}).get("storage_engine", "sqlite")
1523
+ # Storage engine priority: blockchain_config > env var > default (memory)
1524
+ db_pref = (blockchain_config or {}).get("storage_engine")
1525
+ if db_pref is None:
1526
+ db_pref = os.environ.get("ZEXUS_STORAGE_ENGINE", "memory")
1267
1527
 
1268
1528
  # Initialize storage linked to unique address
1269
1529
  # The unique ID ensures multiple "ZiverWallet()" calls don't overwrite each other
@@ -1287,7 +1547,8 @@ class SmartContract:
1287
1547
 
1288
1548
  def instantiate(self, args=None):
1289
1549
  """Create a new instance of this contract when called like ZiverWallet()."""
1290
- print(f"📄 SmartContract.instantiate() called for: {self.name}")
1550
+ if zexus_config.should_log('debug'):
1551
+ print(f"📄 SmartContract.instantiate() called for: {self.name}")
1291
1552
 
1292
1553
  # Generate new unique address for the instance
1293
1554
  new_address = str(uuid.uuid4())[:16]
@@ -1301,7 +1562,8 @@ class SmartContract:
1301
1562
  address=new_address
1302
1563
  )
1303
1564
 
1304
- print(f" 🔗 Contract Address: {new_address}")
1565
+ if zexus_config.should_log('debug'):
1566
+ print(f" 🔗 Contract Address: {new_address}")
1305
1567
 
1306
1568
  # Copy initial storage values from the template contract
1307
1569
  # This ensures instances get the evaluated initial values
@@ -1317,13 +1579,12 @@ class SmartContract:
1317
1579
  # Get the initial value from the template contract's storage
1318
1580
  value = self.storage.get(var_name)
1319
1581
  if value is not None:
1320
- initial_storage[var_name] = value
1582
+ initial_storage[var_name] = self._clone_storage_value(value, var_name=var_name)
1321
1583
 
1322
1584
  # Deploy the instance with the copied initial values
1323
1585
  instance.deploy(evaluated_storage_values=initial_storage)
1324
1586
  instance.parent_contract = self
1325
1587
 
1326
- print(f" Available actions: {list(self.actions.keys())}")
1327
1588
  return instance
1328
1589
 
1329
1590
  def __call__(self, *args):
@@ -1343,7 +1604,8 @@ class SmartContract:
1343
1604
  if evaluated_storage_values:
1344
1605
  for var_name, value in evaluated_storage_values.items():
1345
1606
  if self.storage.get(var_name) is None:
1346
- self.storage.set(var_name, value)
1607
+ cloned_value = self._clone_storage_value(value, var_name=var_name)
1608
+ self.storage.set(var_name, cloned_value)
1347
1609
  else:
1348
1610
  # Fallback: Initialize storage with NULL for declared variables
1349
1611
  for var_node in self.storage_vars:
@@ -1366,24 +1628,50 @@ class SmartContract:
1366
1628
  from zexus.object import EvaluationError
1367
1629
  return EvaluationError(f"Action '{action_name}' not found in contract {self.name}")
1368
1630
 
1631
+ trace_calls = os.environ.get("ZEXUS_VM_TRACE_CALLS")
1632
+ if trace_calls:
1633
+ try:
1634
+ interval = int(trace_calls) if trace_calls.isdigit() else 1000
1635
+ except Exception:
1636
+ interval = 1000
1637
+ count = getattr(self, "_trace_call_count", 0) + 1
1638
+ self._trace_call_count = count
1639
+ if interval > 0 and count % interval == 0:
1640
+ print(f"[VM TRACE] CONTRACT action={action_name} total={count}")
1641
+
1369
1642
  # Get the action (Action object)
1370
1643
  action = self.actions[action_name]
1371
1644
 
1372
- # Create a new environment for the action execution
1645
+ # FAST PATH: Cache environments per action for reuse (big perf win)
1646
+ if not hasattr(self, '_action_env_cache'):
1647
+ self._action_env_cache = {}
1648
+
1373
1649
  from zexus.environment import Environment
1374
- action_env = Environment(outer=action.env if hasattr(action, 'env') else None)
1650
+ cached_env = self._action_env_cache.get(action_name)
1651
+ if cached_env is not None:
1652
+ action_env = cached_env
1653
+ # Clear only local store, keep outer linkage intact
1654
+ action_env.store.clear()
1655
+ else:
1656
+ action_env = Environment(outer=action.env if hasattr(action, 'env') else None)
1657
+ self._action_env_cache[action_name] = action_env
1658
+
1375
1659
 
1376
1660
  # Bind 'this' to the current contract instance in the action environment
1377
1661
  action_env.set('this', self)
1378
1662
 
1379
- # Add msg.sender context - default to contract deployer if not in transaction context
1380
- # In a real blockchain, this would be the transaction sender's address
1663
+ # FAST PATH: Reuse msg object
1381
1664
  msg_sender = getattr(self, '_current_sender', self.deployer if hasattr(self, 'deployer') else "0x0000000000000000")
1665
+ cached_msg = getattr(self, '_cached_msg_obj', None)
1382
1666
  from zexus.object import String as ZexusString, Map as ZexusMap
1383
- # msg is a Map with sender property for better compatibility
1384
- msg_obj = ZexusMap({
1385
- ZexusString("sender"): ZexusString(msg_sender)
1386
- })
1667
+ if cached_msg is not None and getattr(self, '_cached_msg_sender', None) == msg_sender:
1668
+ msg_obj = cached_msg
1669
+ else:
1670
+ msg_obj = ZexusMap({
1671
+ ZexusString("sender"): ZexusString(msg_sender)
1672
+ })
1673
+ self._cached_msg_obj = msg_obj
1674
+ self._cached_msg_sender = msg_sender
1387
1675
  action_env.set('msg', msg_obj)
1388
1676
 
1389
1677
  # Make contract storage accessible in the action environment
@@ -1401,6 +1689,9 @@ class SmartContract:
1401
1689
  stored_value = self.storage.get(var_name)
1402
1690
  if stored_value is not None:
1403
1691
  action_env.set(var_name, stored_value)
1692
+ else:
1693
+ # Ensure state variables always exist in the action env
1694
+ action_env.set(var_name, Null)
1404
1695
 
1405
1696
  # Bind action parameters to arguments
1406
1697
  if hasattr(action, 'parameters'):
@@ -1421,16 +1712,105 @@ class SmartContract:
1421
1712
  from zexus.object import Null
1422
1713
  action_env.set(param_name, Null)
1423
1714
 
1424
- # Execute the action body
1425
- from zexus.evaluator.core import Evaluator
1426
- evaluator = Evaluator()
1715
+ # Execute the action body - use cached evaluator for performance
1716
+ evaluator = _get_cached_evaluator()
1717
+ disable_vm = _get_vm_action_context()
1718
+ saved_use_vm = None
1719
+ saved_vm_enabled = None
1720
+ if disable_vm:
1721
+ saved_use_vm = evaluator.use_vm
1722
+ evaluator.use_vm = False
1723
+ if evaluator.unified_executor is not None:
1724
+ saved_vm_enabled = evaluator.unified_executor.vm_enabled
1725
+ evaluator.unified_executor.vm_enabled = False
1726
+
1727
+ # Optional: VM cached action execution for performance mode
1728
+ vm_result = None
1729
+ use_vm_actions = False
1730
+ try:
1731
+ if evaluator.unified_executor and evaluator.unified_executor.vm_enabled:
1732
+ if evaluator.unified_executor.vm_config.get("vm_action_cache", False):
1733
+ use_vm_actions = True
1734
+ else:
1735
+ perf_mode_flag = action_env.get("performance_mode")
1736
+ perf_mode = getattr(perf_mode_flag, "value", perf_mode_flag)
1737
+ config_obj = action_env.get("config")
1738
+ perf_use_vm_actions = None
1739
+ if isinstance(config_obj, Map):
1740
+ key = String("perf_use_vm_actions")
1741
+ if key in config_obj.pairs:
1742
+ perf_use_vm_actions = config_obj.pairs.get(key)
1743
+ elif "perf_use_vm_actions" in config_obj.pairs:
1744
+ perf_use_vm_actions = config_obj.pairs.get("perf_use_vm_actions")
1745
+ if isinstance(perf_use_vm_actions, BooleanObj):
1746
+ perf_use_vm_actions = perf_use_vm_actions.value
1747
+ if perf_use_vm_actions is True and perf_mode is True:
1748
+ use_vm_actions = True
1749
+ except Exception:
1750
+ use_vm_actions = False
1751
+
1752
+ if disable_vm:
1753
+ use_vm_actions = False
1427
1754
 
1428
1755
  # Start batching storage writes for performance
1429
1756
  self.storage.begin_batch()
1430
1757
  self.storage.enable_action_cache()
1431
1758
 
1432
1759
  try:
1433
- result = evaluator.eval_node(action.body, action_env, stack_trace=[])
1760
+ if use_vm_actions:
1761
+ try:
1762
+ from zexus.evaluator.bytecode_compiler import EvaluatorBytecodeCompiler, should_use_vm_for_node
1763
+ from zexus.evaluator.utils import is_error
1764
+
1765
+ if should_use_vm_for_node(action.body):
1766
+ cache = getattr(self, "_vm_action_cache", None)
1767
+ if cache is None:
1768
+ cache = {}
1769
+ self._vm_action_cache = cache
1770
+
1771
+ bytecode = cache.get(action_name)
1772
+ if bytecode is None:
1773
+ compiler = EvaluatorBytecodeCompiler(use_cache=True)
1774
+ bytecode = compiler.compile(action.body, optimize=True)
1775
+ if bytecode and not compiler.errors:
1776
+ cache[action_name] = bytecode
1777
+ sync_cache = getattr(self, "_vm_action_sync_keys", None)
1778
+ if sync_cache is None:
1779
+ sync_cache = {}
1780
+ self._vm_action_sync_keys = sync_cache
1781
+ try:
1782
+ sync_cache[action_name] = evaluator.unified_executor._collect_assigned_names(action.body)
1783
+ except Exception:
1784
+ sync_cache[action_name] = None
1785
+
1786
+ if bytecode is not None:
1787
+ instr_count = 0
1788
+ try:
1789
+ instr_count = len(getattr(bytecode, "instructions", []) or [])
1790
+ except Exception:
1791
+ instr_count = 0
1792
+ min_instr = 32
1793
+ try:
1794
+ min_instr = int(evaluator.unified_executor.vm_config.get("vm_action_min_instructions", 32))
1795
+ except Exception:
1796
+ min_instr = 32
1797
+
1798
+ if instr_count >= min_instr:
1799
+ sync_keys = None
1800
+ try:
1801
+ sync_keys = self._vm_action_sync_keys.get(action_name)
1802
+ except Exception:
1803
+ sync_keys = None
1804
+ vm_result = evaluator.unified_executor.execute_action_bytecode(bytecode, action_env, sync_keys=sync_keys)
1805
+ if is_error(vm_result):
1806
+ vm_result = None
1807
+ except Exception:
1808
+ vm_result = None
1809
+
1810
+ if vm_result is not None:
1811
+ result = vm_result
1812
+ else:
1813
+ result = evaluator.eval_node(action.body, action_env, stack_trace=[])
1434
1814
 
1435
1815
  # Save any modified state variables back to storage
1436
1816
  # SKIP variables that were set via this.property (direct storage updates)
@@ -1450,6 +1830,13 @@ class SmartContract:
1450
1830
  continue
1451
1831
 
1452
1832
  current_value = action_env.get(var_name)
1833
+ if var_name == 'chain' and zexus_config.should_log('debug'):
1834
+ size = None
1835
+ try:
1836
+ size = len(current_value.elements)
1837
+ except Exception:
1838
+ size = 'n/a'
1839
+ print(f"DEBUG storage sync chain -> {current_value} (len={size})")
1453
1840
  if current_value is not None:
1454
1841
  self.storage.set(var_name, current_value)
1455
1842
 
@@ -1467,6 +1854,11 @@ class SmartContract:
1467
1854
  finally:
1468
1855
  self.storage.disable_action_cache()
1469
1856
 
1857
+ if disable_vm:
1858
+ evaluator.use_vm = saved_use_vm
1859
+ if evaluator.unified_executor is not None and saved_vm_enabled is not None:
1860
+ evaluator.unified_executor.vm_enabled = saved_vm_enabled
1861
+
1470
1862
 
1471
1863
  return result
1472
1864
 
@@ -1502,12 +1894,10 @@ class SmartContract:
1502
1894
  attr = getattr(self, property_name)
1503
1895
  # Wrap primitive Python types
1504
1896
  if isinstance(attr, str):
1505
- from ..object import String
1506
1897
  return String(attr)
1507
1898
  return attr
1508
1899
 
1509
1900
  # Return NULL if not found
1510
- from ..object import NULL
1511
1901
  return NULL
1512
1902
 
1513
1903
  def set(self, property_name, value):