web3 7.0.0b1__py3-none-any.whl → 7.0.0b3__py3-none-any.whl
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.
- ens/async_ens.py +6 -8
- ens/ens.py +6 -6
- ens/utils.py +18 -16
- web3/_utils/abi.py +9 -15
- web3/_utils/events.py +15 -6
- web3/_utils/math.py +12 -14
- web3/_utils/method_formatters.py +7 -0
- web3/_utils/module_testing/eth_module.py +67 -6
- web3/_utils/module_testing/module_testing_utils.py +2 -2
- web3/_utils/request.py +1 -1
- web3/_utils/rpc_abi.py +1 -0
- web3/_utils/transactions.py +4 -0
- web3/contract/base_contract.py +1 -1
- web3/datastructures.py +7 -7
- web3/eth/async_eth.py +20 -2
- web3/eth/eth.py +13 -1
- web3/exceptions.py +11 -0
- web3/main.py +4 -30
- web3/manager.py +12 -13
- web3/middleware/__init__.py +9 -8
- web3/module.py +1 -1
- web3/providers/async_base.py +6 -6
- web3/providers/base.py +8 -8
- web3/providers/eth_tester/main.py +16 -20
- web3/providers/ipc.py +1 -1
- web3/providers/legacy_websocket.py +1 -1
- web3/providers/persistent/persistent.py +2 -2
- web3/providers/persistent/request_processor.py +3 -5
- web3/tools/benchmark/main.py +2 -2
- web3/types.py +4 -0
- web3/utils/caching.py +2 -4
- {web3-7.0.0b1.dist-info → web3-7.0.0b3.dist-info}/METADATA +3 -9
- web3-7.0.0b3.dist-info/RECORD +168 -0
- {web3-7.0.0b1.dist-info → web3-7.0.0b3.dist-info}/WHEEL +1 -1
- {web3-7.0.0b1.dist-info → web3-7.0.0b3.dist-info}/top_level.txt +0 -1
- ethpm/__init__.py +0 -20
- ethpm/_utils/__init__.py +0 -0
- ethpm/_utils/backend.py +0 -93
- ethpm/_utils/cache.py +0 -44
- ethpm/_utils/chains.py +0 -119
- ethpm/_utils/contract.py +0 -35
- ethpm/_utils/deployments.py +0 -145
- ethpm/_utils/ipfs.py +0 -116
- ethpm/_utils/protobuf/__init__.py +0 -0
- ethpm/_utils/protobuf/ipfs_file_pb2.py +0 -33
- ethpm/_utils/registry.py +0 -29
- ethpm/assets/__init__.py +0 -0
- ethpm/assets/ens/v3.json +0 -1
- ethpm/assets/escrow/with_bytecode_v3.json +0 -1
- ethpm/assets/ipfs_file.proto +0 -32
- ethpm/assets/owned/output_v3.json +0 -1
- ethpm/assets/owned/with_contract_type_v3.json +0 -1
- ethpm/assets/registry/contracts/Authority.sol +0 -156
- ethpm/assets/registry/contracts/IndexedOrderedSetLib.sol +0 -106
- ethpm/assets/registry/contracts/PackageDB.sol +0 -225
- ethpm/assets/registry/contracts/PackageRegistry.sol +0 -361
- ethpm/assets/registry/contracts/PackageRegistryInterface.sol +0 -97
- ethpm/assets/registry/contracts/ReleaseDB.sol +0 -309
- ethpm/assets/registry/contracts/ReleaseValidator.sol +0 -152
- ethpm/assets/registry/solc_input.json +0 -1
- ethpm/assets/registry/solc_output.json +0 -1
- ethpm/assets/registry/v3.json +0 -1
- ethpm/assets/safe-math-lib/v3-strict-no-deployments.json +0 -1
- ethpm/assets/simple-registry/contracts/Ownable.sol +0 -63
- ethpm/assets/simple-registry/contracts/PackageRegistry.sol +0 -373
- ethpm/assets/simple-registry/contracts/PackageRegistryInterface.sol +0 -96
- ethpm/assets/simple-registry/solc_input.json +0 -33
- ethpm/assets/simple-registry/solc_output.json +0 -1
- ethpm/assets/simple-registry/v3.json +0 -1
- ethpm/assets/standard-token/output_v3.json +0 -1
- ethpm/assets/standard-token/with_bytecode_v3.json +0 -1
- ethpm/assets/vyper_registry/0.1.0.json +0 -1
- ethpm/assets/vyper_registry/registry.vy +0 -216
- ethpm/assets/vyper_registry/registry_with_delete.vy +0 -244
- ethpm/backends/__init__.py +0 -0
- ethpm/backends/base.py +0 -43
- ethpm/backends/http.py +0 -108
- ethpm/backends/ipfs.py +0 -219
- ethpm/backends/registry.py +0 -154
- ethpm/constants.py +0 -17
- ethpm/contract.py +0 -187
- ethpm/dependencies.py +0 -58
- ethpm/deployments.py +0 -80
- ethpm/ethpm-spec/examples/escrow/1.0.0-pretty.json +0 -146
- ethpm/ethpm-spec/examples/escrow/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/escrow/contracts/Escrow.sol +0 -32
- ethpm/ethpm-spec/examples/escrow/contracts/SafeSendLib.sol +0 -20
- ethpm/ethpm-spec/examples/escrow/v3-pretty.json +0 -171
- ethpm/ethpm-spec/examples/escrow/v3.json +0 -1
- ethpm/ethpm-spec/examples/owned/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/owned/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/owned/contracts/Owned.sol +0 -12
- ethpm/ethpm-spec/examples/owned/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/owned/v3.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/1.0.0-pretty.json +0 -31
- ethpm/ethpm-spec/examples/piper-coin/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/piper-coin/v3-pretty.json +0 -21
- ethpm/ethpm-spec/examples/piper-coin/v3.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0-pretty.json +0 -85
- ethpm/ethpm-spec/examples/safe-math-lib/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/safe-math-lib/contracts/SafeMathLib.sol +0 -24
- ethpm/ethpm-spec/examples/safe-math-lib/v3-pretty.json +0 -117
- ethpm/ethpm-spec/examples/safe-math-lib/v3.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/1.0.0-pretty.json +0 -55
- ethpm/ethpm-spec/examples/standard-token/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/standard-token/contracts/AbstractToken.sol +0 -20
- ethpm/ethpm-spec/examples/standard-token/contracts/StandardToken.sol +0 -84
- ethpm/ethpm-spec/examples/standard-token/v3-pretty.json +0 -460
- ethpm/ethpm-spec/examples/standard-token/v3.json +0 -1
- ethpm/ethpm-spec/examples/transferable/1.0.0-pretty.json +0 -21
- ethpm/ethpm-spec/examples/transferable/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/transferable/contracts/Transferable.sol +0 -14
- ethpm/ethpm-spec/examples/transferable/v3-pretty.json +0 -27
- ethpm/ethpm-spec/examples/transferable/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet/1.0.0-pretty.json +0 -120
- ethpm/ethpm-spec/examples/wallet/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet/contracts/Wallet.sol +0 -41
- ethpm/ethpm-spec/examples/wallet/v3-pretty.json +0 -181
- ethpm/ethpm-spec/examples/wallet/v3.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0-pretty.json +0 -135
- ethpm/ethpm-spec/examples/wallet-with-send/1.0.0.json +0 -1
- ethpm/ethpm-spec/examples/wallet-with-send/contracts/WalletWithSend.sol +0 -18
- ethpm/ethpm-spec/examples/wallet-with-send/v3-pretty.json +0 -207
- ethpm/ethpm-spec/examples/wallet-with-send/v3.json +0 -1
- ethpm/ethpm-spec/spec/package.spec.json +0 -379
- ethpm/ethpm-spec/spec/v3.spec.json +0 -483
- ethpm/exceptions.py +0 -68
- ethpm/package.py +0 -438
- ethpm/tools/__init__.py +0 -4
- ethpm/tools/builder.py +0 -930
- ethpm/tools/checker.py +0 -312
- ethpm/tools/get_manifest.py +0 -19
- ethpm/uri.py +0 -141
- ethpm/validation/__init__.py +0 -0
- ethpm/validation/manifest.py +0 -146
- ethpm/validation/misc.py +0 -39
- ethpm/validation/package.py +0 -80
- ethpm/validation/uri.py +0 -163
- web3/pm.py +0 -602
- web3/tools/__init__.py +0 -4
- web3/tools/pytest_ethereum/__init__.py +0 -0
- web3/tools/pytest_ethereum/_utils.py +0 -145
- web3/tools/pytest_ethereum/deployer.py +0 -48
- web3/tools/pytest_ethereum/exceptions.py +0 -22
- web3/tools/pytest_ethereum/linker.py +0 -128
- web3/tools/pytest_ethereum/plugins.py +0 -33
- web3-7.0.0b1.dist-info/RECORD +0 -280
- web3-7.0.0b1.dist-info/entry_points.txt +0 -2
- {web3-7.0.0b1.dist-info → web3-7.0.0b3.dist-info}/LICENSE +0 -0
ethpm/tools/builder.py
DELETED
|
@@ -1,930 +0,0 @@
|
|
|
1
|
-
import functools
|
|
2
|
-
import json
|
|
3
|
-
from pathlib import (
|
|
4
|
-
Path,
|
|
5
|
-
)
|
|
6
|
-
import tempfile
|
|
7
|
-
from typing import (
|
|
8
|
-
TYPE_CHECKING,
|
|
9
|
-
Any,
|
|
10
|
-
Callable,
|
|
11
|
-
Dict,
|
|
12
|
-
Iterable,
|
|
13
|
-
List,
|
|
14
|
-
Optional,
|
|
15
|
-
Set,
|
|
16
|
-
Tuple,
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
from eth_typing import (
|
|
20
|
-
URI,
|
|
21
|
-
HexStr,
|
|
22
|
-
Manifest,
|
|
23
|
-
)
|
|
24
|
-
from eth_utils import (
|
|
25
|
-
add_0x_prefix,
|
|
26
|
-
is_hex,
|
|
27
|
-
is_string,
|
|
28
|
-
to_bytes,
|
|
29
|
-
to_checksum_address,
|
|
30
|
-
to_dict,
|
|
31
|
-
to_list,
|
|
32
|
-
)
|
|
33
|
-
from eth_utils.toolz import (
|
|
34
|
-
assoc,
|
|
35
|
-
assoc_in,
|
|
36
|
-
concat,
|
|
37
|
-
curry,
|
|
38
|
-
pipe,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
from ethpm import (
|
|
42
|
-
Package,
|
|
43
|
-
)
|
|
44
|
-
from ethpm._utils.chains import (
|
|
45
|
-
is_BIP122_block_uri,
|
|
46
|
-
)
|
|
47
|
-
from ethpm.backends.ipfs import (
|
|
48
|
-
BaseIPFSBackend,
|
|
49
|
-
)
|
|
50
|
-
from ethpm.exceptions import (
|
|
51
|
-
EthPMValidationError,
|
|
52
|
-
ManifestBuildingError,
|
|
53
|
-
)
|
|
54
|
-
from ethpm.package import (
|
|
55
|
-
format_manifest,
|
|
56
|
-
)
|
|
57
|
-
from ethpm.uri import (
|
|
58
|
-
is_supported_content_addressed_uri,
|
|
59
|
-
)
|
|
60
|
-
from ethpm.validation.manifest import (
|
|
61
|
-
validate_manifest_against_schema,
|
|
62
|
-
)
|
|
63
|
-
from ethpm.validation.package import (
|
|
64
|
-
validate_package_name,
|
|
65
|
-
)
|
|
66
|
-
from web3._utils.validation import (
|
|
67
|
-
validate_address,
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if TYPE_CHECKING:
|
|
71
|
-
from web3 import Web3 # noqa: F401
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def build(obj: Dict[str, Any], *fns: Callable[..., Any]) -> Dict[str, Any]:
|
|
75
|
-
"""
|
|
76
|
-
Wrapper function to pipe manifest through build functions.
|
|
77
|
-
Does not validate the manifest by default.
|
|
78
|
-
"""
|
|
79
|
-
return pipe(obj, *fns)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
#
|
|
83
|
-
# Required Fields
|
|
84
|
-
#
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
@curry
|
|
88
|
-
def package_name(name: str, manifest: Manifest) -> Manifest:
|
|
89
|
-
"""
|
|
90
|
-
Return a copy of manifest with `name` set to "name".
|
|
91
|
-
"""
|
|
92
|
-
return assoc(manifest, "name", name)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@curry
|
|
96
|
-
def manifest_version(manifest_version: str, manifest: Manifest) -> Manifest:
|
|
97
|
-
"""
|
|
98
|
-
Return a copy of manifest with `manifest_version` set to "manifest".
|
|
99
|
-
"""
|
|
100
|
-
return assoc(manifest, "manifest", manifest_version)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
@curry
|
|
104
|
-
def version(version: str, manifest: Manifest) -> Manifest:
|
|
105
|
-
"""
|
|
106
|
-
Return a copy of manifest with `version` set to "version".
|
|
107
|
-
"""
|
|
108
|
-
return assoc(manifest, "version", version)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
#
|
|
112
|
-
# Meta
|
|
113
|
-
#
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def authors(*author_list: str) -> Manifest:
|
|
117
|
-
"""
|
|
118
|
-
Return a copy of manifest with a list of author posargs set
|
|
119
|
-
to "meta": {"authors": author_list}
|
|
120
|
-
"""
|
|
121
|
-
return _authors(author_list)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
@curry
|
|
125
|
-
@functools.wraps(authors)
|
|
126
|
-
def _authors(authors: Set[str], manifest: Manifest) -> Manifest:
|
|
127
|
-
return assoc_in(manifest, ("meta", "authors"), list(authors))
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
@curry
|
|
131
|
-
def license(license: str, manifest: Manifest) -> Manifest:
|
|
132
|
-
"""
|
|
133
|
-
Return a copy of manifest with `license` set to
|
|
134
|
-
"meta": {"license": `license`}
|
|
135
|
-
"""
|
|
136
|
-
return assoc_in(manifest, ("meta", "license"), license)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
@curry
|
|
140
|
-
def description(description: str, manifest: Manifest) -> Manifest:
|
|
141
|
-
"""
|
|
142
|
-
Return a copy of manifest with `description` set to
|
|
143
|
-
"meta": {"descriptions": `description`}
|
|
144
|
-
"""
|
|
145
|
-
return assoc_in(manifest, ("meta", "description"), description)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
def keywords(*keyword_list: str) -> Manifest:
|
|
149
|
-
"""
|
|
150
|
-
Return a copy of manifest with a list of keyword posargs set to
|
|
151
|
-
"meta": {"keywords": keyword_list}
|
|
152
|
-
"""
|
|
153
|
-
return _keywords(keyword_list)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
@curry
|
|
157
|
-
@functools.wraps(keywords)
|
|
158
|
-
def _keywords(keywords: Set[str], manifest: Manifest) -> Manifest:
|
|
159
|
-
return assoc_in(manifest, ("meta", "keywords"), list(keywords))
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def links(**link_dict: str) -> Manifest:
|
|
163
|
-
"""
|
|
164
|
-
Return a copy of manifest with a dict of link kwargs set to
|
|
165
|
-
"meta": {"links": link_dict}
|
|
166
|
-
"""
|
|
167
|
-
return _links(link_dict)
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
@curry
|
|
171
|
-
def _links(link_dict: Dict[str, str], manifest: Manifest) -> Manifest:
|
|
172
|
-
return assoc_in(manifest, ("meta", "links"), link_dict)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
#
|
|
176
|
-
# Sources
|
|
177
|
-
#
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def get_names_and_paths(compiler_output: Dict[str, Any]) -> Dict[str, str]:
|
|
181
|
-
"""
|
|
182
|
-
Return a mapping of contract name to relative path as defined in compiler output.
|
|
183
|
-
"""
|
|
184
|
-
return {
|
|
185
|
-
contract_name: make_path_relative(path)
|
|
186
|
-
for path in compiler_output
|
|
187
|
-
for contract_name in compiler_output[path].keys()
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def make_path_relative(path: str) -> str:
|
|
192
|
-
"""
|
|
193
|
-
Returns the given path prefixed with "./" if the path
|
|
194
|
-
is not already relative in the compiler output.
|
|
195
|
-
"""
|
|
196
|
-
if "../" in path:
|
|
197
|
-
raise ManifestBuildingError(
|
|
198
|
-
f"Path: {path} appears to be outside of the virtual source tree. "
|
|
199
|
-
"Please make sure all sources are within the virtual source tree "
|
|
200
|
-
"root directory."
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
if path[:2] != "./":
|
|
204
|
-
return f"./{path}"
|
|
205
|
-
return path
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
def source_inliner(
|
|
209
|
-
compiler_output: Dict[str, Any], package_root_dir: Optional[Path] = None
|
|
210
|
-
) -> Manifest:
|
|
211
|
-
return _inline_sources(compiler_output, package_root_dir)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
@curry
|
|
215
|
-
def _inline_sources(
|
|
216
|
-
compiler_output: Dict[str, Any], package_root_dir: Optional[Path], name: str
|
|
217
|
-
) -> Manifest:
|
|
218
|
-
return _inline_source(name, compiler_output, package_root_dir)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def inline_source(
|
|
222
|
-
name: str, compiler_output: Dict[str, Any], package_root_dir: Optional[Path] = None
|
|
223
|
-
) -> Manifest:
|
|
224
|
-
"""
|
|
225
|
-
Return a copy of manifest with added field to
|
|
226
|
-
"sources": {relative_source_path: contract_source_data}.
|
|
227
|
-
|
|
228
|
-
If `package_root_dir` is not provided, cwd is expected to resolve the relative
|
|
229
|
-
path to the source as defined in the compiler output.
|
|
230
|
-
"""
|
|
231
|
-
return _inline_source(name, compiler_output, package_root_dir)
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
@curry
|
|
235
|
-
def _inline_source(
|
|
236
|
-
name: str,
|
|
237
|
-
compiler_output: Dict[str, Any],
|
|
238
|
-
package_root_dir: Optional[Path],
|
|
239
|
-
manifest: Manifest,
|
|
240
|
-
) -> Manifest:
|
|
241
|
-
names_and_paths = get_names_and_paths(compiler_output)
|
|
242
|
-
cwd = Path.cwd()
|
|
243
|
-
try:
|
|
244
|
-
source_path = names_and_paths[name]
|
|
245
|
-
except KeyError:
|
|
246
|
-
raise ManifestBuildingError(
|
|
247
|
-
f"Unable to inline source: {name}. "
|
|
248
|
-
f"Available sources include: {list(sorted(names_and_paths.keys()))}."
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
if package_root_dir:
|
|
252
|
-
if (package_root_dir / source_path).is_file():
|
|
253
|
-
source_data = (package_root_dir / source_path).read_text()
|
|
254
|
-
else:
|
|
255
|
-
raise ManifestBuildingError(
|
|
256
|
-
f"Contract source: {source_path} cannot be found in "
|
|
257
|
-
f"provided package_root_dir: {package_root_dir}."
|
|
258
|
-
)
|
|
259
|
-
elif (cwd / source_path).is_file():
|
|
260
|
-
source_data = (cwd / source_path).read_text()
|
|
261
|
-
else:
|
|
262
|
-
raise ManifestBuildingError(
|
|
263
|
-
"Contract source cannot be resolved, please make sure that the working "
|
|
264
|
-
"directory is set to the correct directory or provide `package_root_dir`."
|
|
265
|
-
)
|
|
266
|
-
|
|
267
|
-
# rstrip used here since Path.read_text() adds a newline to returned contents
|
|
268
|
-
source_data_object = {
|
|
269
|
-
"content": source_data.rstrip("\n"),
|
|
270
|
-
"installPath": source_path,
|
|
271
|
-
"type": "solidity",
|
|
272
|
-
}
|
|
273
|
-
return assoc_in(manifest, ["sources", source_path], source_data_object)
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
def source_pinner(
|
|
277
|
-
compiler_output: Dict[str, Any],
|
|
278
|
-
ipfs_backend: BaseIPFSBackend,
|
|
279
|
-
package_root_dir: Optional[Path] = None,
|
|
280
|
-
) -> Manifest:
|
|
281
|
-
return _pin_sources(compiler_output, ipfs_backend, package_root_dir)
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
@curry
|
|
285
|
-
def _pin_sources(
|
|
286
|
-
compiler_output: Dict[str, Any],
|
|
287
|
-
ipfs_backend: BaseIPFSBackend,
|
|
288
|
-
package_root_dir: Optional[Path],
|
|
289
|
-
name: str,
|
|
290
|
-
) -> Manifest:
|
|
291
|
-
return _pin_source(name, compiler_output, ipfs_backend, package_root_dir)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
def pin_source(
|
|
295
|
-
name: str,
|
|
296
|
-
compiler_output: Dict[str, Any],
|
|
297
|
-
ipfs_backend: BaseIPFSBackend,
|
|
298
|
-
package_root_dir: Optional[Path] = None,
|
|
299
|
-
) -> Manifest:
|
|
300
|
-
"""
|
|
301
|
-
Pins source to IPFS and returns a copy of manifest with added field to
|
|
302
|
-
"sources": {relative_source_path: IFPS URI}.
|
|
303
|
-
|
|
304
|
-
If `package_root_dir` is not provided, cwd is expected to resolve the relative path
|
|
305
|
-
to the source as defined in the compiler output.
|
|
306
|
-
"""
|
|
307
|
-
return _pin_source(name, compiler_output, ipfs_backend, package_root_dir)
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
@curry
|
|
311
|
-
def _pin_source(
|
|
312
|
-
name: str,
|
|
313
|
-
compiler_output: Dict[str, Any],
|
|
314
|
-
ipfs_backend: BaseIPFSBackend,
|
|
315
|
-
package_root_dir: Optional[Path],
|
|
316
|
-
manifest: Manifest,
|
|
317
|
-
) -> Manifest:
|
|
318
|
-
names_and_paths = get_names_and_paths(compiler_output)
|
|
319
|
-
try:
|
|
320
|
-
source_path = names_and_paths[name]
|
|
321
|
-
except KeyError:
|
|
322
|
-
raise ManifestBuildingError(
|
|
323
|
-
f"Unable to pin source: {name}. "
|
|
324
|
-
f"Available sources include: {list(sorted(names_and_paths.keys()))}."
|
|
325
|
-
)
|
|
326
|
-
if package_root_dir:
|
|
327
|
-
if not (package_root_dir / source_path).is_file():
|
|
328
|
-
raise ManifestBuildingError(
|
|
329
|
-
f"Unable to find and pin contract source: {source_path} "
|
|
330
|
-
f"under specified package_root_dir: {package_root_dir}."
|
|
331
|
-
)
|
|
332
|
-
(ipfs_data,) = ipfs_backend.pin_assets(package_root_dir / source_path)
|
|
333
|
-
else:
|
|
334
|
-
cwd = Path.cwd()
|
|
335
|
-
if not (cwd / source_path).is_file():
|
|
336
|
-
raise ManifestBuildingError(
|
|
337
|
-
f"Unable to find and pin contract source: {source_path} "
|
|
338
|
-
f"current working directory: {cwd}."
|
|
339
|
-
)
|
|
340
|
-
(ipfs_data,) = ipfs_backend.pin_assets(cwd / source_path)
|
|
341
|
-
|
|
342
|
-
source_data_object = {
|
|
343
|
-
"urls": [f"ipfs://{ipfs_data['Hash']}"],
|
|
344
|
-
"type": "solidity",
|
|
345
|
-
"installPath": source_path,
|
|
346
|
-
}
|
|
347
|
-
return assoc_in(manifest, ["sources", source_path], source_data_object)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
#
|
|
351
|
-
# Contract Types
|
|
352
|
-
#
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
def contract_type(
|
|
356
|
-
name: str,
|
|
357
|
-
compiler_output: Dict[str, Any],
|
|
358
|
-
alias: Optional[str] = None,
|
|
359
|
-
abi: Optional[bool] = False,
|
|
360
|
-
compiler: Optional[bool] = False,
|
|
361
|
-
contract_type: Optional[bool] = False,
|
|
362
|
-
deployment_bytecode: Optional[bool] = False,
|
|
363
|
-
devdoc: Optional[bool] = False,
|
|
364
|
-
userdoc: Optional[bool] = False,
|
|
365
|
-
source_id: Optional[bool] = False,
|
|
366
|
-
runtime_bytecode: Optional[bool] = False,
|
|
367
|
-
) -> Manifest:
|
|
368
|
-
"""
|
|
369
|
-
Returns a copy of manifest with added contract_data field as specified by kwargs.
|
|
370
|
-
If no kwargs are present, all available contract_data found in the compiler output
|
|
371
|
-
will be included.
|
|
372
|
-
|
|
373
|
-
To include specific contract_data fields, add kwarg set to True (i.e. `abi=True`)
|
|
374
|
-
To alias a contract_type, include a kwarg `alias` (i.e. `alias="OwnedAlias"`)
|
|
375
|
-
If only an alias kwarg is provided, all available contract data will be included.
|
|
376
|
-
Kwargs must match fields as defined in the EthPM Spec (except "alias") if user
|
|
377
|
-
wants to include them in custom contract_type.
|
|
378
|
-
"""
|
|
379
|
-
contract_type_fields = {
|
|
380
|
-
"contractType": contract_type,
|
|
381
|
-
"deploymentBytecode": deployment_bytecode,
|
|
382
|
-
"runtimeBytecode": runtime_bytecode,
|
|
383
|
-
"abi": abi,
|
|
384
|
-
"compiler": compiler,
|
|
385
|
-
"userdoc": userdoc,
|
|
386
|
-
"devdoc": devdoc,
|
|
387
|
-
"sourceId": source_id,
|
|
388
|
-
}
|
|
389
|
-
selected_fields = [k for k, v in contract_type_fields.items() if v]
|
|
390
|
-
return _contract_type(name, compiler_output, alias, selected_fields)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
@curry
|
|
394
|
-
def _contract_type(
|
|
395
|
-
name: str,
|
|
396
|
-
compiler_output: Dict[str, Any],
|
|
397
|
-
alias: Optional[str],
|
|
398
|
-
selected_fields: Optional[List[str]],
|
|
399
|
-
manifest: Manifest,
|
|
400
|
-
) -> Manifest:
|
|
401
|
-
contracts_by_name = normalize_compiler_output(compiler_output)
|
|
402
|
-
try:
|
|
403
|
-
all_type_data = contracts_by_name[name]
|
|
404
|
-
except KeyError:
|
|
405
|
-
raise ManifestBuildingError(
|
|
406
|
-
f"Contract name: {name} not found in the provided compiler output."
|
|
407
|
-
)
|
|
408
|
-
if selected_fields:
|
|
409
|
-
contract_type_data = filter_all_data_by_selected_fields(
|
|
410
|
-
all_type_data, selected_fields
|
|
411
|
-
)
|
|
412
|
-
else:
|
|
413
|
-
contract_type_data = all_type_data
|
|
414
|
-
|
|
415
|
-
if "compiler" in contract_type_data:
|
|
416
|
-
compiler_info = contract_type_data.pop("compiler")
|
|
417
|
-
contract_type_ref = alias if alias else name
|
|
418
|
-
manifest_with_compilers = add_compilers_to_manifest(
|
|
419
|
-
compiler_info, contract_type_ref, manifest
|
|
420
|
-
)
|
|
421
|
-
else:
|
|
422
|
-
manifest_with_compilers = manifest
|
|
423
|
-
|
|
424
|
-
if alias:
|
|
425
|
-
return assoc_in(
|
|
426
|
-
manifest_with_compilers,
|
|
427
|
-
["contractTypes", alias],
|
|
428
|
-
assoc(contract_type_data, "contractType", name),
|
|
429
|
-
)
|
|
430
|
-
return assoc_in(
|
|
431
|
-
manifest_with_compilers, ["contractTypes", name], contract_type_data
|
|
432
|
-
)
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
def add_compilers_to_manifest(
|
|
436
|
-
compiler_info: Dict[str, Any], contract_type: str, manifest: Manifest
|
|
437
|
-
) -> Manifest:
|
|
438
|
-
"""
|
|
439
|
-
Adds a compiler information object to a manifest's top-level `compilers`.
|
|
440
|
-
"""
|
|
441
|
-
if "compilers" not in manifest:
|
|
442
|
-
compiler_info["contractTypes"] = [contract_type]
|
|
443
|
-
return assoc_in(manifest, ["compilers"], [compiler_info])
|
|
444
|
-
|
|
445
|
-
updated_compiler_info = update_compilers_object(
|
|
446
|
-
compiler_info, contract_type, manifest["compilers"]
|
|
447
|
-
)
|
|
448
|
-
return assoc_in(manifest, ["compilers"], updated_compiler_info)
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
@to_list
|
|
452
|
-
def update_compilers_object(
|
|
453
|
-
new_compiler: Dict[str, Any],
|
|
454
|
-
contract_type: str,
|
|
455
|
-
previous_compilers: List[Dict[str, Any]],
|
|
456
|
-
) -> Iterable[Dict[str, Any]]:
|
|
457
|
-
"""
|
|
458
|
-
Updates a manifest's top-level `compilers` with a new compiler information object.
|
|
459
|
-
- If compiler version already exists, we just update the compiler's `contractTypes`
|
|
460
|
-
"""
|
|
461
|
-
recorded_new_contract_type = False
|
|
462
|
-
for compiler in previous_compilers:
|
|
463
|
-
contract_types = compiler.pop("contractTypes")
|
|
464
|
-
if contract_type in contract_types:
|
|
465
|
-
raise ManifestBuildingError(
|
|
466
|
-
f"Contract type: {contract_type} already referenced in `compilers`."
|
|
467
|
-
)
|
|
468
|
-
if compiler == new_compiler:
|
|
469
|
-
contract_types.append(contract_type)
|
|
470
|
-
recorded_new_contract_type = True
|
|
471
|
-
compiler["contractTypes"] = contract_types
|
|
472
|
-
yield compiler
|
|
473
|
-
|
|
474
|
-
if not recorded_new_contract_type:
|
|
475
|
-
new_compiler["contractTypes"] = [contract_type]
|
|
476
|
-
yield new_compiler
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
@to_dict
|
|
480
|
-
def filter_all_data_by_selected_fields(
|
|
481
|
-
all_type_data: Dict[str, Any], selected_fields: List[str]
|
|
482
|
-
) -> Iterable[Tuple[str, Any]]:
|
|
483
|
-
"""
|
|
484
|
-
Raises exception if selected field data is not available in the contract type data
|
|
485
|
-
automatically gathered by normalize_compiler_output. Otherwise, returns the data.
|
|
486
|
-
"""
|
|
487
|
-
for field in selected_fields:
|
|
488
|
-
if field in all_type_data:
|
|
489
|
-
yield field, all_type_data[field]
|
|
490
|
-
else:
|
|
491
|
-
raise ManifestBuildingError(
|
|
492
|
-
f"Selected field: {field} not available in data collected from "
|
|
493
|
-
f"solc output: {list(sorted(all_type_data.keys()))}. Please make"
|
|
494
|
-
"sure the relevant data is present in your solc output."
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
def normalize_compiler_output(compiler_output: Dict[str, Any]) -> Dict[str, Any]:
|
|
499
|
-
"""
|
|
500
|
-
Return compiler output with normalized fields for each contract type,
|
|
501
|
-
as specified in `normalize_contract_type`.
|
|
502
|
-
"""
|
|
503
|
-
paths_and_names = [
|
|
504
|
-
(path, contract_name)
|
|
505
|
-
for path in compiler_output
|
|
506
|
-
for contract_name in compiler_output[path].keys()
|
|
507
|
-
]
|
|
508
|
-
paths, names = zip(*paths_and_names)
|
|
509
|
-
if len(names) != len(set(names)):
|
|
510
|
-
duplicates = {name for name in names if names.count(name) > 1}
|
|
511
|
-
raise ManifestBuildingError(
|
|
512
|
-
f"Duplicate contract types: {duplicates} were found in the compiler output."
|
|
513
|
-
)
|
|
514
|
-
return {
|
|
515
|
-
name: normalize_contract_type(compiler_output[path][name], path)
|
|
516
|
-
for path, name in paths_and_names
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
@to_dict
|
|
521
|
-
def normalize_contract_type(
|
|
522
|
-
contract_type_data: Dict[str, Any],
|
|
523
|
-
source_id: str,
|
|
524
|
-
) -> Iterable[Tuple[str, Any]]:
|
|
525
|
-
"""
|
|
526
|
-
Serialize contract_data found in compiler output to the defined fields.
|
|
527
|
-
"""
|
|
528
|
-
yield "abi", contract_type_data["abi"]
|
|
529
|
-
yield "sourceId", source_id
|
|
530
|
-
if "evm" in contract_type_data:
|
|
531
|
-
if "bytecode" in contract_type_data["evm"]:
|
|
532
|
-
yield "deploymentBytecode", normalize_bytecode_object(
|
|
533
|
-
contract_type_data["evm"]["bytecode"]
|
|
534
|
-
)
|
|
535
|
-
if "deployedBytecode" in contract_type_data["evm"]:
|
|
536
|
-
yield "runtimeBytecode", normalize_bytecode_object(
|
|
537
|
-
contract_type_data["evm"]["deployedBytecode"]
|
|
538
|
-
)
|
|
539
|
-
if "devdoc" in contract_type_data:
|
|
540
|
-
yield "devdoc", contract_type_data["devdoc"]
|
|
541
|
-
if "userdoc" in contract_type_data:
|
|
542
|
-
yield "userdoc", contract_type_data["userdoc"]
|
|
543
|
-
# make sure metadata isn't an empty string in solc output
|
|
544
|
-
if "metadata" in contract_type_data and contract_type_data["metadata"]:
|
|
545
|
-
yield "compiler", normalize_compiler_object(
|
|
546
|
-
json.loads(contract_type_data["metadata"])
|
|
547
|
-
)
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
@to_dict
|
|
551
|
-
def normalize_compiler_object(obj: Dict[str, Any]) -> Iterable[Tuple[str, Any]]:
|
|
552
|
-
yield "name", "solc"
|
|
553
|
-
yield "version", obj["compiler"]["version"]
|
|
554
|
-
yield "settings", {"optimize": obj["settings"]["optimizer"]["enabled"]}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
@to_dict
|
|
558
|
-
def normalize_bytecode_object(obj: Dict[str, Any]) -> Iterable[Tuple[str, Any]]:
|
|
559
|
-
try:
|
|
560
|
-
link_references = obj["linkReferences"]
|
|
561
|
-
except KeyError:
|
|
562
|
-
link_references = None
|
|
563
|
-
try:
|
|
564
|
-
bytecode = obj["object"]
|
|
565
|
-
except KeyError:
|
|
566
|
-
raise ManifestBuildingError(
|
|
567
|
-
"'object' key not found in bytecode data from compiler output. "
|
|
568
|
-
"Please make sure your solidity compiler output is valid."
|
|
569
|
-
)
|
|
570
|
-
if link_references:
|
|
571
|
-
yield "linkReferences", process_link_references(link_references, bytecode)
|
|
572
|
-
yield "bytecode", process_bytecode(link_references, bytecode)
|
|
573
|
-
else:
|
|
574
|
-
yield "bytecode", add_0x_prefix(bytecode)
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
def process_bytecode(link_refs: Dict[str, Any], bytecode: bytes) -> HexStr:
|
|
578
|
-
"""
|
|
579
|
-
Replace link_refs in bytecode with 0's.
|
|
580
|
-
"""
|
|
581
|
-
all_offsets = [y for x in link_refs.values() for y in x.values()]
|
|
582
|
-
# Link ref validation.
|
|
583
|
-
validate_link_ref_fns = (
|
|
584
|
-
validate_link_ref(ref["start"] * 2, ref["length"] * 2)
|
|
585
|
-
for ref in concat(all_offsets)
|
|
586
|
-
)
|
|
587
|
-
pipe(bytecode, *validate_link_ref_fns)
|
|
588
|
-
# Convert link_refs in bytecode to 0's
|
|
589
|
-
link_fns = (
|
|
590
|
-
replace_link_ref_in_bytecode(ref["start"] * 2, ref["length"] * 2)
|
|
591
|
-
for ref in concat(all_offsets)
|
|
592
|
-
)
|
|
593
|
-
processed_bytecode = pipe(bytecode, *link_fns)
|
|
594
|
-
return add_0x_prefix(processed_bytecode)
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
@curry
|
|
598
|
-
def replace_link_ref_in_bytecode(offset: int, length: int, bytecode: str) -> str:
|
|
599
|
-
new_bytes = (
|
|
600
|
-
bytecode[:offset] + "0" * length + bytecode[offset + length :] # noqa: E203
|
|
601
|
-
)
|
|
602
|
-
return new_bytes
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
# todo pull all bytecode linking/validating across py-ethpm into shared utils
|
|
606
|
-
@to_list
|
|
607
|
-
def process_link_references(
|
|
608
|
-
link_refs: Dict[str, Any], bytecode: str
|
|
609
|
-
) -> Iterable[Dict[str, Any]]:
|
|
610
|
-
for link_ref in link_refs.values():
|
|
611
|
-
yield normalize_link_ref(link_ref, bytecode)
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
def normalize_link_ref(link_ref: Dict[str, Any], bytecode: str) -> Dict[str, Any]:
|
|
615
|
-
name = list(link_ref.keys())[0]
|
|
616
|
-
return {
|
|
617
|
-
"name": name,
|
|
618
|
-
"length": 20,
|
|
619
|
-
"offsets": normalize_offsets(link_ref, bytecode),
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
@to_list
|
|
624
|
-
def normalize_offsets(data: Dict[str, Any], bytecode: str) -> Iterable[List[int]]:
|
|
625
|
-
for link_ref in data.values():
|
|
626
|
-
for ref in link_ref:
|
|
627
|
-
yield ref["start"]
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
@curry
|
|
631
|
-
def validate_link_ref(offset: int, length: int, bytecode: str) -> str:
|
|
632
|
-
slot_length = offset + length
|
|
633
|
-
slot = bytecode[offset:slot_length]
|
|
634
|
-
if slot[:2] != "__" and slot[-2:] != "__":
|
|
635
|
-
raise EthPMValidationError(
|
|
636
|
-
f"Slot: {slot}, at offset: {offset} of length: {length} is not a valid "
|
|
637
|
-
"link_ref that can be replaced."
|
|
638
|
-
)
|
|
639
|
-
return bytecode
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
#
|
|
643
|
-
# Deployments
|
|
644
|
-
#
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
def deployment_type(
|
|
648
|
-
*,
|
|
649
|
-
contract_instance: str,
|
|
650
|
-
contract_type: str,
|
|
651
|
-
deployment_bytecode: Dict[str, Any] = None,
|
|
652
|
-
runtime_bytecode: Dict[str, Any] = None,
|
|
653
|
-
compiler: Dict[str, Any] = None,
|
|
654
|
-
) -> Manifest:
|
|
655
|
-
"""
|
|
656
|
-
Returns a callable that allows the user to add deployments of the same type
|
|
657
|
-
across multiple chains.
|
|
658
|
-
"""
|
|
659
|
-
return _deployment_type(
|
|
660
|
-
contract_instance,
|
|
661
|
-
contract_type,
|
|
662
|
-
deployment_bytecode,
|
|
663
|
-
runtime_bytecode,
|
|
664
|
-
compiler,
|
|
665
|
-
)
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
def deployment(
|
|
669
|
-
*,
|
|
670
|
-
block_uri: URI,
|
|
671
|
-
contract_instance: str,
|
|
672
|
-
contract_type: str,
|
|
673
|
-
address: HexStr,
|
|
674
|
-
transaction: HexStr = None,
|
|
675
|
-
block: HexStr = None,
|
|
676
|
-
deployment_bytecode: Dict[str, Any] = None,
|
|
677
|
-
runtime_bytecode: Dict[str, Any] = None,
|
|
678
|
-
compiler: Dict[str, Any] = None,
|
|
679
|
-
) -> Manifest:
|
|
680
|
-
"""
|
|
681
|
-
Returns a manifest, with the newly included deployment. Requires a valid
|
|
682
|
-
blockchain URI, however no validation is provided that this URI is unique
|
|
683
|
-
amongst the other deployment URIs, so the user must take care that each
|
|
684
|
-
blockchain URI represents a unique blockchain.
|
|
685
|
-
"""
|
|
686
|
-
return _deployment(
|
|
687
|
-
contract_instance,
|
|
688
|
-
contract_type,
|
|
689
|
-
deployment_bytecode,
|
|
690
|
-
runtime_bytecode,
|
|
691
|
-
compiler,
|
|
692
|
-
block_uri,
|
|
693
|
-
address,
|
|
694
|
-
transaction,
|
|
695
|
-
block,
|
|
696
|
-
)
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
@curry
|
|
700
|
-
def _deployment_type(
|
|
701
|
-
contract_instance: str,
|
|
702
|
-
contract_type: str,
|
|
703
|
-
deployment_bytecode: Dict[str, Any],
|
|
704
|
-
runtime_bytecode: Dict[str, Any],
|
|
705
|
-
compiler: Dict[str, Any],
|
|
706
|
-
block_uri: URI,
|
|
707
|
-
address: HexStr,
|
|
708
|
-
tx: HexStr = None,
|
|
709
|
-
block: HexStr = None,
|
|
710
|
-
manifest: Manifest = None,
|
|
711
|
-
) -> Manifest:
|
|
712
|
-
return _deployment(
|
|
713
|
-
contract_instance,
|
|
714
|
-
contract_type,
|
|
715
|
-
deployment_bytecode,
|
|
716
|
-
runtime_bytecode,
|
|
717
|
-
compiler,
|
|
718
|
-
block_uri,
|
|
719
|
-
address,
|
|
720
|
-
tx,
|
|
721
|
-
block,
|
|
722
|
-
)
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
@curry
|
|
726
|
-
def _deployment(
|
|
727
|
-
contract_instance: str,
|
|
728
|
-
contract_type: str,
|
|
729
|
-
deployment_bytecode: Dict[str, Any],
|
|
730
|
-
runtime_bytecode: Dict[str, Any],
|
|
731
|
-
compiler: Dict[str, Any],
|
|
732
|
-
block_uri: URI,
|
|
733
|
-
address: HexStr,
|
|
734
|
-
tx: HexStr,
|
|
735
|
-
block: HexStr,
|
|
736
|
-
manifest: Manifest,
|
|
737
|
-
) -> Manifest:
|
|
738
|
-
validate_address(address)
|
|
739
|
-
if not is_BIP122_block_uri(block_uri):
|
|
740
|
-
raise ManifestBuildingError(f"{block_uri} is not a valid BIP122 URI.")
|
|
741
|
-
|
|
742
|
-
if tx:
|
|
743
|
-
if not is_string(tx) and not is_hex(tx):
|
|
744
|
-
raise ManifestBuildingError(
|
|
745
|
-
f"Transaction hash: {tx} is not a valid hexstring"
|
|
746
|
-
)
|
|
747
|
-
|
|
748
|
-
if block:
|
|
749
|
-
if not is_string(block) and not is_hex(block):
|
|
750
|
-
raise ManifestBuildingError(f"Block hash: {block} is not a valid hexstring")
|
|
751
|
-
# todo: validate db, rb and compiler are properly formatted dicts
|
|
752
|
-
deployment_data = _build_deployments_object(
|
|
753
|
-
contract_type,
|
|
754
|
-
deployment_bytecode,
|
|
755
|
-
runtime_bytecode,
|
|
756
|
-
compiler,
|
|
757
|
-
address,
|
|
758
|
-
tx,
|
|
759
|
-
block,
|
|
760
|
-
manifest,
|
|
761
|
-
)
|
|
762
|
-
return assoc_in(
|
|
763
|
-
manifest, ["deployments", block_uri, contract_instance], deployment_data
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
@to_dict
|
|
768
|
-
def _build_deployments_object(
|
|
769
|
-
contract_type: str,
|
|
770
|
-
deployment_bytecode: Dict[str, Any],
|
|
771
|
-
runtime_bytecode: Dict[str, Any],
|
|
772
|
-
compiler: Dict[str, Any],
|
|
773
|
-
address: HexStr,
|
|
774
|
-
tx: HexStr,
|
|
775
|
-
block: HexStr,
|
|
776
|
-
manifest: Dict[str, Any],
|
|
777
|
-
) -> Iterable[Tuple[str, Any]]:
|
|
778
|
-
"""
|
|
779
|
-
Returns a dict with properly formatted deployment data.
|
|
780
|
-
"""
|
|
781
|
-
yield "contractType", contract_type
|
|
782
|
-
yield "address", to_checksum_address(address)
|
|
783
|
-
if deployment_bytecode:
|
|
784
|
-
yield "deploymentBytecode", deployment_bytecode
|
|
785
|
-
if compiler:
|
|
786
|
-
yield "compiler", compiler
|
|
787
|
-
if tx:
|
|
788
|
-
yield "transaction", tx
|
|
789
|
-
if block:
|
|
790
|
-
yield "block", block
|
|
791
|
-
if runtime_bytecode:
|
|
792
|
-
yield "runtimeBytecode", runtime_bytecode
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
#
|
|
796
|
-
# Build Dependencies
|
|
797
|
-
#
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
def build_dependency(package_name: str, uri: URI) -> Manifest:
|
|
801
|
-
"""
|
|
802
|
-
Returns the manifest with injected build dependency.
|
|
803
|
-
"""
|
|
804
|
-
return _build_dependency(package_name, uri)
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
@curry
|
|
808
|
-
def _build_dependency(package_name: str, uri: URI, manifest: Manifest) -> Manifest:
|
|
809
|
-
validate_package_name(package_name)
|
|
810
|
-
if not is_supported_content_addressed_uri(uri):
|
|
811
|
-
raise EthPMValidationError(
|
|
812
|
-
f"{uri} is not a supported content-addressed URI. "
|
|
813
|
-
"Currently only IPFS and Github blob uris are supported."
|
|
814
|
-
)
|
|
815
|
-
return assoc_in(manifest, ("buildDependencies", package_name), uri)
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
#
|
|
819
|
-
# Helpers
|
|
820
|
-
#
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
@curry
|
|
824
|
-
def init_manifest(
|
|
825
|
-
package_name: str, version: str, manifest_version: Optional[str] = "ethpm/3"
|
|
826
|
-
) -> Dict[str, Any]:
|
|
827
|
-
"""
|
|
828
|
-
Returns an initial dict with the minimal required fields for a valid manifest.
|
|
829
|
-
Should only be used as the first fn to be piped into a `build()` pipeline.
|
|
830
|
-
"""
|
|
831
|
-
return {
|
|
832
|
-
"name": package_name,
|
|
833
|
-
"version": version,
|
|
834
|
-
"manifest": manifest_version,
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
#
|
|
839
|
-
# Formatting
|
|
840
|
-
#
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
@curry
|
|
844
|
-
def validate(manifest: Manifest) -> Manifest:
|
|
845
|
-
"""
|
|
846
|
-
Return a validated manifest against the V2-specification schema.
|
|
847
|
-
"""
|
|
848
|
-
validate_manifest_against_schema(manifest)
|
|
849
|
-
return manifest
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
@curry
|
|
853
|
-
def as_package(w3: "Web3", manifest: Manifest) -> Package:
|
|
854
|
-
"""
|
|
855
|
-
Return a Package object instantiated with the provided manifest and web3 instance.
|
|
856
|
-
"""
|
|
857
|
-
return Package(manifest, w3)
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
def write_to_disk(
|
|
861
|
-
manifest_root_dir: Optional[Path] = None,
|
|
862
|
-
manifest_name: Optional[str] = None,
|
|
863
|
-
prettify: Optional[bool] = False,
|
|
864
|
-
) -> Manifest:
|
|
865
|
-
"""
|
|
866
|
-
Write the active manifest to disk
|
|
867
|
-
Defaults
|
|
868
|
-
- Writes manifest to cwd unless Path is provided as manifest_root_dir.
|
|
869
|
-
- Writes manifest with a filename of Manifest[version].json unless a desired
|
|
870
|
-
manifest name (which must end in json) is provided as manifest_name.
|
|
871
|
-
- Writes the minified manifest version to disk unless prettify is set to True.
|
|
872
|
-
"""
|
|
873
|
-
return _write_to_disk(manifest_root_dir, manifest_name, prettify)
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
@curry
|
|
877
|
-
def _write_to_disk(
|
|
878
|
-
manifest_root_dir: Optional[Path],
|
|
879
|
-
manifest_name: Optional[str],
|
|
880
|
-
prettify: Optional[bool],
|
|
881
|
-
manifest: Manifest,
|
|
882
|
-
) -> Manifest:
|
|
883
|
-
if manifest_root_dir:
|
|
884
|
-
if manifest_root_dir.is_dir():
|
|
885
|
-
cwd = manifest_root_dir
|
|
886
|
-
else:
|
|
887
|
-
raise ManifestBuildingError(
|
|
888
|
-
f"Manifest root directory: {manifest_root_dir} cannot be found, please "
|
|
889
|
-
"provide a valid directory for writing the manifest to disk. "
|
|
890
|
-
"(Path obj // leave manifest_root_dir blank to default to cwd)"
|
|
891
|
-
)
|
|
892
|
-
else:
|
|
893
|
-
cwd = Path.cwd()
|
|
894
|
-
|
|
895
|
-
if manifest_name:
|
|
896
|
-
if not manifest_name.lower().endswith(".json"):
|
|
897
|
-
raise ManifestBuildingError(
|
|
898
|
-
f"Invalid manifest name: {manifest_name}. "
|
|
899
|
-
"All manifest names must end in .json"
|
|
900
|
-
)
|
|
901
|
-
disk_manifest_name = manifest_name
|
|
902
|
-
else:
|
|
903
|
-
disk_manifest_name = manifest["version"] + ".json"
|
|
904
|
-
|
|
905
|
-
contents = format_manifest(manifest, prettify=prettify)
|
|
906
|
-
|
|
907
|
-
if (cwd / disk_manifest_name).is_file():
|
|
908
|
-
raise ManifestBuildingError(
|
|
909
|
-
f"Manifest: {disk_manifest_name} already exists in cwd: {cwd}"
|
|
910
|
-
)
|
|
911
|
-
(cwd / disk_manifest_name).write_text(contents)
|
|
912
|
-
return manifest
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
@curry
|
|
916
|
-
def pin_to_ipfs(
|
|
917
|
-
manifest: Manifest, *, backend: BaseIPFSBackend, prettify: Optional[bool] = False
|
|
918
|
-
) -> List[Dict[str, str]]:
|
|
919
|
-
"""
|
|
920
|
-
Returns the IPFS pin data after pinning the manifest to the provided IPFS Backend.
|
|
921
|
-
|
|
922
|
-
`pin_to_ipfs()` Should *always* be the last argument in a builder, as it will
|
|
923
|
-
return the pin data and not the manifest.
|
|
924
|
-
"""
|
|
925
|
-
contents = format_manifest(manifest, prettify=prettify)
|
|
926
|
-
|
|
927
|
-
with tempfile.NamedTemporaryFile() as temp:
|
|
928
|
-
temp.write(to_bytes(text=contents))
|
|
929
|
-
temp.seek(0)
|
|
930
|
-
return backend.pin_assets(Path(temp.name))
|