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,7 +13,7 @@ from .utils import is_error, debug_log, NULL, TRUE, FALSE, _resolve_awaitable, _
13
13
 
14
14
  # Try to import backend, handle failure gracefully (as per your original code)
15
15
  try:
16
- from renderer import backend as _BACKEND
16
+ from ..renderer import backend as _BACKEND
17
17
  _BACKEND_AVAILABLE = True
18
18
  except Exception:
19
19
  _BACKEND_AVAILABLE = False
@@ -25,6 +25,9 @@ class FunctionEvaluatorMixin:
25
25
  def __init__(self):
26
26
  # Initialize registries
27
27
  self.builtins = {}
28
+ self._allow_coroutine_result = False
29
+ self._pending_revert_signature = None
30
+ self._tolerant_skip_counts = {}
28
31
 
29
32
  # Renderer Registry (moved from global scope to instance scope)
30
33
  self.render_registry = {
@@ -32,6 +35,11 @@ class FunctionEvaluatorMixin:
32
35
  'components': {},
33
36
  'themes': {},
34
37
  'canvases': {},
38
+ 'canvas_aliases': {},
39
+ 'colours': {},
40
+ 'graphics': {},
41
+ 'animations': {},
42
+ 'clocks': {},
35
43
  'current_theme': None
36
44
  }
37
45
 
@@ -40,9 +48,60 @@ class FunctionEvaluatorMixin:
40
48
  self._register_main_entry_point_builtins()
41
49
  self._register_renderer_builtins()
42
50
 
51
+ def _execute_coroutine_to_completion(self, coroutine):
52
+ from ..object import EvaluationError
53
+
54
+ max_steps = 10000
55
+ pending_value = None
56
+
57
+ for _ in range(max_steps):
58
+ done, value = coroutine.resume(pending_value)
59
+ if done:
60
+ if isinstance(value, EvaluationError):
61
+ return value
62
+ return value if value is not None else coroutine.result
63
+ pending_value = None
64
+
65
+ return EvaluationError("Coroutine did not complete within step limit")
66
+
67
+ def _compute_revert_signature(self, reason_node):
68
+ if reason_node is None:
69
+ return ("none",)
70
+
71
+ try:
72
+ from .. import zexus_ast
73
+ if isinstance(reason_node, zexus_ast.StringLiteral):
74
+ return ("string", getattr(reason_node, "value", None))
75
+ if isinstance(reason_node, zexus_ast.Identifier):
76
+ return ("identifier", getattr(reason_node, "value", None))
77
+ except Exception:
78
+ pass
79
+
80
+ return ("expr", repr(reason_node))
81
+
43
82
  def eval_call_expression(self, node, env, stack_trace):
44
83
  debug_log("🚀 CallExpression node", f"Calling {node.function}")
45
84
 
85
+ if (
86
+ isinstance(node.function, zexus_ast.Identifier)
87
+ and getattr(node.function, "value", None) == "revert"
88
+ ):
89
+ if len(node.arguments) > 1:
90
+ return EvaluationError(
91
+ "revert() accepts at most one argument",
92
+ stack_trace=stack_trace,
93
+ )
94
+
95
+ debug_log(
96
+ "eval_call_expression",
97
+ "Treating call expression as revert statement",
98
+ )
99
+
100
+ reason_expr = node.arguments[0] if node.arguments else None
101
+ result = self._perform_revert(reason_expr, env, stack_trace)
102
+ self._pending_revert_signature = self._compute_revert_signature(reason_expr)
103
+ return result
104
+
46
105
  fn = self.eval_node(node.function, env, stack_trace)
47
106
  if is_error(fn):
48
107
  return fn
@@ -66,7 +125,6 @@ class FunctionEvaluatorMixin:
66
125
 
67
126
  # Check if arguments contain keyword arguments (AssignmentExpression nodes)
68
127
  # This handles syntax like: Person(name="Bob", age=25)
69
- from .. import zexus_ast
70
128
  has_keyword_args = any(isinstance(arg, zexus_ast.AssignmentExpression) for arg in node.arguments)
71
129
 
72
130
  if has_keyword_args:
@@ -106,7 +164,20 @@ class FunctionEvaluatorMixin:
106
164
  if isinstance(fn, SmartContract):
107
165
  return fn.instantiate(args)
108
166
 
109
- return self.apply_function(fn, args, env)
167
+ should_allow_coroutine = (
168
+ isinstance(fn, (Action, LambdaFunction))
169
+ and getattr(fn, "is_async", False)
170
+ )
171
+
172
+ previous_allow = getattr(self, "_allow_coroutine_result", False)
173
+ if should_allow_coroutine:
174
+ self._allow_coroutine_result = True
175
+
176
+ try:
177
+ return self.apply_function(fn, args, env)
178
+ finally:
179
+ if should_allow_coroutine:
180
+ self._allow_coroutine_result = previous_allow
110
181
 
111
182
  def _create_specialized_generic_constructor(self, template, type_args, env, stack_trace):
112
183
  """Create a specialized constructor for a generic type with concrete type arguments
@@ -114,7 +185,6 @@ class FunctionEvaluatorMixin:
114
185
  Example: Box<number> creates a specialized Box constructor with T = number
115
186
  """
116
187
  from ..object import EvaluationError, String, Map
117
- from .. import zexus_ast
118
188
 
119
189
  debug_log("_create_specialized_generic_constructor", f"Specializing with types: {type_args}")
120
190
 
@@ -268,10 +338,12 @@ class FunctionEvaluatorMixin:
268
338
  # Re-raise exception to be caught by coroutine
269
339
  raise e
270
340
 
271
- # Create and return coroutine
341
+ # Create coroutine and decide how to surface result
272
342
  gen = async_generator()
273
343
  coroutine = Coroutine(gen, fn)
274
- return coroutine
344
+ if getattr(self, "_allow_coroutine_result", False):
345
+ return coroutine
346
+ return self._execute_coroutine_to_completion(coroutine)
275
347
 
276
348
  # Synchronous function execution
277
349
  new_env = Environment(outer=fn.env)
@@ -295,6 +367,7 @@ class FunctionEvaluatorMixin:
295
367
  except Exception:
296
368
  pass
297
369
 
370
+ result = None
298
371
  try:
299
372
  res = self.eval_node(fn.body, new_env)
300
373
  res = _resolve_awaitable(res)
@@ -310,6 +383,10 @@ class FunctionEvaluatorMixin:
310
383
  # Store result for after-call hook
311
384
  result = EvaluationError(str(e))
312
385
  raise
386
+ except BaseException as e:
387
+ # Ensure result is set even for interrupts/SystemExit
388
+ result = EvaluationError(str(e))
389
+ raise
313
390
  finally:
314
391
  # CRITICAL: Execute deferred cleanup when function exits
315
392
  # This happens in finally block to ensure cleanup runs even on errors
@@ -429,7 +506,9 @@ class FunctionEvaluatorMixin:
429
506
  def eval_method_call_expression(self, node, env, stack_trace):
430
507
  debug_log(" MethodCallExpression node", f"{node.object}.{node.method}")
431
508
 
509
+ debug_log("DEBUG evaluating method call object", node.object)
432
510
  obj = self.eval_node(node.object, env, stack_trace)
511
+ debug_log("DEBUG object evaluated to", obj)
433
512
  if is_error(obj):
434
513
  return obj
435
514
 
@@ -588,6 +667,32 @@ class FunctionEvaluatorMixin:
588
667
  if is_error(args):
589
668
  return args
590
669
  result = obj.call_method(method_name, args)
670
+
671
+ # CRITICAL: Sync state variables back to caller's environment after internal call
672
+ # This ensures that when action A calls this.actionB(), any state changes made
673
+ # by actionB are visible to actionA's local environment
674
+ # OPTIMIZATION: Only sync for 'this' calls (internal calls within same contract)
675
+ from ..security import SmartContract
676
+ if isinstance(obj, SmartContract):
677
+ # Check if this is a 'this.method()' call by checking the caller's env
678
+ this_ref = env.get('this')
679
+ if this_ref is obj and hasattr(obj, 'storage_vars'):
680
+ # This is an internal call - sync state variables
681
+ for var_node in obj.storage_vars:
682
+ var_name = None
683
+ if hasattr(var_node, 'name'):
684
+ var_name = var_node.name.value if hasattr(var_node.name, 'value') else var_node.name
685
+ elif isinstance(var_node, dict):
686
+ var_name = var_node.get("name")
687
+ elif isinstance(var_node, str):
688
+ var_name = var_node
689
+
690
+ if var_name:
691
+ # Read the updated value from storage and refresh the caller's env
692
+ updated_value = obj.storage.get(var_name)
693
+ if updated_value is not None:
694
+ env.set(var_name, updated_value)
695
+
591
696
  # Unwrap ReturnValue if needed
592
697
  from ..object import ReturnValue
593
698
  if isinstance(result, ReturnValue):
@@ -618,6 +723,7 @@ class FunctionEvaluatorMixin:
618
723
  return self.apply_function(method_value, args, env)
619
724
 
620
725
  obj_type = obj.type() if hasattr(obj, 'type') and callable(obj.type) else type(obj).__name__
726
+ debug_log("DEBUG method dispatch failure", f"method={method_name}, obj={obj}, obj_type={obj_type}")
621
727
  return EvaluationError(f"Method '{method_name}' not supported for {obj_type}")
622
728
 
623
729
  # --- Array Helpers (Internal) ---
@@ -826,16 +932,56 @@ class FunctionEvaluatorMixin:
826
932
  except Exception as e:
827
933
  return EvaluationError(f"constant_time_compare() error: {str(e)}")
828
934
 
829
- # File I/O
935
+ # File I/O — VFS-aware helpers
936
+ # The VFS manager (with its file cache) is obtained lazily so the
937
+ # evaluator can function even when the integration layer is not loaded.
938
+ _vfs_mgr = None
939
+ def _get_vfs_manager():
940
+ nonlocal _vfs_mgr
941
+ if _vfs_mgr is None:
942
+ try:
943
+ from .integration import get_integration
944
+ _vfs_mgr = get_integration().vfs_manager
945
+ except Exception:
946
+ pass
947
+ return _vfs_mgr
948
+
949
+ def _resolve_read_path(path_str):
950
+ """Resolve a path for reading – uses VFS cache when available."""
951
+ import os
952
+ if not os.path.isabs(path_str):
953
+ path_str = os.path.join(os.getcwd(), path_str)
954
+ return os.path.normpath(path_str)
955
+
956
+ def _cached_read(real_path):
957
+ """Read via VFS cache (skips disk if file unchanged)."""
958
+ mgr = _get_vfs_manager()
959
+ if mgr is not None:
960
+ return mgr.cached_read(real_path)
961
+ with open(real_path, 'r') as f:
962
+ return f.read()
963
+
964
+ def _invalidate_file_cache(real_path):
965
+ """Invalidate VFS cache after a write."""
966
+ mgr = _get_vfs_manager()
967
+ if mgr is not None:
968
+ mgr.invalidate_cache(real_path)
969
+
830
970
  def _read_text(*a):
971
+ cap_err = _check_io_read_capability()
972
+ if cap_err: return cap_err
831
973
  if len(a) != 1 or not isinstance(a[0], String):
832
974
  return EvaluationError("file_read_text() takes exactly 1 string argument")
833
975
  return File.read_text(a[0])
834
976
 
835
977
  def _write_text(*a):
978
+ cap_err = _check_io_write_capability()
979
+ if cap_err: return cap_err
836
980
  if len(a) != 2 or not all(isinstance(x, String) for x in a):
837
981
  return EvaluationError("file_write_text() takes exactly 2 string arguments")
838
- return File.write_text(a[0], a[1])
982
+ result = File.write_text(a[0], a[1])
983
+ _invalidate_file_cache(_resolve_read_path(a[0].value))
984
+ return result
839
985
 
840
986
  def _exists(*a):
841
987
  if len(a) != 1 or not isinstance(a[0], String):
@@ -843,26 +989,38 @@ class FunctionEvaluatorMixin:
843
989
  return File.exists(a[0])
844
990
 
845
991
  def _read_json(*a):
992
+ cap_err = _check_io_read_capability()
993
+ if cap_err: return cap_err
846
994
  if len(a) != 1 or not isinstance(a[0], String):
847
995
  return EvaluationError("file_read_json() takes exactly 1 string argument")
848
996
  return File.read_json(a[0])
849
997
 
850
998
  def _write_json(*a):
999
+ cap_err = _check_io_write_capability()
1000
+ if cap_err: return cap_err
851
1001
  if len(a) != 2 or not isinstance(a[0], String):
852
1002
  return EvaluationError("file_write_json() takes path string and data")
853
- return File.write_json(a[0], a[1])
1003
+ result = File.write_json(a[0], a[1])
1004
+ _invalidate_file_cache(_resolve_read_path(a[0].value))
1005
+ return result
854
1006
 
855
1007
  def _file_append(*a):
1008
+ cap_err = _check_io_write_capability()
1009
+ if cap_err: return cap_err
856
1010
  if len(a) != 2 or not all(isinstance(x, String) for x in a):
857
1011
  return EvaluationError("file_append() takes exactly 2 string arguments")
858
- return File.append_text(a[0], a[1])
1012
+ result = File.append_text(a[0], a[1])
1013
+ _invalidate_file_cache(_resolve_read_path(a[0].value))
1014
+ return result
859
1015
 
860
1016
  def _list_dir(*a):
1017
+ cap_err = _check_io_read_capability()
1018
+ if cap_err: return cap_err
861
1019
  if len(a) != 1 or not isinstance(a[0], String):
862
1020
  return EvaluationError("file_list_dir() takes exactly 1 string argument")
863
1021
  return File.list_directory(a[0])
864
1022
 
865
- # Extended File System Operations
1023
+ # Extended File System Operations (with capability checks)
866
1024
  def _fs_is_file(*a):
867
1025
  if len(a) != 1 or not isinstance(a[0], String):
868
1026
  return EvaluationError("fs_is_file() takes exactly 1 string argument")
@@ -876,6 +1034,8 @@ class FunctionEvaluatorMixin:
876
1034
  return BooleanObj(os.path.isdir(a[0].value))
877
1035
 
878
1036
  def _fs_mkdir(*a):
1037
+ cap_err = _check_io_write_capability()
1038
+ if cap_err: return cap_err
879
1039
  if len(a) < 1 or not isinstance(a[0], String):
880
1040
  return EvaluationError("fs_mkdir() takes path string and optional parents boolean")
881
1041
  from pathlib import Path
@@ -889,16 +1049,21 @@ class FunctionEvaluatorMixin:
889
1049
  return EvaluationError(f"fs_mkdir() error: {str(e)}")
890
1050
 
891
1051
  def _fs_remove(*a):
1052
+ cap_err = _check_io_write_capability()
1053
+ if cap_err: return cap_err
892
1054
  if len(a) != 1 or not isinstance(a[0], String):
893
1055
  return EvaluationError("fs_remove() takes exactly 1 string argument")
894
1056
  import os
895
1057
  try:
896
1058
  os.remove(a[0].value)
1059
+ _invalidate_file_cache(_resolve_read_path(a[0].value))
897
1060
  return BooleanObj(True)
898
1061
  except Exception as e:
899
1062
  return EvaluationError(f"fs_remove() error: {str(e)}")
900
1063
 
901
1064
  def _fs_rmdir(*a):
1065
+ cap_err = _check_io_write_capability()
1066
+ if cap_err: return cap_err
902
1067
  if len(a) < 1 or not isinstance(a[0], String):
903
1068
  return EvaluationError("fs_rmdir() takes path string and optional recursive boolean")
904
1069
  import os
@@ -916,6 +1081,8 @@ class FunctionEvaluatorMixin:
916
1081
  return EvaluationError(f"fs_rmdir() error: {str(e)}")
917
1082
 
918
1083
  def _fs_rename(*a):
1084
+ cap_err = _check_io_write_capability()
1085
+ if cap_err: return cap_err
919
1086
  if len(a) != 2 or not all(isinstance(x, String) for x in a):
920
1087
  return EvaluationError("fs_rename() takes exactly 2 string arguments: old_path, new_path")
921
1088
  import os
@@ -926,6 +1093,8 @@ class FunctionEvaluatorMixin:
926
1093
  return EvaluationError(f"fs_rename() error: {str(e)}")
927
1094
 
928
1095
  def _fs_copy(*a):
1096
+ cap_err = _check_io_write_capability()
1097
+ if cap_err: return cap_err
929
1098
  if len(a) != 2 or not all(isinstance(x, String) for x in a):
930
1099
  return EvaluationError("fs_copy() takes exactly 2 string arguments: src, dst")
931
1100
  import shutil
@@ -946,6 +1115,8 @@ class FunctionEvaluatorMixin:
946
1115
  # Socket/TCP Primitives
947
1116
  def _socket_create_server(*a):
948
1117
  """Create TCP server: socket_create_server(host, port, handler, backlog?)"""
1118
+ cap_err = _check_network_capability()
1119
+ if cap_err: return cap_err
949
1120
  if len(a) < 3:
950
1121
  return EvaluationError("socket_create_server() requires at least 3 arguments: host, port, handler")
951
1122
 
@@ -1035,6 +1206,8 @@ class FunctionEvaluatorMixin:
1035
1206
 
1036
1207
  def _socket_create_connection(*a):
1037
1208
  """Create TCP client: socket_create_connection(host, port, timeout?)"""
1209
+ cap_err = _check_network_capability()
1210
+ if cap_err: return cap_err
1038
1211
  if len(a) < 2:
1039
1212
  return EvaluationError("socket_create_connection() requires at least 2 arguments: host, port")
1040
1213
 
@@ -1685,9 +1858,42 @@ class FunctionEvaluatorMixin:
1685
1858
  except Exception as e:
1686
1859
  return EvaluationError(f"mongo_connect() error: {str(e)}")
1687
1860
 
1861
+ # Capability-checked helpers
1862
+ def _check_network_capability():
1863
+ """Check if network operations are allowed in current context."""
1864
+ try:
1865
+ from .integration import CapabilityChecker
1866
+ if not CapabilityChecker.check_network():
1867
+ return EvaluationError("Network access denied: missing 'network.tcp' capability")
1868
+ except Exception:
1869
+ pass # If capability system isn't loaded, allow by default
1870
+ return None
1871
+
1872
+ def _check_io_read_capability():
1873
+ """Check if file read operations are allowed."""
1874
+ try:
1875
+ from .integration import CapabilityChecker
1876
+ if not CapabilityChecker.check_io_read():
1877
+ return EvaluationError("File read access denied: missing 'io.read' capability")
1878
+ except Exception:
1879
+ pass
1880
+ return None
1881
+
1882
+ def _check_io_write_capability():
1883
+ """Check if file write operations are allowed."""
1884
+ try:
1885
+ from .integration import CapabilityChecker
1886
+ if not CapabilityChecker.check_io_write():
1887
+ return EvaluationError("File write access denied: missing 'io.write' capability")
1888
+ except Exception:
1889
+ pass
1890
+ return None
1891
+
1688
1892
  # HTTP Client
1689
1893
  def _http_get(*a):
1690
1894
  """HTTP GET request: http_get(url, headers?, timeout?)"""
1895
+ cap_err = _check_network_capability()
1896
+ if cap_err: return cap_err
1691
1897
  if len(a) < 1:
1692
1898
  return EvaluationError("http_get() requires at least 1 argument: url")
1693
1899
 
@@ -1713,6 +1919,8 @@ class FunctionEvaluatorMixin:
1713
1919
 
1714
1920
  def _http_post(*a):
1715
1921
  """HTTP POST request: http_post(url, data, headers?, timeout?)"""
1922
+ cap_err = _check_network_capability()
1923
+ if cap_err: return cap_err
1716
1924
  if len(a) < 2:
1717
1925
  return EvaluationError("http_post() requires at least 2 arguments: url, data")
1718
1926
 
@@ -1741,6 +1949,8 @@ class FunctionEvaluatorMixin:
1741
1949
 
1742
1950
  def _http_put(*a):
1743
1951
  """HTTP PUT request: http_put(url, data, headers?, timeout?)"""
1952
+ cap_err = _check_network_capability()
1953
+ if cap_err: return cap_err
1744
1954
  if len(a) < 2:
1745
1955
  return EvaluationError("http_put() requires at least 2 arguments: url, data")
1746
1956
 
@@ -1766,6 +1976,8 @@ class FunctionEvaluatorMixin:
1766
1976
 
1767
1977
  def _http_delete(*a):
1768
1978
  """HTTP DELETE request: http_delete(url, headers?, timeout?)"""
1979
+ cap_err = _check_network_capability()
1980
+ if cap_err: return cap_err
1769
1981
  if len(a) < 1:
1770
1982
  return EvaluationError("http_delete() requires at least 1 argument: url")
1771
1983
 
@@ -1786,6 +1998,62 @@ class FunctionEvaluatorMixin:
1786
1998
  return _python_to_zexus(result, mark_untrusted=True)
1787
1999
  except Exception as e:
1788
2000
  return EvaluationError(f"HTTP DELETE error: {str(e)}")
2001
+
2002
+ def _http_request(*a):
2003
+ """Generic HTTP request: http_request(method, url, data?, headers?, timeout?)"""
2004
+ cap_err = _check_network_capability()
2005
+ if cap_err: return cap_err
2006
+ if len(a) < 2:
2007
+ return EvaluationError("http_request() requires at least 2 arguments: method, url")
2008
+ method_str = a[0].value if isinstance(a[0], String) else str(a[0])
2009
+ url = a[1].value if isinstance(a[1], String) else str(a[1])
2010
+ data = _zexus_to_python(a[2]) if len(a) >= 3 and a[2] != NULL else None
2011
+ headers = _zexus_to_python(a[3]) if len(a) >= 4 and isinstance(a[3], Map) else None
2012
+ timeout = a[4].value if len(a) >= 5 and isinstance(a[4], Integer) else 30
2013
+ try:
2014
+ from ..stdlib.http import HttpModule
2015
+ result = HttpModule.request(method_str, url, data, headers, timeout)
2016
+ return _python_to_zexus(result, mark_untrusted=True)
2017
+ except Exception as e:
2018
+ return EvaluationError(f"HTTP {method_str} error: {str(e)}")
2019
+
2020
+ def _http_parallel_get(*a):
2021
+ """Parallel GET requests: http_parallel_get([url1, url2, ...], headers?, timeout?)"""
2022
+ cap_err = _check_network_capability()
2023
+ if cap_err: return cap_err
2024
+ if len(a) < 1 or not isinstance(a[0], List):
2025
+ return EvaluationError("http_parallel_get() requires a list of URLs as first argument")
2026
+ urls = [e.value if isinstance(e, String) else str(e) for e in a[0].elements]
2027
+ headers = _zexus_to_python(a[1]) if len(a) >= 2 and isinstance(a[1], Map) else None
2028
+ timeout = a[2].value if len(a) >= 3 and isinstance(a[2], Integer) else 30
2029
+ try:
2030
+ from ..stdlib.http import HttpModule
2031
+ results = HttpModule.parallel_get(urls, headers, timeout)
2032
+ return List([_python_to_zexus(r, mark_untrusted=True) for r in results])
2033
+ except Exception as e:
2034
+ return EvaluationError(f"http_parallel_get() error: {str(e)}")
2035
+
2036
+ def _http_async_get(*a):
2037
+ """Non-blocking HTTP GET: http_async_get(url, headers?, timeout?) -> Future"""
2038
+ cap_err = _check_network_capability()
2039
+ if cap_err: return cap_err
2040
+ if len(a) < 1:
2041
+ return EvaluationError("http_async_get() requires at least 1 argument: url")
2042
+ url = a[0].value if isinstance(a[0], String) else str(a[0])
2043
+ headers = _zexus_to_python(a[1]) if len(a) >= 2 and isinstance(a[1], Map) else None
2044
+ timeout = a[2].value if len(a) >= 3 and isinstance(a[2], Integer) else 30
2045
+ try:
2046
+ from ..stdlib.http import HttpModule
2047
+ future = HttpModule.async_get(url, headers, timeout)
2048
+ # Wrap future so await_result() works from Zexus
2049
+ from ..object import Map as ZMap
2050
+ return ZMap({
2051
+ "type": String("HttpFuture"),
2052
+ "done": Builtin(lambda *_: BooleanObj(future.done()), "done"),
2053
+ "result": Builtin(lambda *_: _python_to_zexus(future.result(), mark_untrusted=True), "result"),
2054
+ })
2055
+ except Exception as e:
2056
+ return EvaluationError(f"http_async_get() error: {str(e)}")
1789
2057
 
1790
2058
  # Debug
1791
2059
  def _debug(*a):
@@ -1898,6 +2166,22 @@ class FunctionEvaluatorMixin:
1898
2166
  if isinstance(arg, String):
1899
2167
  return String(arg.value.lower())
1900
2168
  return EvaluationError(f"lowercase() requires a string argument")
2169
+
2170
+ def _split(*a):
2171
+ """Split string by delimiter"""
2172
+ if len(a) != 2:
2173
+ return EvaluationError(f"split() takes 2 args: string, delimiter")
2174
+
2175
+ str_obj = a[0]
2176
+ delim_obj = a[1]
2177
+
2178
+ if not isinstance(str_obj, String):
2179
+ return EvaluationError("split() first argument must be a string")
2180
+ if not isinstance(delim_obj, String):
2181
+ return EvaluationError("split() second argument must be a delimiter string")
2182
+
2183
+ parts = str_obj.value.split(delim_obj.value)
2184
+ return List([String(p) for p in parts])
1901
2185
 
1902
2186
  def _random(*a):
1903
2187
  """Generate random number. random() -> 0-1, random(max) -> 0 to max-1"""
@@ -2099,6 +2383,106 @@ class FunctionEvaluatorMixin:
2099
2383
  a[0].extend(a[1])
2100
2384
  return a[0]
2101
2385
 
2386
+ def _sort(*a):
2387
+ """Sort a list: sort(list) or sort(list, key_field) for maps
2388
+
2389
+ - sort([3, 1, 2]) -> [1, 2, 3]
2390
+ - sort([{fee: 5}, {fee: 3}], "fee") -> [{fee: 3}, {fee: 5}]
2391
+ - sort(list, "fee", true) -> descending order
2392
+ """
2393
+ if len(a) < 1:
2394
+ return EvaluationError("sort() takes 1-3 arguments: sort(list, [key], [descending])")
2395
+ if not isinstance(a[0], List):
2396
+ return EvaluationError("sort() first argument must be a list")
2397
+
2398
+ lst = a[0]
2399
+ key_field = None
2400
+ descending = False
2401
+
2402
+ if len(a) >= 2:
2403
+ if isinstance(a[1], String):
2404
+ key_field = a[1].value
2405
+ elif isinstance(a[1], BooleanObj):
2406
+ descending = a[1].value
2407
+ else:
2408
+ return EvaluationError("sort() second argument must be a key string or boolean for descending")
2409
+
2410
+ if len(a) >= 3:
2411
+ if isinstance(a[2], BooleanObj):
2412
+ descending = a[2].value
2413
+ else:
2414
+ return EvaluationError("sort() third argument must be a boolean for descending order")
2415
+
2416
+ try:
2417
+ # Make a copy of elements for non-destructive sort
2418
+ elements = list(lst.elements)
2419
+
2420
+ def get_sort_key(elem):
2421
+ if key_field is not None:
2422
+ # Sort by field in map
2423
+ if isinstance(elem, Map):
2424
+ # Try string key first
2425
+ val = elem.pairs.get(String(key_field))
2426
+ if val is None:
2427
+ # Try with key_field as-is (for internal dict keys)
2428
+ val = elem.pairs.get(key_field)
2429
+ if val is None:
2430
+ return 0 # Default for missing key
2431
+ if isinstance(val, (Integer, Float)):
2432
+ return val.value
2433
+ if isinstance(val, String):
2434
+ return val.value
2435
+ return 0
2436
+ elif isinstance(elem, dict):
2437
+ val = elem.get(key_field, 0)
2438
+ if hasattr(val, 'value'):
2439
+ return val.value
2440
+ return val
2441
+ return 0
2442
+ else:
2443
+ # Direct sort
2444
+ if isinstance(elem, (Integer, Float)):
2445
+ return elem.value
2446
+ if isinstance(elem, String):
2447
+ return elem.value
2448
+ return 0
2449
+
2450
+ elements.sort(key=get_sort_key, reverse=descending)
2451
+ return List(elements)
2452
+ except Exception as e:
2453
+ return EvaluationError(f"sort() error: {str(e)}")
2454
+
2455
+ def _slice(*a):
2456
+ """Get a slice of a list: slice(list, start, end?) -> list
2457
+
2458
+ - slice([1, 2, 3, 4], 1) -> [2, 3, 4] (from index 1 to end)
2459
+ - slice([1, 2, 3, 4], 1, 3) -> [2, 3] (from index 1 to 3, exclusive)
2460
+ - slice([1, 2, 3, 4], 0, 2) -> [1, 2] (first 2 elements)
2461
+ """
2462
+ if len(a) < 2:
2463
+ return EvaluationError("slice() takes 2-3 arguments: slice(list, start, [end])")
2464
+ if not isinstance(a[0], List):
2465
+ return EvaluationError("slice() first argument must be a list")
2466
+ if not isinstance(a[1], Integer):
2467
+ return EvaluationError("slice() start must be an integer")
2468
+
2469
+ lst = a[0]
2470
+ start = a[1].value
2471
+ end = len(lst.elements) # Default: to the end
2472
+
2473
+ if len(a) >= 3:
2474
+ if not isinstance(a[2], Integer):
2475
+ return EvaluationError("slice() end must be an integer")
2476
+ end = a[2].value
2477
+
2478
+ # Handle negative indices
2479
+ if start < 0:
2480
+ start = max(0, len(lst.elements) + start)
2481
+ if end < 0:
2482
+ end = max(0, len(lst.elements) + end)
2483
+
2484
+ return List(lst.elements[start:end])
2485
+
2102
2486
  def _reduce(*a):
2103
2487
  if len(a) < 2:
2104
2488
  return EvaluationError("reduce(arr, fn, [init])")
@@ -2114,6 +2498,28 @@ class FunctionEvaluatorMixin:
2114
2498
  return EvaluationError("filter(arr, fn)")
2115
2499
  return self._array_filter(a[0], a[1])
2116
2500
 
2501
+ def _vfs_stats(*a):
2502
+ """Return VFS file cache statistics as a Map: vfs_stats()"""
2503
+ mgr = _get_vfs_manager()
2504
+ if mgr is None:
2505
+ return Map({"error": String("VFS not initialized")})
2506
+ stats = mgr.file_cache.stats()
2507
+ return Map({
2508
+ "entries": Integer(stats["entries"]),
2509
+ "bytes": Integer(stats["bytes"]),
2510
+ "hits": Integer(stats["hits"]),
2511
+ "misses": Integer(stats["misses"]),
2512
+ "hit_rate": Float(round(stats["hit_rate"], 4)),
2513
+ })
2514
+
2515
+ def _vfs_clear_cache(*a):
2516
+ """Flush the VFS file content cache: vfs_clear_cache()"""
2517
+ mgr = _get_vfs_manager()
2518
+ if mgr is None:
2519
+ return NULL
2520
+ mgr.file_cache.clear()
2521
+ return NULL
2522
+
2117
2523
  # File object creation (for RAII using statements)
2118
2524
  def _file(*a):
2119
2525
  if len(a) == 0 or len(a) > 2:
@@ -2133,22 +2539,18 @@ class FunctionEvaluatorMixin:
2133
2539
  return EvaluationError(f"file() error: {str(e)}")
2134
2540
 
2135
2541
  def _read_file(*a):
2136
- """Read entire file contents as string"""
2542
+ """Read entire file contents as string (VFS-cached)"""
2543
+ cap_err = _check_io_read_capability()
2544
+ if cap_err: return cap_err
2137
2545
  if len(a) != 1:
2138
2546
  return EvaluationError("read_file() takes exactly 1 argument: path")
2139
2547
  if not isinstance(a[0], String):
2140
2548
  return EvaluationError("read_file() path must be a string")
2141
2549
 
2142
- import os
2143
- path = a[0].value
2144
-
2145
- # Normalize path
2146
- if not os.path.isabs(path):
2147
- path = os.path.join(os.getcwd(), path)
2550
+ path = _resolve_read_path(a[0].value)
2148
2551
 
2149
2552
  try:
2150
- with open(path, 'r') as f:
2151
- content = f.read()
2553
+ content = _cached_read(path)
2152
2554
  return String(content)
2153
2555
  except FileNotFoundError:
2154
2556
  return EvaluationError(f"File not found: {path}")
@@ -2414,8 +2816,13 @@ class FunctionEvaluatorMixin:
2414
2816
  "http_post": Builtin(_http_post, "http_post"),
2415
2817
  "http_put": Builtin(_http_put, "http_put"),
2416
2818
  "http_delete": Builtin(_http_delete, "http_delete"),
2819
+ "http_request": Builtin(_http_request, "http_request"),
2820
+ "http_parallel_get": Builtin(_http_parallel_get, "http_parallel_get"),
2821
+ "http_async_get": Builtin(_http_async_get, "http_async_get"),
2417
2822
  "read_file": Builtin(_read_file, "read_file"),
2418
2823
  "eval_file": Builtin(_eval_file, "eval_file"),
2824
+ "vfs_stats": Builtin(_vfs_stats, "vfs_stats"),
2825
+ "vfs_clear_cache": Builtin(_vfs_clear_cache, "vfs_clear_cache"),
2419
2826
  "debug": Builtin(_debug, "debug"),
2420
2827
  "debug_log": Builtin(_debug_log, "debug_log"),
2421
2828
  "debug_trace": Builtin(_debug_trace, "debug_trace"),
@@ -2424,6 +2831,7 @@ class FunctionEvaluatorMixin:
2424
2831
  "float": Builtin(_float, "float"),
2425
2832
  "uppercase": Builtin(_uppercase, "uppercase"),
2426
2833
  "lowercase": Builtin(_lowercase, "lowercase"),
2834
+ "split": Builtin(_split, "split"),
2427
2835
  "random": Builtin(_random, "random"),
2428
2836
  "persist_set": Builtin(_persist_set, "persist_set"),
2429
2837
  "persist_get": Builtin(_persist_get, "persist_get"),
@@ -2435,6 +2843,8 @@ class FunctionEvaluatorMixin:
2435
2843
  "push": Builtin(_push, "push"),
2436
2844
  "append": Builtin(_append, "append"), # Mutating list append
2437
2845
  "extend": Builtin(_extend, "extend"), # Mutating list extend
2846
+ "sort": Builtin(_sort, "sort"), # Sort list or list of maps by key
2847
+ "slice": Builtin(_slice, "slice"), # Get list slice: slice(list, start, end?)
2438
2848
  "reduce": Builtin(_reduce, "reduce"),
2439
2849
  "map": Builtin(_map, "map"),
2440
2850
  "filter": Builtin(_filter, "filter"),
@@ -3120,6 +3530,32 @@ class FunctionEvaluatorMixin:
3120
3530
  String("limit"): Integer(tx.gas_limit)
3121
3531
  })
3122
3532
 
3533
+ # generateKeypair(algorithm?)
3534
+ def _generate_keypair(*a):
3535
+ algorithm = a[0].value if len(a) > 0 and hasattr(a[0], 'value') else 'ECDSA'
3536
+ try:
3537
+ private_key, public_key = CryptoPlugin.generate_keypair(algorithm)
3538
+ return Map({
3539
+ String('private_key'): String(private_key),
3540
+ String('public_key'): String(public_key)
3541
+ })
3542
+ except Exception as e:
3543
+ return EvaluationError(f"Keypair generation error: {str(e)}")
3544
+
3545
+ # deriveAddress(public_key, [prefix])
3546
+ def _derive_address(*a):
3547
+ if len(a) < 1 or len(a) > 2:
3548
+ return EvaluationError("deriveAddress() expects 1 or 2 arguments: public_key, [prefix]")
3549
+ public_key = a[0].value if hasattr(a[0], 'value') else str(a[0])
3550
+ prefix = None
3551
+ if len(a) > 1:
3552
+ prefix = a[1].value if hasattr(a[1], 'value') else str(a[1])
3553
+ try:
3554
+ result = CryptoPlugin.derive_address(public_key, prefix=prefix)
3555
+ return String(result)
3556
+ except Exception as e:
3557
+ return EvaluationError(f"Address derivation error: {str(e)}")
3558
+
3123
3559
  self.builtins.update({
3124
3560
  "hash": Builtin(_hash, "hash"),
3125
3561
  "keccak256": Builtin(_keccak256, "keccak256"),
@@ -3127,6 +3563,8 @@ class FunctionEvaluatorMixin:
3127
3563
  "verify_sig": Builtin(_verify_sig, "verify_sig"),
3128
3564
  "tx": Builtin(_tx, "tx"),
3129
3565
  "gas": Builtin(_gas, "gas"),
3566
+ "generateKeypair": Builtin(_generate_keypair, "generateKeypair"),
3567
+ "deriveAddress": Builtin(_derive_address, "deriveAddress"),
3130
3568
  })
3131
3569
 
3132
3570
  # Register advanced feature builtins