zexus 1.6.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.
- package/LICENSE +0 -0
- package/README.md +2513 -0
- package/bin/zexus +2 -0
- package/bin/zpics +2 -0
- package/bin/zpm +2 -0
- package/bin/zx +2 -0
- package/bin/zx-deploy +2 -0
- package/bin/zx-dev +2 -0
- package/bin/zx-run +2 -0
- package/package.json +66 -0
- package/scripts/README.md +24 -0
- package/scripts/postinstall.js +44 -0
- package/shared_config.json +24 -0
- package/src/README.md +1525 -0
- package/src/tests/run_zexus_tests.py +117 -0
- package/src/tests/test_all_phases.zx +346 -0
- package/src/tests/test_blockchain_features.zx +306 -0
- package/src/tests/test_complexity_features.zx +321 -0
- package/src/tests/test_core_integration.py +185 -0
- package/src/tests/test_phase10_ecosystem.zx +177 -0
- package/src/tests/test_phase1_modifiers.zx +87 -0
- package/src/tests/test_phase2_plugins.zx +80 -0
- package/src/tests/test_phase3_security.zx +97 -0
- package/src/tests/test_phase4_vfs.zx +116 -0
- package/src/tests/test_phase5_types.zx +117 -0
- package/src/tests/test_phase6_metaprogramming.zx +125 -0
- package/src/tests/test_phase7_optimization.zx +132 -0
- package/src/tests/test_phase9_advanced_types.zx +157 -0
- package/src/tests/test_security_features.py +419 -0
- package/src/tests/test_security_features.zx +276 -0
- package/src/tests/test_simple_zx.zx +1 -0
- package/src/tests/test_verification_simple.zx +69 -0
- package/src/zexus/__init__.py +28 -0
- package/src/zexus/__main__.py +5 -0
- package/src/zexus/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/advanced_types.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/builtin_modules.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/capability_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/complexity_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/concurrency_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/config.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/dependency_injection.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/ecosystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/environment.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/error_reporter.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/hybrid_orchestrator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/metaprogramming.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/module_cache.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/object.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/optimization.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/plugin_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/policy_engine.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/security.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/stdlib_integration.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/strategy_recovery.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/syntax_validator.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/type_system.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/virtual_filesystem.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/__pycache__/zexus_token.cpython-312.pyc +0 -0
- package/src/zexus/advanced_types.py +401 -0
- package/src/zexus/blockchain/__init__.py +40 -0
- package/src/zexus/blockchain/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/crypto.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/ledger.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/__pycache__/transaction.cpython-312.pyc +0 -0
- package/src/zexus/blockchain/crypto.py +463 -0
- package/src/zexus/blockchain/ledger.py +255 -0
- package/src/zexus/blockchain/transaction.py +267 -0
- package/src/zexus/builtin_modules.py +284 -0
- package/src/zexus/builtin_plugins.py +317 -0
- package/src/zexus/capability_system.py +372 -0
- package/src/zexus/cli/__init__.py +2 -0
- package/src/zexus/cli/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/cli/__pycache__/main.cpython-312.pyc +0 -0
- package/src/zexus/cli/main.py +707 -0
- package/src/zexus/cli/zpm.py +203 -0
- package/src/zexus/compare_interpreter_compiler.py +146 -0
- package/src/zexus/compiler/__init__.py +169 -0
- package/src/zexus/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/lexer.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/compiler/__pycache__/zexus_ast.cpython-312.pyc +0 -0
- package/src/zexus/compiler/bytecode.py +266 -0
- package/src/zexus/compiler/compat_runtime.py +277 -0
- package/src/zexus/compiler/lexer.py +257 -0
- package/src/zexus/compiler/parser.py +779 -0
- package/src/zexus/compiler/semantic.py +118 -0
- package/src/zexus/compiler/zexus_ast.py +454 -0
- package/src/zexus/complexity_system.py +575 -0
- package/src/zexus/concurrency_system.py +493 -0
- package/src/zexus/config.py +201 -0
- package/src/zexus/crypto_bridge.py +19 -0
- package/src/zexus/dependency_injection.py +423 -0
- package/src/zexus/ecosystem.py +434 -0
- package/src/zexus/environment.py +101 -0
- package/src/zexus/environment_manager.py +119 -0
- package/src/zexus/error_reporter.py +314 -0
- package/src/zexus/evaluator/__init__.py +12 -0
- package/src/zexus/evaluator/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/bytecode_compiler.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/core.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/expressions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/functions.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/integration.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/statements.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/__pycache__/utils.cpython-312.pyc +0 -0
- package/src/zexus/evaluator/bytecode_compiler.py +700 -0
- package/src/zexus/evaluator/core.py +891 -0
- package/src/zexus/evaluator/expressions.py +827 -0
- package/src/zexus/evaluator/functions.py +3989 -0
- package/src/zexus/evaluator/integration.py +396 -0
- package/src/zexus/evaluator/statements.py +4303 -0
- package/src/zexus/evaluator/utils.py +126 -0
- package/src/zexus/evaluator_original.py +2041 -0
- package/src/zexus/external_bridge.py +16 -0
- package/src/zexus/find_affected_imports.sh +155 -0
- package/src/zexus/hybrid_orchestrator.py +152 -0
- package/src/zexus/input_validation.py +259 -0
- package/src/zexus/lexer.py +571 -0
- package/src/zexus/logging.py +89 -0
- package/src/zexus/lsp/__init__.py +9 -0
- package/src/zexus/lsp/completion_provider.py +207 -0
- package/src/zexus/lsp/definition_provider.py +22 -0
- package/src/zexus/lsp/hover_provider.py +71 -0
- package/src/zexus/lsp/server.py +269 -0
- package/src/zexus/lsp/symbol_provider.py +31 -0
- package/src/zexus/metaprogramming.py +321 -0
- package/src/zexus/module_cache.py +89 -0
- package/src/zexus/module_manager.py +107 -0
- package/src/zexus/object.py +973 -0
- package/src/zexus/optimization.py +424 -0
- package/src/zexus/parser/__init__.py +31 -0
- package/src/zexus/parser/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/parser.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_context.cpython-312.pyc +0 -0
- package/src/zexus/parser/__pycache__/strategy_structural.cpython-312.pyc +0 -0
- package/src/zexus/parser/integration.py +86 -0
- package/src/zexus/parser/parser.py +3977 -0
- package/src/zexus/parser/strategy_context.py +7254 -0
- package/src/zexus/parser/strategy_structural.py +1033 -0
- package/src/zexus/persistence.py +391 -0
- package/src/zexus/plugin_system.py +290 -0
- package/src/zexus/policy_engine.py +365 -0
- package/src/zexus/profiler/__init__.py +5 -0
- package/src/zexus/profiler/profiler.py +233 -0
- package/src/zexus/purity_system.py +398 -0
- package/src/zexus/runtime/__init__.py +20 -0
- package/src/zexus/runtime/async_runtime.py +324 -0
- package/src/zexus/search_old_imports.sh +65 -0
- package/src/zexus/security.py +1407 -0
- package/src/zexus/stack_trace.py +233 -0
- package/src/zexus/stdlib/__init__.py +27 -0
- package/src/zexus/stdlib/blockchain.py +341 -0
- package/src/zexus/stdlib/compression.py +167 -0
- package/src/zexus/stdlib/crypto.py +124 -0
- package/src/zexus/stdlib/datetime.py +163 -0
- package/src/zexus/stdlib/db_mongo.py +199 -0
- package/src/zexus/stdlib/db_mysql.py +162 -0
- package/src/zexus/stdlib/db_postgres.py +163 -0
- package/src/zexus/stdlib/db_sqlite.py +133 -0
- package/src/zexus/stdlib/encoding.py +230 -0
- package/src/zexus/stdlib/fs.py +195 -0
- package/src/zexus/stdlib/http.py +219 -0
- package/src/zexus/stdlib/http_server.py +248 -0
- package/src/zexus/stdlib/json_module.py +61 -0
- package/src/zexus/stdlib/math.py +360 -0
- package/src/zexus/stdlib/os_module.py +265 -0
- package/src/zexus/stdlib/regex.py +148 -0
- package/src/zexus/stdlib/sockets.py +253 -0
- package/src/zexus/stdlib/test_framework.zx +208 -0
- package/src/zexus/stdlib/test_runner.zx +119 -0
- package/src/zexus/stdlib_integration.py +341 -0
- package/src/zexus/strategy_recovery.py +256 -0
- package/src/zexus/syntax_validator.py +356 -0
- package/src/zexus/testing/zpics.py +407 -0
- package/src/zexus/testing/zpics_runtime.py +369 -0
- package/src/zexus/type_system.py +374 -0
- package/src/zexus/validation_system.py +569 -0
- package/src/zexus/virtual_filesystem.py +355 -0
- package/src/zexus/vm/__init__.py +8 -0
- package/src/zexus/vm/__pycache__/__init__.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/async_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/bytecode.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/cache.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/jit.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_manager.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/memory_pool.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/parallel_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/peephole_optimizer.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/profiler.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_allocator.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/register_vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/ssa_converter.cpython-312.pyc +0 -0
- package/src/zexus/vm/__pycache__/vm.cpython-312.pyc +0 -0
- package/src/zexus/vm/async_optimizer.py +420 -0
- package/src/zexus/vm/bytecode.py +428 -0
- package/src/zexus/vm/bytecode_converter.py +297 -0
- package/src/zexus/vm/cache.py +532 -0
- package/src/zexus/vm/jit.py +720 -0
- package/src/zexus/vm/memory_manager.py +520 -0
- package/src/zexus/vm/memory_pool.py +511 -0
- package/src/zexus/vm/optimizer.py +478 -0
- package/src/zexus/vm/parallel_vm.py +899 -0
- package/src/zexus/vm/peephole_optimizer.py +452 -0
- package/src/zexus/vm/profiler.py +527 -0
- package/src/zexus/vm/register_allocator.py +462 -0
- package/src/zexus/vm/register_vm.py +520 -0
- package/src/zexus/vm/ssa_converter.py +757 -0
- package/src/zexus/vm/vm.py +1392 -0
- package/src/zexus/zexus_ast.py +1782 -0
- package/src/zexus/zexus_token.py +253 -0
- package/src/zexus/zpm/__init__.py +15 -0
- package/src/zexus/zpm/installer.py +116 -0
- package/src/zexus/zpm/package_manager.py +208 -0
- package/src/zexus/zpm/publisher.py +98 -0
- package/src/zexus/zpm/registry.py +110 -0
- package/src/zexus.egg-info/PKG-INFO +2235 -0
- package/src/zexus.egg-info/SOURCES.txt +876 -0
- package/src/zexus.egg-info/dependency_links.txt +1 -0
- package/src/zexus.egg-info/entry_points.txt +3 -0
- package/src/zexus.egg-info/not-zip-safe +1 -0
- package/src/zexus.egg-info/requires.txt +14 -0
- package/src/zexus.egg-info/top_level.txt +2 -0
- package/zexus.json +14 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Zexus Blockchain Ledger System
|
|
3
|
+
|
|
4
|
+
Implements immutable, versioned state storage for blockchain and smart contract features.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
import time
|
|
9
|
+
import hashlib
|
|
10
|
+
from copy import deepcopy
|
|
11
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class LedgerEntry:
|
|
15
|
+
"""A single versioned entry in the ledger"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, key: str, value: Any, version: int, timestamp: float, tx_hash: str):
|
|
18
|
+
self.key = key
|
|
19
|
+
self.value = value
|
|
20
|
+
self.version = version
|
|
21
|
+
self.timestamp = timestamp
|
|
22
|
+
self.tx_hash = tx_hash
|
|
23
|
+
self.prev_hash = None
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> Dict:
|
|
26
|
+
"""Convert entry to dictionary for hashing"""
|
|
27
|
+
return {
|
|
28
|
+
'key': self.key,
|
|
29
|
+
'value': str(self.value),
|
|
30
|
+
'version': self.version,
|
|
31
|
+
'timestamp': self.timestamp,
|
|
32
|
+
'tx_hash': self.tx_hash,
|
|
33
|
+
'prev_hash': self.prev_hash
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
def hash(self) -> str:
|
|
37
|
+
"""Calculate hash of this entry"""
|
|
38
|
+
data = json.dumps(self.to_dict(), sort_keys=True)
|
|
39
|
+
return hashlib.sha256(data.encode()).hexdigest()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Ledger:
|
|
43
|
+
"""
|
|
44
|
+
Immutable, versioned ledger for blockchain state.
|
|
45
|
+
|
|
46
|
+
Features:
|
|
47
|
+
- Immutability: Old values are never modified, only new versions created
|
|
48
|
+
- Versioning: Every write creates a new version
|
|
49
|
+
- Cryptographic integrity: Each entry is hashed and linked
|
|
50
|
+
- Audit trail: Complete history of all changes
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(self, name: str):
|
|
54
|
+
self.name = name
|
|
55
|
+
self.entries: List[LedgerEntry] = []
|
|
56
|
+
self.current_state: Dict[str, Any] = {}
|
|
57
|
+
self.version_index: Dict[str, List[LedgerEntry]] = {} # key -> list of versions
|
|
58
|
+
self.locked = False
|
|
59
|
+
|
|
60
|
+
def write(self, key: str, value: Any, tx_hash: str) -> LedgerEntry:
|
|
61
|
+
"""
|
|
62
|
+
Write a new value to the ledger (creates new version, doesn't modify old)
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
key: The variable name
|
|
66
|
+
value: The new value
|
|
67
|
+
tx_hash: Hash of the transaction making this write
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
The new ledger entry
|
|
71
|
+
"""
|
|
72
|
+
if self.locked:
|
|
73
|
+
raise RuntimeError(f"Ledger '{self.name}' is locked (immutable)")
|
|
74
|
+
|
|
75
|
+
# Get current version number
|
|
76
|
+
version = len(self.version_index.get(key, [])) + 1
|
|
77
|
+
|
|
78
|
+
# Create new entry
|
|
79
|
+
entry = LedgerEntry(
|
|
80
|
+
key=key,
|
|
81
|
+
value=deepcopy(value), # Deep copy to prevent external modification
|
|
82
|
+
version=version,
|
|
83
|
+
timestamp=time.time(),
|
|
84
|
+
tx_hash=tx_hash
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Link to previous entry
|
|
88
|
+
if key in self.version_index and self.version_index[key]:
|
|
89
|
+
prev_entry = self.version_index[key][-1]
|
|
90
|
+
entry.prev_hash = prev_entry.hash()
|
|
91
|
+
|
|
92
|
+
# Add to ledger
|
|
93
|
+
self.entries.append(entry)
|
|
94
|
+
|
|
95
|
+
# Update indices
|
|
96
|
+
if key not in self.version_index:
|
|
97
|
+
self.version_index[key] = []
|
|
98
|
+
self.version_index[key].append(entry)
|
|
99
|
+
|
|
100
|
+
# Update current state
|
|
101
|
+
self.current_state[key] = value
|
|
102
|
+
|
|
103
|
+
return entry
|
|
104
|
+
|
|
105
|
+
def read(self, key: str, version: Optional[int] = None) -> Any:
|
|
106
|
+
"""
|
|
107
|
+
Read a value from the ledger
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
key: The variable name
|
|
111
|
+
version: Optional version number (defaults to latest)
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
The value at the specified version
|
|
115
|
+
"""
|
|
116
|
+
if key not in self.version_index:
|
|
117
|
+
raise KeyError(f"Key '{key}' not found in ledger '{self.name}'")
|
|
118
|
+
|
|
119
|
+
if version is None:
|
|
120
|
+
# Return current version
|
|
121
|
+
return deepcopy(self.current_state[key])
|
|
122
|
+
|
|
123
|
+
# Return specific version
|
|
124
|
+
versions = self.version_index[key]
|
|
125
|
+
if version < 1 or version > len(versions):
|
|
126
|
+
raise ValueError(f"Invalid version {version} for key '{key}' (1-{len(versions)} available)")
|
|
127
|
+
|
|
128
|
+
return deepcopy(versions[version - 1].value)
|
|
129
|
+
|
|
130
|
+
def get_history(self, key: str) -> List[Tuple[int, Any, float, str]]:
|
|
131
|
+
"""
|
|
132
|
+
Get complete history for a key
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
List of (version, value, timestamp, tx_hash) tuples
|
|
136
|
+
"""
|
|
137
|
+
if key not in self.version_index:
|
|
138
|
+
return []
|
|
139
|
+
|
|
140
|
+
return [
|
|
141
|
+
(entry.version, entry.value, entry.timestamp, entry.tx_hash)
|
|
142
|
+
for entry in self.version_index[key]
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
def verify_integrity(self) -> bool:
|
|
146
|
+
"""
|
|
147
|
+
Verify the cryptographic integrity of the ledger
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
True if all hashes are valid and chain is intact
|
|
151
|
+
"""
|
|
152
|
+
for key, versions in self.version_index.items():
|
|
153
|
+
prev_hash = None
|
|
154
|
+
for entry in versions:
|
|
155
|
+
# Verify hash chain
|
|
156
|
+
if entry.prev_hash != prev_hash:
|
|
157
|
+
return False
|
|
158
|
+
prev_hash = entry.hash()
|
|
159
|
+
return True
|
|
160
|
+
|
|
161
|
+
def seal(self):
|
|
162
|
+
"""Make the ledger immutable (no more writes allowed)"""
|
|
163
|
+
self.locked = True
|
|
164
|
+
|
|
165
|
+
def get_state_root(self) -> str:
|
|
166
|
+
"""
|
|
167
|
+
Calculate the merkle root hash of the current state
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
SHA256 hash representing the entire current state
|
|
171
|
+
"""
|
|
172
|
+
state_data = json.dumps(self.current_state, sort_keys=True)
|
|
173
|
+
return hashlib.sha256(state_data.encode()).hexdigest()
|
|
174
|
+
|
|
175
|
+
def export_audit_trail(self) -> List[Dict]:
|
|
176
|
+
"""Export complete audit trail as JSON-serializable data"""
|
|
177
|
+
return [entry.to_dict() for entry in self.entries]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
class LedgerManager:
|
|
181
|
+
"""
|
|
182
|
+
Global ledger manager
|
|
183
|
+
|
|
184
|
+
Manages all ledgers in the system and provides transaction isolation.
|
|
185
|
+
"""
|
|
186
|
+
|
|
187
|
+
def __init__(self):
|
|
188
|
+
self.ledgers: Dict[str, Ledger] = {}
|
|
189
|
+
self.transaction_stack: List[Dict[str, Any]] = []
|
|
190
|
+
|
|
191
|
+
def create_ledger(self, name: str) -> Ledger:
|
|
192
|
+
"""Create a new ledger"""
|
|
193
|
+
if name in self.ledgers:
|
|
194
|
+
raise ValueError(f"Ledger '{name}' already exists")
|
|
195
|
+
|
|
196
|
+
ledger = Ledger(name)
|
|
197
|
+
self.ledgers[name] = ledger
|
|
198
|
+
return ledger
|
|
199
|
+
|
|
200
|
+
def get_ledger(self, name: str) -> Ledger:
|
|
201
|
+
"""Get existing ledger"""
|
|
202
|
+
if name not in self.ledgers:
|
|
203
|
+
raise KeyError(f"Ledger '{name}' not found")
|
|
204
|
+
return self.ledgers[name]
|
|
205
|
+
|
|
206
|
+
def begin_transaction(self, tx_hash: str, caller: str, timestamp: float):
|
|
207
|
+
"""Begin a new transaction scope"""
|
|
208
|
+
tx_context = {
|
|
209
|
+
'tx_hash': tx_hash,
|
|
210
|
+
'caller': caller,
|
|
211
|
+
'timestamp': timestamp,
|
|
212
|
+
'writes': [], # List of (ledger_name, key, old_value)
|
|
213
|
+
'gas_used': 0,
|
|
214
|
+
'gas_limit': None
|
|
215
|
+
}
|
|
216
|
+
self.transaction_stack.append(tx_context)
|
|
217
|
+
|
|
218
|
+
def commit_transaction(self):
|
|
219
|
+
"""Commit current transaction"""
|
|
220
|
+
if not self.transaction_stack:
|
|
221
|
+
raise RuntimeError("No active transaction to commit")
|
|
222
|
+
|
|
223
|
+
# Remove transaction from stack
|
|
224
|
+
self.transaction_stack.pop()
|
|
225
|
+
|
|
226
|
+
def revert_transaction(self):
|
|
227
|
+
"""
|
|
228
|
+
Revert current transaction
|
|
229
|
+
|
|
230
|
+
Note: For ledgers, we can't truly "revert" since they're immutable.
|
|
231
|
+
Instead, we write compensating entries to restore old values.
|
|
232
|
+
"""
|
|
233
|
+
if not self.transaction_stack:
|
|
234
|
+
raise RuntimeError("No active transaction to revert")
|
|
235
|
+
|
|
236
|
+
tx = self.transaction_stack.pop()
|
|
237
|
+
|
|
238
|
+
# Write compensating entries
|
|
239
|
+
for ledger_name, key, old_value in reversed(tx['writes']):
|
|
240
|
+
ledger = self.ledgers[ledger_name]
|
|
241
|
+
# Create a revert entry
|
|
242
|
+
ledger.write(key, old_value, f"REVERT:{tx['tx_hash']}")
|
|
243
|
+
|
|
244
|
+
def get_current_tx(self) -> Optional[Dict]:
|
|
245
|
+
"""Get current transaction context"""
|
|
246
|
+
return self.transaction_stack[-1] if self.transaction_stack else None
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# Global ledger manager instance
|
|
250
|
+
_ledger_manager = LedgerManager()
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def get_ledger_manager() -> LedgerManager:
|
|
254
|
+
"""Get the global ledger manager"""
|
|
255
|
+
return _ledger_manager
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Zexus Blockchain Transaction Context
|
|
3
|
+
|
|
4
|
+
Implements the TX object and gas tracking for smart contracts.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import time
|
|
8
|
+
import hashlib
|
|
9
|
+
import secrets
|
|
10
|
+
from typing import Optional, Dict, Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TransactionContext:
|
|
14
|
+
"""
|
|
15
|
+
Immutable transaction context (TX object)
|
|
16
|
+
|
|
17
|
+
Provides mandatory information about the current execution environment:
|
|
18
|
+
- TX.caller: Address/ID of the entity executing the code
|
|
19
|
+
- TX.timestamp: Canonical, un-tamperable time of execution
|
|
20
|
+
- TX.block_hash: Cryptographic reference to the preceding state
|
|
21
|
+
- TX.gas_remaining: Remaining gas for execution
|
|
22
|
+
- TX.gas_used: Gas consumed so far
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, caller: str, timestamp: Optional[float] = None,
|
|
26
|
+
block_hash: Optional[str] = None, gas_limit: Optional[int] = None):
|
|
27
|
+
# Immutable properties
|
|
28
|
+
self._caller = caller
|
|
29
|
+
self._timestamp = timestamp if timestamp is not None else time.time()
|
|
30
|
+
self._block_hash = block_hash if block_hash else self._generate_block_hash()
|
|
31
|
+
self._gas_limit = gas_limit if gas_limit is not None else 1_000_000
|
|
32
|
+
self._gas_used = 0
|
|
33
|
+
self._reverted = False
|
|
34
|
+
self._revert_reason = None
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def caller(self) -> str:
|
|
38
|
+
"""The address/ID of the entity executing the code"""
|
|
39
|
+
return self._caller
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def timestamp(self) -> float:
|
|
43
|
+
"""The canonical, un-tamperable time of execution"""
|
|
44
|
+
return self._timestamp
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def block_hash(self) -> str:
|
|
48
|
+
"""Cryptographic reference to the preceding state"""
|
|
49
|
+
return self._block_hash
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def gas_limit(self) -> int:
|
|
53
|
+
"""Maximum gas allowed for this transaction"""
|
|
54
|
+
return self._gas_limit
|
|
55
|
+
|
|
56
|
+
@gas_limit.setter
|
|
57
|
+
def gas_limit(self, value: int):
|
|
58
|
+
"""Set gas limit (can be changed during execution via LIMIT statement)"""
|
|
59
|
+
if value < 0:
|
|
60
|
+
raise ValueError("Gas limit cannot be negative")
|
|
61
|
+
self._gas_limit = value
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def gas_used(self) -> int:
|
|
65
|
+
"""Gas consumed so far"""
|
|
66
|
+
return self._gas_used
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def gas_remaining(self) -> int:
|
|
70
|
+
"""Remaining gas for execution"""
|
|
71
|
+
return max(0, self._gas_limit - self._gas_used)
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def reverted(self) -> bool:
|
|
75
|
+
"""Whether this transaction has been reverted"""
|
|
76
|
+
return self._reverted
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def revert_reason(self) -> Optional[str]:
|
|
80
|
+
"""Reason for revert (if reverted)"""
|
|
81
|
+
return self._revert_reason
|
|
82
|
+
|
|
83
|
+
def consume_gas(self, amount: int) -> bool:
|
|
84
|
+
"""
|
|
85
|
+
Consume gas for an operation
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
True if enough gas available, False otherwise
|
|
89
|
+
"""
|
|
90
|
+
if self._gas_used + amount > self._gas_limit:
|
|
91
|
+
return False
|
|
92
|
+
self._gas_used += amount
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
def revert(self, reason: Optional[str] = None):
|
|
96
|
+
"""Mark transaction as reverted"""
|
|
97
|
+
self._reverted = True
|
|
98
|
+
self._revert_reason = reason
|
|
99
|
+
|
|
100
|
+
def _generate_block_hash(self) -> str:
|
|
101
|
+
"""Generate a pseudo-random block hash"""
|
|
102
|
+
data = f"{self._caller}{self._timestamp}{secrets.token_hex(16)}"
|
|
103
|
+
return hashlib.sha256(data.encode()).hexdigest()
|
|
104
|
+
|
|
105
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
106
|
+
"""Convert TX context to dictionary"""
|
|
107
|
+
return {
|
|
108
|
+
'caller': self.caller,
|
|
109
|
+
'timestamp': self.timestamp,
|
|
110
|
+
'block_hash': self.block_hash,
|
|
111
|
+
'gas_limit': self.gas_limit,
|
|
112
|
+
'gas_used': self.gas_used,
|
|
113
|
+
'gas_remaining': self.gas_remaining,
|
|
114
|
+
'reverted': self.reverted,
|
|
115
|
+
'revert_reason': self.revert_reason
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
def __repr__(self):
|
|
119
|
+
return f"TX(caller={self.caller}, timestamp={self.timestamp}, gas={self.gas_remaining}/{self.gas_limit})"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class GasTracker:
|
|
123
|
+
"""
|
|
124
|
+
Gas consumption tracker for operations
|
|
125
|
+
|
|
126
|
+
Defines gas costs for different operations to prevent DoS attacks.
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
# Base gas costs (inspired by EVM gas model)
|
|
130
|
+
BASE_COSTS = {
|
|
131
|
+
# Storage operations
|
|
132
|
+
'ledger_write': 20_000,
|
|
133
|
+
'ledger_read': 200,
|
|
134
|
+
'state_write': 5_000,
|
|
135
|
+
'state_read': 200,
|
|
136
|
+
|
|
137
|
+
# Computation
|
|
138
|
+
'add': 3,
|
|
139
|
+
'sub': 3,
|
|
140
|
+
'mul': 5,
|
|
141
|
+
'div': 5,
|
|
142
|
+
'mod': 5,
|
|
143
|
+
'compare': 3,
|
|
144
|
+
|
|
145
|
+
# Control flow
|
|
146
|
+
'if': 10,
|
|
147
|
+
'loop': 10,
|
|
148
|
+
'function_call': 100,
|
|
149
|
+
'return': 10,
|
|
150
|
+
|
|
151
|
+
# Cryptography
|
|
152
|
+
'hash_sha256': 60,
|
|
153
|
+
'hash_keccak256': 30,
|
|
154
|
+
'signature_create': 3_000,
|
|
155
|
+
'signature_verify': 3_000,
|
|
156
|
+
|
|
157
|
+
# Memory
|
|
158
|
+
'memory_read': 3,
|
|
159
|
+
'memory_write': 3,
|
|
160
|
+
'memory_allocate': 100,
|
|
161
|
+
|
|
162
|
+
# Base operation
|
|
163
|
+
'base': 21_000,
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def get_cost(cls, operation: str, **kwargs) -> int:
|
|
168
|
+
"""
|
|
169
|
+
Get gas cost for an operation
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
operation: Operation name
|
|
173
|
+
**kwargs: Additional parameters (e.g., data_size for hashing)
|
|
174
|
+
|
|
175
|
+
Returns:
|
|
176
|
+
Gas cost
|
|
177
|
+
"""
|
|
178
|
+
base_cost = cls.BASE_COSTS.get(operation, 1)
|
|
179
|
+
|
|
180
|
+
# Adjust for data size if applicable
|
|
181
|
+
if 'data_size' in kwargs:
|
|
182
|
+
# Additional cost per 32 bytes
|
|
183
|
+
size = kwargs['data_size']
|
|
184
|
+
word_cost = (size + 31) // 32
|
|
185
|
+
base_cost += word_cost * 3
|
|
186
|
+
|
|
187
|
+
return base_cost
|
|
188
|
+
|
|
189
|
+
@classmethod
|
|
190
|
+
def estimate_limit(cls, action_name: str) -> int:
|
|
191
|
+
"""
|
|
192
|
+
Estimate reasonable gas limit for an action
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
Suggested gas limit
|
|
196
|
+
"""
|
|
197
|
+
# Default limits for common action types
|
|
198
|
+
limits = {
|
|
199
|
+
'transfer': 50_000,
|
|
200
|
+
'mint': 100_000,
|
|
201
|
+
'burn': 50_000,
|
|
202
|
+
'approve': 50_000,
|
|
203
|
+
'swap': 150_000,
|
|
204
|
+
'stake': 100_000,
|
|
205
|
+
'unstake': 100_000,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return limits.get(action_name, 1_000_000)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
# Transaction context stack (for nested calls)
|
|
212
|
+
_tx_stack = []
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def create_tx_context(caller: str, gas_limit: Optional[int] = None,
|
|
216
|
+
timestamp: Optional[float] = None,
|
|
217
|
+
block_hash: Optional[str] = None) -> TransactionContext:
|
|
218
|
+
"""Create a new transaction context"""
|
|
219
|
+
tx = TransactionContext(
|
|
220
|
+
caller=caller,
|
|
221
|
+
timestamp=timestamp,
|
|
222
|
+
block_hash=block_hash,
|
|
223
|
+
gas_limit=gas_limit
|
|
224
|
+
)
|
|
225
|
+
_tx_stack.append(tx)
|
|
226
|
+
return tx
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def get_current_tx() -> Optional[TransactionContext]:
|
|
230
|
+
"""Get the current transaction context"""
|
|
231
|
+
return _tx_stack[-1] if _tx_stack else None
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def end_tx_context():
|
|
235
|
+
"""End the current transaction context"""
|
|
236
|
+
if _tx_stack:
|
|
237
|
+
_tx_stack.pop()
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def consume_gas(amount: int, operation: str = "unknown") -> bool:
|
|
241
|
+
"""
|
|
242
|
+
Consume gas from current transaction
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
True if enough gas available, False otherwise
|
|
246
|
+
"""
|
|
247
|
+
tx = get_current_tx()
|
|
248
|
+
if not tx:
|
|
249
|
+
return True # No transaction context = no gas tracking
|
|
250
|
+
|
|
251
|
+
if not tx.consume_gas(amount):
|
|
252
|
+
# Out of gas!
|
|
253
|
+
tx.revert(f"Out of gas during operation: {operation}")
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
return True
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def check_gas_and_consume(operation: str, **kwargs) -> bool:
|
|
260
|
+
"""
|
|
261
|
+
Check if enough gas and consume it
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
True if successful, False if out of gas
|
|
265
|
+
"""
|
|
266
|
+
cost = GasTracker.get_cost(operation, **kwargs)
|
|
267
|
+
return consume_gas(cost, operation)
|