xian-tech-contracting 1.0.1__tar.gz

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 (47) hide show
  1. xian_tech_contracting-1.0.1/LICENSE +7 -0
  2. xian_tech_contracting-1.0.1/PKG-INFO +125 -0
  3. xian_tech_contracting-1.0.1/README.md +99 -0
  4. xian_tech_contracting-1.0.1/pyproject.toml +81 -0
  5. xian_tech_contracting-1.0.1/setup.cfg +4 -0
  6. xian_tech_contracting-1.0.1/src/contracting/__init__.py +0 -0
  7. xian_tech_contracting-1.0.1/src/contracting/client.py +389 -0
  8. xian_tech_contracting-1.0.1/src/contracting/compilation/__init__.py +0 -0
  9. xian_tech_contracting-1.0.1/src/contracting/compilation/compiler.py +155 -0
  10. xian_tech_contracting-1.0.1/src/contracting/compilation/linter.py +419 -0
  11. xian_tech_contracting-1.0.1/src/contracting/compilation/parser.py +55 -0
  12. xian_tech_contracting-1.0.1/src/contracting/compilation/whitelists.py +145 -0
  13. xian_tech_contracting-1.0.1/src/contracting/constants.py +54 -0
  14. xian_tech_contracting-1.0.1/src/contracting/contracts/__init__.py +0 -0
  15. xian_tech_contracting-1.0.1/src/contracting/contracts/proxythis.py +11 -0
  16. xian_tech_contracting-1.0.1/src/contracting/contracts/submission.s.py +108 -0
  17. xian_tech_contracting-1.0.1/src/contracting/contracts/thistest2.py +11 -0
  18. xian_tech_contracting-1.0.1/src/contracting/contracts/zk_registry.s.py +153 -0
  19. xian_tech_contracting-1.0.1/src/contracting/execution/__init__.py +0 -0
  20. xian_tech_contracting-1.0.1/src/contracting/execution/executor.py +235 -0
  21. xian_tech_contracting-1.0.1/src/contracting/execution/module.py +188 -0
  22. xian_tech_contracting-1.0.1/src/contracting/execution/native_tracer.py +139 -0
  23. xian_tech_contracting-1.0.1/src/contracting/execution/python_tracer.py +188 -0
  24. xian_tech_contracting-1.0.1/src/contracting/execution/runtime.py +428 -0
  25. xian_tech_contracting-1.0.1/src/contracting/execution/tracer.py +57 -0
  26. xian_tech_contracting-1.0.1/src/contracting/execution/tracer_common.py +282 -0
  27. xian_tech_contracting-1.0.1/src/contracting/names.py +26 -0
  28. xian_tech_contracting-1.0.1/src/contracting/stdlib/__init__.py +0 -0
  29. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/__init__.py +0 -0
  30. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/access.py +41 -0
  31. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/crypto.py +35 -0
  32. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/hashing.py +43 -0
  33. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/imports.py +337 -0
  34. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/orm.py +62 -0
  35. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/random.py +128 -0
  36. xian_tech_contracting-1.0.1/src/contracting/stdlib/bridge/zk.py +274 -0
  37. xian_tech_contracting-1.0.1/src/contracting/stdlib/env.py +33 -0
  38. xian_tech_contracting-1.0.1/src/contracting/storage/__init__.py +0 -0
  39. xian_tech_contracting-1.0.1/src/contracting/storage/contract.py +115 -0
  40. xian_tech_contracting-1.0.1/src/contracting/storage/driver.py +390 -0
  41. xian_tech_contracting-1.0.1/src/contracting/storage/lmdb_store.py +137 -0
  42. xian_tech_contracting-1.0.1/src/contracting/storage/orm.py +428 -0
  43. xian_tech_contracting-1.0.1/src/xian_tech_contracting.egg-info/PKG-INFO +125 -0
  44. xian_tech_contracting-1.0.1/src/xian_tech_contracting.egg-info/SOURCES.txt +45 -0
  45. xian_tech_contracting-1.0.1/src/xian_tech_contracting.egg-info/dependency_links.txt +1 -0
  46. xian_tech_contracting-1.0.1/src/xian_tech_contracting.egg-info/requires.txt +11 -0
  47. xian_tech_contracting-1.0.1/src/xian_tech_contracting.egg-info/top_level.txt +1 -0
@@ -0,0 +1,7 @@
1
+ Creative Commons Attribution‑NonCommercial 4.0 International
2
+
3
+ Copyright © 2025 XIAN.org
4
+
5
+ This work is licensed under CC BY‑NC 4.0.
6
+ You may copy, modify, and share it **for non‑commercial purposes only**, provided that you give appropriate credit.
7
+ Full legal text: https://creativecommons.org/licenses/by-nc/4.0/legalcode
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: xian-tech-contracting
3
+ Version: 1.0.1
4
+ Summary: Xian Network Python Contracting Engine
5
+ Author-email: Xian Network <info@xian.org>
6
+ License-Expression: GPL-3.0-only
7
+ Project-URL: Repository, https://github.com/xian-technology/xian-contracting
8
+ Keywords: blockchain,xian,contracting,python
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Classifier: Programming Language :: Python :: 3.14
12
+ Classifier: Development Status :: 5 - Production/Stable
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: autopep8<2,>=1.5.7
17
+ Requires-Dist: cachetools<8,>=5
18
+ Requires-Dist: lmdb<2,>=1.6
19
+ Requires-Dist: pynacl<2,>=1.5.0
20
+ Requires-Dist: xian-tech-runtime-types<0.2,>=0.1.0
21
+ Provides-Extra: native
22
+ Requires-Dist: xian-tech-native-tracer<0.2,>=0.1.0; extra == "native"
23
+ Provides-Extra: zk
24
+ Requires-Dist: xian-tech-zk<0.2,>=0.1.0; extra == "zk"
25
+ Dynamic: license-file
26
+
27
+ # xian-contracting
28
+
29
+ `xian-contracting` is the Python contract runtime for Xian. It owns contract
30
+ compilation, secure execution, storage semantics, metering, and the runtime
31
+ rules that contracts must obey.
32
+
33
+ ## Quick Start
34
+
35
+ Install the runtime:
36
+
37
+ ```bash
38
+ pip install xian-tech-contracting
39
+ ```
40
+
41
+ If you want contract-side zk proof verification, install the optional zk
42
+ backend too:
43
+
44
+ ```bash
45
+ pip install 'xian-tech-contracting[zk]'
46
+ ```
47
+
48
+ The published PyPI package name is `xian-tech-contracting`. The repo name
49
+ remains `xian-contracting`, and the import surface remains `contracting`.
50
+
51
+ Submit and call a contract:
52
+
53
+ ```python
54
+ from contracting.client import ContractingClient
55
+
56
+ client = ContractingClient()
57
+ client.submit(name="con_token", code=contract_source)
58
+ token = client.get_contract("con_token")
59
+ token.transfer(amount=100, to="bob")
60
+ ```
61
+
62
+ Access storage directly:
63
+
64
+ ```python
65
+ from contracting.storage.driver import Driver
66
+
67
+ driver = Driver()
68
+ driver.set("example.key", "value")
69
+ print(driver.get("example.key"))
70
+ ```
71
+
72
+ ## Principles
73
+
74
+ - Contracts use Python syntax, but execution rules are consensus-sensitive and
75
+ intentionally narrower than general Python.
76
+ - Metering, storage encoding, import restrictions, and runtime helpers must
77
+ stay version-aligned across validators.
78
+ - Optional native tracing is an implementation detail. The contract model and
79
+ runtime rules should remain understandable without it.
80
+ - Built-in helpers should serve the execution model, not grow into a general
81
+ convenience framework.
82
+
83
+ ## Key Directories
84
+
85
+ - `src/contracting/`: runtime, storage, compilation, and stdlib bridge code
86
+ - `packages/`: shared packages such as `xian-runtime-types`, `xian-accounts`,
87
+ the native tracer, and `xian-zk`
88
+ - `tests/`: unit, integration, and security coverage
89
+ - `docs/`: architecture, backlog, and execution notes
90
+
91
+ ## What It Covers
92
+
93
+ - compilation and linting
94
+ - runtime execution and metering
95
+ - storage drivers and encoding
96
+ - contract-side runtime helpers
97
+ - optional native tracing backend
98
+ - native zero-knowledge verifier building blocks
99
+
100
+ ## Validation
101
+
102
+ ```bash
103
+ uv sync --group dev
104
+ uv run ruff check .
105
+ uv run ruff format --check .
106
+ uv run pytest
107
+ ```
108
+
109
+ If you change the zk runtime surface or the native verifier package, run:
110
+
111
+ ```bash
112
+ uv sync --group dev --extra zk
113
+ uv run --extra zk pytest -q tests/unit/test_zk_stdlib.py tests/integration/test_zk_bridge.py
114
+ cd packages/xian-zk && uv sync --group dev && uv run maturin develop && uv run pytest -q
115
+ ```
116
+
117
+ If you change metering, tracing, storage encoding, or import restrictions, run
118
+ the relevant `tests/security/` and `tests/integration/` paths explicitly too.
119
+
120
+ ## Related Docs
121
+
122
+ - [AGENTS.md](AGENTS.md)
123
+ - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
124
+ - [docs/BACKLOG.md](docs/BACKLOG.md)
125
+ - [docs/README.md](docs/README.md)
@@ -0,0 +1,99 @@
1
+ # xian-contracting
2
+
3
+ `xian-contracting` is the Python contract runtime for Xian. It owns contract
4
+ compilation, secure execution, storage semantics, metering, and the runtime
5
+ rules that contracts must obey.
6
+
7
+ ## Quick Start
8
+
9
+ Install the runtime:
10
+
11
+ ```bash
12
+ pip install xian-tech-contracting
13
+ ```
14
+
15
+ If you want contract-side zk proof verification, install the optional zk
16
+ backend too:
17
+
18
+ ```bash
19
+ pip install 'xian-tech-contracting[zk]'
20
+ ```
21
+
22
+ The published PyPI package name is `xian-tech-contracting`. The repo name
23
+ remains `xian-contracting`, and the import surface remains `contracting`.
24
+
25
+ Submit and call a contract:
26
+
27
+ ```python
28
+ from contracting.client import ContractingClient
29
+
30
+ client = ContractingClient()
31
+ client.submit(name="con_token", code=contract_source)
32
+ token = client.get_contract("con_token")
33
+ token.transfer(amount=100, to="bob")
34
+ ```
35
+
36
+ Access storage directly:
37
+
38
+ ```python
39
+ from contracting.storage.driver import Driver
40
+
41
+ driver = Driver()
42
+ driver.set("example.key", "value")
43
+ print(driver.get("example.key"))
44
+ ```
45
+
46
+ ## Principles
47
+
48
+ - Contracts use Python syntax, but execution rules are consensus-sensitive and
49
+ intentionally narrower than general Python.
50
+ - Metering, storage encoding, import restrictions, and runtime helpers must
51
+ stay version-aligned across validators.
52
+ - Optional native tracing is an implementation detail. The contract model and
53
+ runtime rules should remain understandable without it.
54
+ - Built-in helpers should serve the execution model, not grow into a general
55
+ convenience framework.
56
+
57
+ ## Key Directories
58
+
59
+ - `src/contracting/`: runtime, storage, compilation, and stdlib bridge code
60
+ - `packages/`: shared packages such as `xian-runtime-types`, `xian-accounts`,
61
+ the native tracer, and `xian-zk`
62
+ - `tests/`: unit, integration, and security coverage
63
+ - `docs/`: architecture, backlog, and execution notes
64
+
65
+ ## What It Covers
66
+
67
+ - compilation and linting
68
+ - runtime execution and metering
69
+ - storage drivers and encoding
70
+ - contract-side runtime helpers
71
+ - optional native tracing backend
72
+ - native zero-knowledge verifier building blocks
73
+
74
+ ## Validation
75
+
76
+ ```bash
77
+ uv sync --group dev
78
+ uv run ruff check .
79
+ uv run ruff format --check .
80
+ uv run pytest
81
+ ```
82
+
83
+ If you change the zk runtime surface or the native verifier package, run:
84
+
85
+ ```bash
86
+ uv sync --group dev --extra zk
87
+ uv run --extra zk pytest -q tests/unit/test_zk_stdlib.py tests/integration/test_zk_bridge.py
88
+ cd packages/xian-zk && uv sync --group dev && uv run maturin develop && uv run pytest -q
89
+ ```
90
+
91
+ If you change metering, tracing, storage encoding, or import restrictions, run
92
+ the relevant `tests/security/` and `tests/integration/` paths explicitly too.
93
+
94
+ ## Related Docs
95
+
96
+ - [AGENTS.md](AGENTS.md)
97
+ - [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
98
+ - [docs/BACKLOG.md](docs/BACKLOG.md)
99
+ - [docs/README.md](docs/README.md)
@@ -0,0 +1,81 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "xian-tech-contracting"
7
+ version = "1.0.1"
8
+ description = "Xian Network Python Contracting Engine"
9
+ readme = "README.md"
10
+ license = "GPL-3.0-only"
11
+ authors = [{ name = "Xian Network", email = "info@xian.org" }]
12
+ requires-python = ">=3.12"
13
+ dependencies = [
14
+ "autopep8>=1.5.7,<2",
15
+ "cachetools>=5,<8",
16
+ "lmdb>=1.6,<2",
17
+ "pynacl>=1.5.0,<2",
18
+ "xian-tech-runtime-types>=0.1.0,<0.2",
19
+ ]
20
+ keywords = ["blockchain", "xian", "contracting", "python"]
21
+ classifiers = [
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Development Status :: 5 - Production/Stable",
26
+ ]
27
+
28
+ [project.urls]
29
+ Repository = "https://github.com/xian-technology/xian-contracting"
30
+
31
+ [project.optional-dependencies]
32
+ native = [
33
+ "xian-tech-native-tracer>=0.1.0,<0.2",
34
+ ]
35
+ zk = [
36
+ "xian-tech-zk>=0.1.0,<0.2",
37
+ ]
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pytest>=9.0.2,<10",
42
+ "pytest-cov>=7.0.0,<8",
43
+ "ruff>=0.15.6,<0.16",
44
+ ]
45
+
46
+ [tool.setuptools]
47
+ package-dir = {"" = "src"}
48
+ include-package-data = true
49
+
50
+ [tool.setuptools.packages.find]
51
+ where = ["src"]
52
+
53
+ [tool.setuptools.package-data]
54
+ contracting = ["contracts/*.s.py"]
55
+
56
+ [tool.pytest.ini_options]
57
+ testpaths = ["tests"]
58
+
59
+ [tool.ruff]
60
+ line-length = 80
61
+ target-version = "py312"
62
+ exclude = [
63
+ "examples",
64
+ "tests/integration/test_contracts",
65
+ "tests",
66
+ "tests/performance/test_contracts",
67
+ "tests/security/contracts",
68
+ "tests/unit/contracts",
69
+ "tests/unit/precompiled",
70
+ "tests/unit/test_sys_contracts",
71
+ "src/contracting/contracts",
72
+ ]
73
+
74
+ [tool.ruff.lint]
75
+ select = ["E", "F", "I"]
76
+ ignore = ["E501"]
77
+
78
+ [tool.uv.sources]
79
+ xian-tech-runtime-types = { path = "packages/xian-runtime-types", editable = true }
80
+ xian-tech-native-tracer = { path = "packages/xian-native-tracer", editable = true }
81
+ xian-tech-zk = { path = "packages/xian-zk", editable = true }
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,389 @@
1
+ import ast
2
+ import inspect
3
+ import os
4
+ from datetime import datetime
5
+ from functools import partial
6
+ from types import FunctionType
7
+
8
+ import autopep8
9
+ from xian_runtime_types.time import Datetime
10
+
11
+ from contracting.compilation.compiler import ContractingCompiler
12
+ from contracting.execution import runtime
13
+ from contracting.execution.executor import Executor
14
+ from contracting.storage.driver import Driver
15
+
16
+ from . import constants
17
+ from .storage.orm import Hash, Variable
18
+
19
+
20
+ class AbstractContract:
21
+ def __init__(
22
+ self,
23
+ name,
24
+ signer,
25
+ environment,
26
+ executor: Executor,
27
+ funcs,
28
+ return_full_output=False,
29
+ ):
30
+ self.name = name
31
+ self.signer = signer
32
+ self.environment = environment
33
+ self.executor = executor
34
+ self.functions = funcs
35
+
36
+ # set up virtual functions
37
+ for f in funcs:
38
+ # unpack tuple packed in SenecaClient
39
+ func, kwargs = f
40
+
41
+ # set the kwargs to None. these will fail if they are not provided
42
+ default_kwargs = {}
43
+ for kwarg in kwargs:
44
+ default_kwargs[kwarg] = None
45
+
46
+ # each function is a partial that allows kwarg overloading and overriding
47
+ setattr(
48
+ self,
49
+ func,
50
+ partial(
51
+ self._abstract_function_call,
52
+ signer=self.signer,
53
+ contract_name=self.name,
54
+ executor=self.executor,
55
+ func=func,
56
+ return_full_output=return_full_output,
57
+ # environment=self.environment,
58
+ **default_kwargs,
59
+ ),
60
+ )
61
+
62
+ def keys(self):
63
+ # Scope strictly to this contract's namespace
64
+ return self.executor.driver.keys(f"{self.name}.")
65
+
66
+ # a variable contains a DOT, but no __, and no :
67
+ # a hash contains a DOT, no __, and a :
68
+ # a constant contains __, a DOT, and :
69
+
70
+ def quick_read(self, variable, key=None, args=None):
71
+ a = []
72
+
73
+ if key is not None:
74
+ a.append(key)
75
+
76
+ if args is not None and isinstance(args, list):
77
+ for arg in args:
78
+ a.append(arg)
79
+
80
+ k = self.executor.driver.make_key(
81
+ contract=self.name, variable=variable, args=a
82
+ )
83
+ return self.executor.driver.get(k)
84
+
85
+ def quick_write(self, variable, key=None, value=None, args=None):
86
+ if key is not None:
87
+ a = [key]
88
+ else:
89
+ a = []
90
+
91
+ if args is not None and isinstance(args, list):
92
+ for arg in args:
93
+ a.append(arg)
94
+
95
+ k = self.executor.driver.make_key(
96
+ contract=self.name, variable=variable, args=a
97
+ )
98
+
99
+ self.executor.driver.set(k, value)
100
+ self.executor.driver.commit()
101
+
102
+ def run_private_function(self, f, signer=None, environment=None, **kwargs):
103
+ # Override kwargs if provided
104
+ signer = signer or self.signer
105
+ environment = environment or self.environment
106
+
107
+ # Let executor access private functions
108
+ self.executor.bypass_privates = True
109
+
110
+ try:
111
+ # Append private method prefix to function name if it isn't there already
112
+ if not f.startswith(constants.PRIVATE_METHOD_PREFIX):
113
+ f = "{}{}".format(constants.PRIVATE_METHOD_PREFIX, f)
114
+
115
+ return self._abstract_function_call(
116
+ signer=signer,
117
+ executor=self.executor,
118
+ contract_name=self.name,
119
+ environment=environment,
120
+ func=f,
121
+ metering=None,
122
+ now=None,
123
+ **kwargs,
124
+ )
125
+ finally:
126
+ # Always restore restricted mode, even if the private call fails.
127
+ self.executor.bypass_privates = False
128
+
129
+ def __getattr__(self, item):
130
+ try:
131
+ # return the attribute if it exists on the instance
132
+ return self.__getattribute__(item)
133
+ except AttributeError as e:
134
+ # otherwise, attempt to resolve it. full name is contract.item
135
+ fullname = "{}.{}".format(self.name, item)
136
+
137
+ # if the raw name exists, it is a __protected__ or a variable, so prepare for those
138
+ if fullname in self.keys():
139
+ variable = Variable(
140
+ contract=self.name, name=item, driver=self.executor.driver
141
+ )
142
+
143
+ # return just the value if it is __protected__ to prevent sets
144
+ if item.startswith("__"):
145
+ return variable.get()
146
+
147
+ # otherwise, return the variable object with allows sets
148
+ return variable
149
+
150
+ # otherwise, see if contract.items: has more than one entry
151
+ if (
152
+ len(
153
+ self.executor.driver.values(
154
+ prefix=self.name + "." + item + ":"
155
+ )
156
+ )
157
+ > 0
158
+ ):
159
+ # if so, it is a hash. return the hash object
160
+ return Hash(
161
+ contract=self.name, name=item, driver=self.executor.driver
162
+ )
163
+
164
+ # otherwise, the attribut does not exist, so throw the error.
165
+ raise e
166
+
167
+ def now(self):
168
+ d = datetime.today()
169
+ return Datetime(d.year, d.month, d.day, hour=d.hour, minute=d.minute)
170
+
171
+ def _abstract_function_call(
172
+ self,
173
+ signer,
174
+ executor,
175
+ contract_name,
176
+ func,
177
+ environment=None,
178
+ stamps=constants.DEFAULT_STAMPS,
179
+ metering=None,
180
+ now=None,
181
+ return_full_output=False,
182
+ **kwargs,
183
+ ):
184
+
185
+ # for k, v in kwargs.items():
186
+ # assert v is not None, 'Keyword "{}" not provided. Must not be None.'.format(k)
187
+ environment = environment or self.environment
188
+
189
+ if now is None:
190
+ now = self.now()
191
+
192
+ if environment.get("now") is None:
193
+ environment.update({"now": now})
194
+
195
+ output = executor.execute(
196
+ sender=signer,
197
+ contract_name=contract_name,
198
+ function_name=func,
199
+ kwargs=kwargs,
200
+ stamps=stamps,
201
+ environment=environment,
202
+ metering=metering,
203
+ )
204
+
205
+ if executor.production:
206
+ executor.sandbox.terminate()
207
+
208
+ if output["status_code"] == 1:
209
+ raise output["result"] if not return_full_output else output
210
+ return output["result"] if not return_full_output else output
211
+
212
+
213
+ class ContractingClient:
214
+ def __init__(
215
+ self,
216
+ signer="sys",
217
+ submission_filename=os.path.join(
218
+ os.path.dirname(__file__), "contracts/submission.s.py"
219
+ ),
220
+ storage_home=constants.STORAGE_HOME,
221
+ driver: Driver = None,
222
+ metering=False,
223
+ compiler=ContractingCompiler(),
224
+ environment={},
225
+ tracer_mode: str | None = None,
226
+ ):
227
+ if tracer_mode is not None:
228
+ runtime.rt.set_tracer_mode(tracer_mode)
229
+ driver = (
230
+ driver if driver is not None else Driver(storage_home=storage_home)
231
+ )
232
+ self.executor = Executor(metering=metering, driver=driver)
233
+ self.raw_driver = driver
234
+ self.signer = signer
235
+ self.compiler = compiler
236
+ self.submission_filename = submission_filename
237
+ self.environment = environment
238
+ # Get submission contract from file
239
+ if submission_filename is not None:
240
+ # Seed the genesis contracts into the instance
241
+ with open(self.submission_filename) as f:
242
+ contract = f.read()
243
+
244
+ self.raw_driver.set_contract(name="submission", code=contract)
245
+ self.raw_driver.commit()
246
+
247
+ # Get submission contract from state
248
+ self.submission_contract = self.get_contract("submission")
249
+
250
+ def set_submission_contract(self, filename=None, commit=True):
251
+ state_contract = self.get_contract("submission")
252
+
253
+ if filename is None:
254
+ filename = self.submission_filename
255
+
256
+ if filename is None and state_contract is None:
257
+ raise AssertionError(
258
+ "No submission contract provided or found in state."
259
+ )
260
+
261
+ if filename is not None:
262
+ with open(filename) as f:
263
+ contract = f.read()
264
+
265
+ self.raw_driver.delete_contract(name="submission")
266
+ self.raw_driver.set_contract(name="submission", code=contract)
267
+
268
+ if commit:
269
+ self.raw_driver.commit()
270
+
271
+ self.submission_contract = self.get_contract("submission")
272
+
273
+ def flush(self):
274
+ # flushes storage and resubmits genesis contracts
275
+ self.raw_driver.flush_full()
276
+ self.raw_driver.flush_cache()
277
+
278
+ if self.submission_filename is not None:
279
+ self.set_submission_contract()
280
+
281
+ # Returns abstract contract which has partial methods mapped to each exported function.
282
+ def get_contract(self, name):
283
+ contract = self.raw_driver.get_contract(name)
284
+
285
+ if contract is None:
286
+ return None
287
+
288
+ tree = ast.parse(contract)
289
+
290
+ function_defs = [
291
+ n for n in ast.walk(tree) if isinstance(n, ast.FunctionDef)
292
+ ]
293
+
294
+ funcs = []
295
+ for definition in function_defs:
296
+ func_name = definition.name
297
+ kwargs = [arg.arg for arg in definition.args.args]
298
+
299
+ funcs.append((func_name, kwargs))
300
+
301
+ return AbstractContract(
302
+ name=name,
303
+ signer=self.signer,
304
+ environment=self.environment,
305
+ executor=self.executor,
306
+ funcs=funcs,
307
+ )
308
+
309
+ def closure_to_code_string(self, f):
310
+ closure_code = inspect.getsource(f)
311
+ closure_code = autopep8.fix_code(closure_code)
312
+ closure_tree = ast.parse(closure_code)
313
+
314
+ # Remove the enclosing function by swapping out the function def node with its children
315
+ assert len(closure_tree.body) == 1, "Module has multiple body nodes."
316
+ assert isinstance(closure_tree.body[0], ast.FunctionDef), (
317
+ "Function definition not found at root."
318
+ )
319
+
320
+ func_def_body = closure_tree.body[0]
321
+ closure_tree.body = func_def_body.body
322
+
323
+ contract_code = ast.unparse(closure_tree)
324
+ name = func_def_body.name
325
+
326
+ return contract_code, name
327
+
328
+ def lint(self, f, raise_errors=False):
329
+ if isinstance(f, FunctionType):
330
+ f, _ = self.closure_to_code_string(f)
331
+
332
+ if raise_errors:
333
+ self.compiler.linter.check_raise(f)
334
+ return None
335
+
336
+ return self.compiler.linter.check(f)
337
+
338
+ def compile(self, f):
339
+ if isinstance(f, FunctionType):
340
+ f, _ = self.closure_to_code_string(f)
341
+
342
+ code = self.compiler.parse_to_code(f)
343
+ return code
344
+
345
+ def submit(
346
+ self,
347
+ f,
348
+ name=None,
349
+ metering=None,
350
+ owner=None,
351
+ constructor_args={},
352
+ signer=None,
353
+ ):
354
+
355
+ assert self.submission_contract is not None, (
356
+ "No submission contract set. Try set_submission_contract first."
357
+ )
358
+
359
+ if isinstance(f, FunctionType):
360
+ f, n = self.closure_to_code_string(f)
361
+ if name is None:
362
+ name = n
363
+
364
+ assert name is not None, "No name provided."
365
+
366
+ if signer is None:
367
+ signer = self.signer
368
+
369
+ self.submission_contract.submit_contract(
370
+ name=name,
371
+ code=f,
372
+ owner=owner,
373
+ constructor_args=constructor_args,
374
+ metering=metering,
375
+ signer=signer,
376
+ )
377
+
378
+ def get_contracts(self):
379
+ contracts = []
380
+ for key in self.raw_driver.keys():
381
+ if key.endswith(".__code__"):
382
+ contracts.append(key.replace(".__code__", ""))
383
+ return contracts
384
+
385
+ def get_var(self, contract, variable, arguments=[], mark=False):
386
+ return self.raw_driver.get_var(contract, variable, arguments, mark)
387
+
388
+ def set_var(self, contract, variable, arguments=[], value=None, mark=False):
389
+ self.raw_driver.set_var(contract, variable, arguments, value, mark)