zexus 1.7.2 → 1.8.1

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 (49) hide show
  1. package/README.md +57 -6
  2. package/package.json +2 -1
  3. package/rust_core/Cargo.lock +603 -0
  4. package/rust_core/Cargo.toml +26 -0
  5. package/rust_core/README.md +15 -0
  6. package/rust_core/pyproject.toml +25 -0
  7. package/rust_core/src/binary_bytecode.rs +543 -0
  8. package/rust_core/src/contract_vm.rs +643 -0
  9. package/rust_core/src/executor.rs +847 -0
  10. package/rust_core/src/hasher.rs +90 -0
  11. package/rust_core/src/lib.rs +71 -0
  12. package/rust_core/src/merkle.rs +128 -0
  13. package/rust_core/src/rust_vm.rs +2313 -0
  14. package/rust_core/src/signature.rs +79 -0
  15. package/rust_core/src/state_adapter.rs +281 -0
  16. package/rust_core/src/validator.rs +116 -0
  17. package/scripts/postinstall.js +34 -2
  18. package/src/zexus/__init__.py +1 -1
  19. package/src/zexus/blockchain/accelerator.py +27 -0
  20. package/src/zexus/blockchain/contract_vm.py +409 -3
  21. package/src/zexus/blockchain/rust_bridge.py +64 -0
  22. package/src/zexus/cli/main.py +1 -1
  23. package/src/zexus/cli/zpm.py +1 -1
  24. package/src/zexus/evaluator/bytecode_compiler.py +150 -52
  25. package/src/zexus/evaluator/core.py +151 -809
  26. package/src/zexus/evaluator/expressions.py +27 -22
  27. package/src/zexus/evaluator/functions.py +171 -126
  28. package/src/zexus/evaluator/statements.py +55 -112
  29. package/src/zexus/module_cache.py +20 -9
  30. package/src/zexus/object.py +330 -38
  31. package/src/zexus/parser/parser.py +69 -14
  32. package/src/zexus/parser/strategy_context.py +228 -5
  33. package/src/zexus/parser/strategy_structural.py +2 -2
  34. package/src/zexus/persistence.py +46 -17
  35. package/src/zexus/security.py +140 -234
  36. package/src/zexus/type_checker.py +44 -5
  37. package/src/zexus/vm/binary_bytecode.py +7 -3
  38. package/src/zexus/vm/bytecode.py +6 -0
  39. package/src/zexus/vm/cache.py +24 -46
  40. package/src/zexus/vm/compiler.py +80 -20
  41. package/src/zexus/vm/fastops.c +1093 -2975
  42. package/src/zexus/vm/gas_metering.py +2 -2
  43. package/src/zexus/vm/memory_pool.py +21 -9
  44. package/src/zexus/vm/vm.py +527 -67
  45. package/src/zexus/zpm/package_manager.py +1 -1
  46. package/src/zexus.egg-info/PKG-INFO +79 -12
  47. package/src/zexus.egg-info/SOURCES.txt +23 -1
  48. package/src/zexus.egg-info/requires.txt +26 -0
  49. package/src/zexus.egg-info/entry_points.txt +0 -4
@@ -58,6 +58,22 @@ except ImportError:
58
58
  GasCost = None # type: ignore
59
59
  OutOfGasError = None # type: ignore
60
60
 
61
+ # Rust VM (Phase 3 — adaptive contract execution)
62
+ try:
63
+ from zexus_core import RustVMExecutor as _RustVMExecutor
64
+ _RUST_VM_AVAILABLE = True
65
+ except Exception:
66
+ _RUST_VM_AVAILABLE = False
67
+ _RustVMExecutor = None # type: ignore
68
+
69
+ # Rust ContractVM orchestrator (Phase 4)
70
+ try:
71
+ from zexus_core import RustContractVM as _RustContractVM
72
+ _RUST_CONTRACT_VM_AVAILABLE = True
73
+ except Exception:
74
+ _RUST_CONTRACT_VM_AVAILABLE = False
75
+ _RustContractVM = None # type: ignore
76
+
61
77
  # SmartContract from security module
62
78
  try:
63
79
  from ..security import SmartContract
@@ -196,8 +212,31 @@ class ContractVM:
196
212
  "bytecode_executions": 0,
197
213
  "bytecode_fallbacks": 0,
198
214
  "treewalk_executions": 0,
215
+ "rust_executions": 0,
216
+ "rust_fallbacks": 0,
199
217
  }
200
218
 
219
+ # Rust VM executor (Phase 3 + Phase 6 — Rust-first execution)
220
+ self._rust_vm_executor = _RustVMExecutor() if _RUST_VM_AVAILABLE else None
221
+ self._rust_vm_threshold = 0 # Phase 6: route ALL contracts through Rust by default
222
+ try:
223
+ _env_thresh = os.environ.get("ZEXUS_RUST_VM_THRESHOLD")
224
+ if _env_thresh is not None:
225
+ self._rust_vm_threshold = int(_env_thresh)
226
+ except (ValueError, TypeError):
227
+ pass
228
+
229
+ # Rust ContractVM orchestrator (Phase 4)
230
+ self._rust_contract_vm = (
231
+ _RustContractVM(
232
+ gas_discount=0.6,
233
+ default_gas_limit=gas_limit,
234
+ max_call_depth=self._max_call_depth,
235
+ )
236
+ if _RUST_CONTRACT_VM_AVAILABLE
237
+ else None
238
+ )
239
+
201
240
  # ------------------------------------------------------------------
202
241
  # Contract lifecycle
203
242
  # ------------------------------------------------------------------
@@ -334,7 +373,20 @@ class ContractVM:
334
373
  env = self._build_env(state_adapter, tx_ctx, contract, args or {})
335
374
  builtins = self._build_builtins(tx_ctx, contract_address, logs)
336
375
 
337
- # 4. Execute
376
+ # ── Phase 4: Rust ContractVM orchestration ──
377
+ # Try to handle the entire execution lifecycle in Rust.
378
+ # If Rust signals needs_fallback we fall through to Python.
379
+ if (self._rust_contract_vm is not None
380
+ and self._use_bytecode_vm
381
+ and hasattr(action_obj, 'body')):
382
+ rust_receipt = self._try_rust_contract_vm(
383
+ contract_address, action_obj, state_adapter,
384
+ snapshot, env, args or {}, gas_limit, caller, logs,
385
+ )
386
+ if rust_receipt is not None:
387
+ return rust_receipt
388
+
389
+ # 4. Execute (Python path — Phase 3/0/tree-walk)
338
390
  try:
339
391
  vm = ZexusVM(
340
392
  env=env,
@@ -717,6 +769,16 @@ class ContractVM:
717
769
  except Exception:
718
770
  pass
719
771
 
772
+ # --- Phase 3: Rust VM execution for large contracts ---
773
+ if (self._rust_vm_executor is not None
774
+ and self._use_bytecode_vm
775
+ and hasattr(action_obj, 'body')):
776
+ rust_result = self._try_rust_vm_execution(
777
+ action_obj, env, args, vm, cached_bc
778
+ )
779
+ if rust_result is not None:
780
+ used_bytecode, result = rust_result
781
+
720
782
  # --- Phase 0: bytecoded execution with fallback ---
721
783
  if self._use_bytecode_vm and hasattr(action_obj, 'body'):
722
784
  try:
@@ -811,9 +873,342 @@ class ContractVM:
811
873
 
812
874
  return result
813
875
 
876
+ def _try_rust_vm_execution(
877
+ self,
878
+ action_obj: Any,
879
+ env: Dict[str, Any],
880
+ args: Dict[str, Any],
881
+ vm: "ZexusVM",
882
+ cached_bc: Any,
883
+ ) -> Optional[Tuple[bool, Any]]:
884
+ """Attempt to run an action through the Rust VM.
885
+
886
+ Returns ``(True, result)`` on success, ``None`` if the Rust VM
887
+ is unavailable or signals a fallback. The caller should fall
888
+ through to Phase 0 / tree-walk when ``None`` is returned.
889
+ """
890
+ try:
891
+ from ..vm.binary_bytecode import serialize as _serialize_zxc
892
+
893
+ # We need serializable bytecode — either from the .zxc cache
894
+ # or by compiling now.
895
+ zxc_data = None
896
+ bc = cached_bc
897
+ if bc is None:
898
+ # Try to compile to bytecode so we can check instruction count
899
+ from ..evaluator.core import Evaluator
900
+ evaluator = Evaluator(use_vm=True)
901
+ try:
902
+ bc = evaluator.compile_to_bytecode(action_obj.body)
903
+ except Exception:
904
+ return None
905
+
906
+ # Check threshold
907
+ instr_count = len(getattr(bc, "instructions", []))
908
+ if instr_count < self._rust_vm_threshold:
909
+ return None # Too small — let Python handle it
910
+
911
+ # Serialize
912
+ zxc_data = _serialize_zxc(bc, include_checksum=True)
913
+
914
+ # Build state dict from ContractStateAdapter
915
+ state_adapter = env.get("_blockchain_state")
916
+ rust_state = {}
917
+ if state_adapter and isinstance(state_adapter, dict):
918
+ for k, v in state_adapter.items():
919
+ if isinstance(v, (int, float, str, bool, type(None))):
920
+ rust_state[k] = v
921
+
922
+ # Build env dict (simple values only)
923
+ from ..object import (
924
+ Integer as ZInteger, Float as ZFloat,
925
+ Boolean as ZBoolean, String as ZString, Null as ZNull,
926
+ )
927
+ rust_env = {}
928
+ for k, v in env.items():
929
+ if isinstance(v, (int, float, str, bool, type(None))):
930
+ rust_env[k] = v
931
+ elif isinstance(v, ZInteger):
932
+ rust_env[k] = v.value
933
+ elif isinstance(v, ZFloat):
934
+ rust_env[k] = v.value
935
+ elif isinstance(v, ZString):
936
+ rust_env[k] = v.value
937
+ elif isinstance(v, ZBoolean):
938
+ rust_env[k] = v.value
939
+ elif isinstance(v, ZNull):
940
+ rust_env[k] = None
941
+
942
+ # Add action parameters
943
+ if hasattr(action_obj, 'parameters') and action_obj.parameters:
944
+ for param in action_obj.parameters:
945
+ param_name = param.value if hasattr(param, 'value') else str(param)
946
+ if param_name in args:
947
+ v = args[param_name]
948
+ if isinstance(v, (int, float, str, bool, type(None))):
949
+ rust_env[param_name] = v
950
+
951
+ # Gas limit
952
+ gas_limit = 0
953
+ if vm.gas_metering:
954
+ remaining_fn = getattr(vm.gas_metering, "remaining", None)
955
+ if callable(remaining_fn):
956
+ try:
957
+ rem = remaining_fn()
958
+ if isinstance(rem, (int, float)) and rem > 0:
959
+ gas_limit = int(rem)
960
+ except Exception:
961
+ pass
962
+ if gas_limit == 0:
963
+ gl = getattr(vm.gas_metering, "gas_limit", 0) or 0
964
+ gu = getattr(vm.gas_metering, "gas_used", 0) or 0
965
+ if isinstance(gl, (int, float)) and isinstance(gu, (int, float)):
966
+ if gl > gu:
967
+ gas_limit = int(gl - gu)
968
+
969
+ # Execute
970
+ result_dict = self._rust_vm_executor.execute(
971
+ zxc_data,
972
+ env=rust_env or None,
973
+ state=rust_state or None,
974
+ gas_limit=gas_limit,
975
+ )
976
+
977
+ # Fallback?
978
+ if result_dict.get("needs_fallback", False):
979
+ self._vm_stats["rust_fallbacks"] += 1
980
+ return None
981
+
982
+ # Error?
983
+ error = result_dict.get("error")
984
+ if error:
985
+ if "OutOfGas" in str(error):
986
+ raise RuntimeError(str(error))
987
+ if "RequireFailed" in str(error):
988
+ raise RuntimeError(str(error))
989
+ # Other errors — fall back
990
+ self._vm_stats["rust_fallbacks"] += 1
991
+ return None
992
+
993
+ # Success — bridge gas back
994
+ if vm.gas_metering:
995
+ rust_gas = result_dict.get("gas_used", 0)
996
+ if rust_gas > 0:
997
+ current_used = getattr(vm.gas_metering, "gas_used", None)
998
+ if current_used is not None:
999
+ vm.gas_metering.gas_used = current_used + rust_gas
1000
+ add_fn = getattr(vm.gas_metering, "add_gas", None)
1001
+ if add_fn:
1002
+ add_fn(rust_gas)
1003
+
1004
+ # Merge state back into ContractStateAdapter
1005
+ rust_state_out = result_dict.get("state", {})
1006
+ if rust_state_out and state_adapter is not None:
1007
+ for k, v in rust_state_out.items():
1008
+ state_adapter[k] = v
1009
+
1010
+ self._vm_stats["rust_executions"] += 1
1011
+ if self._debug:
1012
+ logger.debug(
1013
+ "Rust VM execution: ops=%d gas=%d",
1014
+ result_dict.get("instructions_executed", 0),
1015
+ result_dict.get("gas_used", 0),
1016
+ )
1017
+
1018
+ return (True, result_dict.get("result"))
1019
+
1020
+ except Exception as e:
1021
+ self._vm_stats["rust_fallbacks"] += 1
1022
+ logger.debug("Rust VM execution failed, falling back: %s", e)
1023
+ return None
1024
+
1025
+ def _try_rust_contract_vm(
1026
+ self,
1027
+ contract_address: str,
1028
+ action_obj: Any,
1029
+ state_adapter: ContractStateAdapter,
1030
+ snapshot: Dict[str, Any],
1031
+ env: Dict[str, Any],
1032
+ args: Dict[str, Any],
1033
+ gas_limit: int,
1034
+ caller: str,
1035
+ logs: List[Dict[str, Any]],
1036
+ ) -> Optional[ContractExecutionReceipt]:
1037
+ """Phase 4: Attempt full contract execution via Rust ContractVM.
1038
+
1039
+ Returns a ``ContractExecutionReceipt`` on success, or ``None``
1040
+ if Rust can't handle it (falls back to Python).
1041
+ """
1042
+ try:
1043
+ from ..vm.binary_bytecode import serialize as _serialize_zxc
1044
+
1045
+ # Compile to bytecode
1046
+ bc = getattr(action_obj, '_cached_bytecode', None)
1047
+ if bc is None:
1048
+ from ..evaluator.core import Evaluator
1049
+ evaluator = Evaluator(use_vm=True)
1050
+ try:
1051
+ bc = evaluator.compile_to_bytecode(action_obj.body)
1052
+ except Exception:
1053
+ return None # Can't compile — fall back
1054
+
1055
+ # Serialize to .zxc
1056
+ zxc_data = _serialize_zxc(bc, include_checksum=True)
1057
+
1058
+ # Build state dict (simple values)
1059
+ rust_state = {}
1060
+ for k, v in state_adapter.items():
1061
+ if isinstance(v, (int, float, str, bool, type(None))):
1062
+ rust_state[k] = v
1063
+
1064
+ # Build env dict (simple values)
1065
+ from ..object import (
1066
+ Integer as ZInteger, Float as ZFloat,
1067
+ Boolean as ZBoolean, String as ZString, Null as ZNull,
1068
+ )
1069
+ rust_env = {}
1070
+ for k, v in env.items():
1071
+ if isinstance(v, (int, float, str, bool, type(None))):
1072
+ rust_env[k] = v
1073
+ elif isinstance(v, ZInteger):
1074
+ rust_env[k] = v.value
1075
+ elif isinstance(v, ZFloat):
1076
+ rust_env[k] = v.value
1077
+ elif isinstance(v, ZString):
1078
+ rust_env[k] = v.value
1079
+ elif isinstance(v, ZBoolean):
1080
+ rust_env[k] = v.value
1081
+ elif isinstance(v, ZNull):
1082
+ rust_env[k] = None
1083
+
1084
+ # Phase 6: Inject chain info for Rust builtins
1085
+ if "_block_number" not in rust_env:
1086
+ try:
1087
+ rust_env["_block_number"] = self._chain.height
1088
+ except Exception:
1089
+ rust_env["_block_number"] = 0
1090
+ if "_block_timestamp" not in rust_env:
1091
+ try:
1092
+ tip = self._chain.tip
1093
+ rust_env["_block_timestamp"] = (
1094
+ tip.header.timestamp if tip else 0.0
1095
+ )
1096
+ except Exception:
1097
+ rust_env["_block_timestamp"] = 0.0
1098
+
1099
+ # Build args dict (simple values)
1100
+ rust_args = {}
1101
+ for k, v in args.items():
1102
+ if isinstance(v, (int, float, str, bool, type(None))):
1103
+ rust_args[k] = v
1104
+
1105
+ # Execute via Rust ContractVM
1106
+ result_dict = self._rust_contract_vm.execute_contract(
1107
+ contract_address=contract_address,
1108
+ action_bytecode=zxc_data,
1109
+ state=rust_state or None,
1110
+ env=rust_env or None,
1111
+ args=rust_args or None,
1112
+ gas_limit=gas_limit,
1113
+ caller=caller,
1114
+ )
1115
+
1116
+ # Check for fallback
1117
+ if result_dict.get("needs_fallback", False):
1118
+ self._vm_stats["rust_fallbacks"] += 1
1119
+ if self._debug:
1120
+ logger.debug("Rust ContractVM needs fallback: %s",
1121
+ result_dict.get("error", ""))
1122
+ return None
1123
+
1124
+ # Build receipt
1125
+ success = result_dict.get("success", False)
1126
+ gas_used = result_dict.get("gas_used", 0)
1127
+
1128
+ if success:
1129
+ # Merge new state back to ContractStateAdapter
1130
+ new_state = result_dict.get("new_state", {})
1131
+ if new_state:
1132
+ state_adapter.clear()
1133
+ state_adapter.update(new_state)
1134
+ state_adapter.commit()
1135
+
1136
+ # Phase 6: Collect events emitted by Rust builtins
1137
+ rust_events = result_dict.get("events", [])
1138
+ import time as _time
1139
+ for ev in rust_events:
1140
+ ev_name = ev.get("event", "") if isinstance(ev, dict) else str(ev)
1141
+ ev_data = ev.get("data", None) if isinstance(ev, dict) else None
1142
+ logs.append({
1143
+ "event": ev_name,
1144
+ "data": ev_data,
1145
+ "timestamp": _time.time(),
1146
+ "contract": contract_address,
1147
+ })
1148
+
1149
+ self._vm_stats["rust_executions"] += 1
1150
+
1151
+ return ContractExecutionReceipt(
1152
+ success=True,
1153
+ return_value=result_dict.get("result"),
1154
+ gas_used=gas_used,
1155
+ gas_limit=gas_limit,
1156
+ logs=list(logs),
1157
+ state_changes=result_dict.get("state_changes", {}),
1158
+ )
1159
+ else:
1160
+ # Error — rollback
1161
+ state_adapter.rollback(snapshot)
1162
+ error = result_dict.get("error", "UnknownError")
1163
+
1164
+ if error == "OutOfGas":
1165
+ self._vm_stats["rust_fallbacks"] += 1
1166
+ return ContractExecutionReceipt(
1167
+ success=False,
1168
+ gas_used=gas_limit,
1169
+ gas_limit=gas_limit,
1170
+ error="OutOfGas",
1171
+ revert_reason=result_dict.get("revert_reason", ""),
1172
+ )
1173
+ elif error == "ReentrancyGuard":
1174
+ return ContractExecutionReceipt(
1175
+ success=False,
1176
+ error="ReentrancyGuard",
1177
+ revert_reason=result_dict.get("revert_reason", ""),
1178
+ gas_limit=gas_limit,
1179
+ )
1180
+ else:
1181
+ self._vm_stats["rust_fallbacks"] += 1
1182
+ return ContractExecutionReceipt(
1183
+ success=False,
1184
+ gas_used=gas_used,
1185
+ gas_limit=gas_limit,
1186
+ error=error,
1187
+ revert_reason=result_dict.get("revert_reason", ""),
1188
+ logs=list(logs),
1189
+ )
1190
+
1191
+ except Exception as e:
1192
+ self._vm_stats["rust_fallbacks"] += 1
1193
+ logger.debug("Rust ContractVM failed, falling back: %s", e)
1194
+ return None
1195
+
814
1196
  def get_vm_execution_stats(self) -> Dict[str, Any]:
815
- """Return Phase 0 execution statistics."""
816
- total = sum(self._vm_stats.values())
1197
+ """Return Phase 0-3 execution statistics."""
1198
+ total = (
1199
+ self._vm_stats["bytecode_executions"]
1200
+ + self._vm_stats["bytecode_fallbacks"]
1201
+ + self._vm_stats["treewalk_executions"]
1202
+ + self._vm_stats["rust_executions"]
1203
+ )
1204
+ # Phase 4 stats from Rust ContractVM
1205
+ rust_cvm_stats = {}
1206
+ if self._rust_contract_vm is not None:
1207
+ try:
1208
+ rust_cvm_stats = self._rust_contract_vm.get_stats()
1209
+ except Exception:
1210
+ pass
1211
+
817
1212
  return {
818
1213
  **self._vm_stats,
819
1214
  "total_executions": total,
@@ -821,7 +1216,15 @@ class ContractVM:
821
1216
  self._vm_stats["bytecode_executions"] / total * 100
822
1217
  if total > 0 else 0.0
823
1218
  ),
1219
+ "rust_rate": (
1220
+ self._vm_stats["rust_executions"] / total * 100
1221
+ if total > 0 else 0.0
1222
+ ),
824
1223
  "use_bytecode_vm": self._use_bytecode_vm,
1224
+ "rust_vm_available": self._rust_vm_executor is not None,
1225
+ "rust_vm_threshold": self._rust_vm_threshold,
1226
+ "rust_contract_vm_available": self._rust_contract_vm is not None,
1227
+ "rust_contract_vm_stats": rust_cvm_stats,
825
1228
  }
826
1229
 
827
1230
  # ------------------------------------------------------------------
@@ -940,6 +1343,9 @@ class ContractVM:
940
1343
  gas_limit=gas_limit,
941
1344
  debug=self._debug,
942
1345
  )
1346
+ # Static calls use light gas metering (flat 1/op) since
1347
+ # they don't consume chain resources — read-only.
1348
+ vm.enable_gas_light = True
943
1349
  result = self._execute_action(vm, action_obj, env, args or {})
944
1350
  gas_used = vm.gas_metering.gas_used if vm.gas_metering else 0
945
1351
 
@@ -327,6 +327,48 @@ def _execute_batch_py(
327
327
  return result
328
328
 
329
329
 
330
+ # ── Phase 5: GIL-free Native Batch Execution ──────────────────────────
331
+
332
+ def execute_batch_native(
333
+ transactions: List[Dict[str, Any]],
334
+ max_workers: int = 0,
335
+ gas_discount: float = 0.6,
336
+ default_gas_limit: int = 10_000_000,
337
+ ) -> Optional[Dict[str, Any]]:
338
+ """Execute a batch of pre-compiled .zxc transactions entirely in Rust.
339
+
340
+ **Zero GIL acquisitions during execution.** Requires Rust core.
341
+
342
+ Parameters
343
+ ----------
344
+ transactions : list of dict
345
+ Each dict must contain ``bytecode`` (bytes), ``contract_address`` (str),
346
+ ``caller`` (str). Optional: ``gas_limit``, ``state``, ``gas_discount``.
347
+ max_workers : int
348
+ Rayon thread count (0 = auto-detect CPU cores).
349
+ gas_discount : float
350
+ Default gas discount for Rust execution (0.6 = 40% cheaper).
351
+ default_gas_limit : int
352
+ Default gas limit if not specified per-transaction.
353
+
354
+ Returns
355
+ -------
356
+ dict or None
357
+ Dict with keys: total, succeeded, failed, gas_used, gas_saved,
358
+ throughput, receipts, state_changes, mode='native_gil_free'.
359
+ Returns None if Rust core is not available.
360
+ """
361
+ if not _RUST_AVAILABLE:
362
+ return None
363
+
364
+ executor = _zexus_core.RustBatchExecutor(
365
+ max_workers=max_workers,
366
+ gas_discount=gas_discount,
367
+ default_gas_limit=default_gas_limit,
368
+ )
369
+ return executor.execute_batch_native(transactions)
370
+
371
+
330
372
  # ── Block Validation ───────────────────────────────────────────────────
331
373
 
332
374
  def validate_chain_headers(
@@ -416,6 +458,28 @@ class RustCoreBridge:
416
458
  transactions, vm_callback, max_workers=self._max_workers
417
459
  )
418
460
 
461
+ def execute_batch_native(
462
+ self,
463
+ transactions: List[Dict[str, Any]],
464
+ ) -> Optional[Dict[str, Any]]:
465
+ """Execute a batch of pre-compiled .zxc transactions — zero GIL.
466
+
467
+ Each transaction dict must contain:
468
+ - ``bytecode``: bytes — .zxc serialized bytecode
469
+ - ``contract_address``: str
470
+ - ``caller``: str
471
+ - ``gas_limit``: int (optional)
472
+ - ``state``: dict (optional)
473
+ - ``gas_discount``: float (optional)
474
+
475
+ Returns a dict with keys: total, succeeded, failed, gas_used,
476
+ gas_saved, throughput, receipts, state_changes, mode='native_gil_free'.
477
+ Returns None if Rust is not available.
478
+ """
479
+ return execute_batch_native(
480
+ transactions, max_workers=self._max_workers
481
+ )
482
+
419
483
  # Validation
420
484
  validate_chain = staticmethod(validate_chain_headers)
421
485
  check_pow = staticmethod(check_pow_difficulty)
@@ -156,7 +156,7 @@ def show_all_commands():
156
156
  console.print("\n[bold green]💡 Tip:[/bold green] Use 'zx <command> --help' for detailed command options\n")
157
157
 
158
158
  @click.group(invoke_without_command=True)
159
- @click.version_option(version="1.7.2", prog_name="Zexus")
159
+ @click.version_option(version="1.8.1", prog_name="Zexus")
160
160
  @click.option('--syntax-style', type=click.Choice(['universal', 'tolerable', 'auto']),
161
161
  default='auto', help='Syntax style to use (universal=strict, tolerable=flexible)')
162
162
  @click.option('--advanced-parsing', is_flag=True, default=True,
@@ -18,7 +18,7 @@ console = Console()
18
18
 
19
19
 
20
20
  @click.group()
21
- @click.version_option(version="1.7.2", prog_name="ZPM")
21
+ @click.version_option(version="1.8.1", prog_name="ZPM")
22
22
  def cli():
23
23
  """ZPM - Zexus Package Manager
24
24