Skip to content

Commit 8114f87

Browse files
Merge branch 'main' into cleanup
2 parents 1d6d1ca + 7539d16 commit 8114f87

23 files changed

Lines changed: 567 additions & 44 deletions

erdpy/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
77
## [Unreleased]
88
- TBD
99

10+
## [1.2.0] - 07.03.2022
11+
- [On contract builld, reveal imported functions and check compatibility](https://github.com/ElrondNetwork/elrond-sdk-erdpy/pull/111)
12+
1013
## [1.1.0] - 01.03.2022
1114
- [Add reports: contract sizes and twiggy symbol checks](https://github.com/ElrondNetwork/elrond-sdk-erdpy/pull/106)
1215
- [Add `--recursive` option on contract build](https://github.com/ElrondNetwork/elrond-sdk-erdpy/pull/104)

erdpy/CLI.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ TOP-LEVEL OPTIONS:
3030
----------------------
3131
COMMAND GROUPS summary
3232
----------------------
33-
contract Build, deploy and interact with Smart Contracts
33+
contract Build, deploy, upgrade and interact with Smart Contracts
3434
tx Create and broadcast Transactions
3535
validator Stake, UnStake, UnBond, Unjail and other actions useful for Validators
3636
account Get Account data (nonce, balance) from the Network
@@ -54,7 +54,7 @@ dns Operations related to the Domain Name Service
5454
$ erdpy contract --help
5555
usage: erdpy contract COMMAND [-h] ...
5656
57-
Build, deploy and interact with Smart Contracts
57+
Build, deploy, upgrade and interact with Smart Contracts
5858
5959
COMMANDS:
6060
{new,templates,build,clean,test,report,deploy,call,upgrade,query}
@@ -131,6 +131,8 @@ optional arguments:
131131
analysing the bytecode. Creates larger wasm files. Avoid in production (default:
132132
False)
133133
--wasm-name WASM_NAME for rust projects, optionally specify the name of the wasm bytecode output file
134+
--skip-eei-checks skip EEI compatibility checks (default: False)
135+
--ignore-eei-checks ignore EEI compatibility errors (default: False)
134136
135137
```
136138
### Contract.Clean
@@ -1216,7 +1218,7 @@ usage: erdpy deps install [-h] ...
12161218
Install dependencies or elrond-sdk modules.
12171219
12181220
positional arguments:
1219-
{all,llvm,clang,cpp,rust,nodejs,golang,vmtools,elrond_go,elrond_proxy_go,mcl_signer,wasm-opt,twiggy}
1221+
{all,llvm,clang,cpp,rust,nodejs,golang,wabt,vmtools,elrond_go,elrond_proxy_go,mcl_signer,wasm-opt,twiggy}
12201222
the dependency to install
12211223
12221224
optional arguments:
@@ -1235,7 +1237,7 @@ usage: erdpy deps check [-h] ...
12351237
Check whether a dependency is installed.
12361238
12371239
positional arguments:
1238-
{all,llvm,clang,cpp,rust,nodejs,golang,vmtools,elrond_go,elrond_proxy_go,mcl_signer,wasm-opt,twiggy}
1240+
{all,llvm,clang,cpp,rust,nodejs,golang,wabt,vmtools,elrond_go,elrond_proxy_go,mcl_signer,wasm-opt,twiggy}
12391241
the dependency to check
12401242
12411243
optional arguments:

erdpy/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.1.0"
1+
__version__ = "1.2.0"

erdpy/cli_contracts.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818

1919
def setup_parser(args: List[str], subparsers: Any) -> Any:
20-
parser = cli_shared.add_group_subparser(subparsers, "contract", "Build, deploy and interact with Smart Contracts")
20+
parser = cli_shared.add_group_subparser(subparsers, "contract", "Build, deploy, upgrade and interact with Smart Contracts")
2121
subparsers = parser.add_subparsers()
2222

2323
sub = cli_shared.add_command_subparser(subparsers, "contract", "new",
@@ -46,6 +46,8 @@ def setup_parser(args: List[str], subparsers: Any) -> Any:
4646
help="for rust projects, does not strip the symbols from the wasm output. Useful for analysing the bytecode. Creates larger wasm files. Avoid in production (default: %(default)s)")
4747
sub.add_argument("--wasm-name", type=str,
4848
help="for rust projects, optionally specify the name of the wasm bytecode output file")
49+
sub.add_argument("--skip-eei-checks", action="store_true", default=False, help="skip EEI compatibility checks (default: %(default)s)")
50+
sub.add_argument("--ignore-eei-checks", action="store_true", default=False, help="ignore EEI compatibility errors (default: %(default)s)")
4951
sub.set_defaults(func=build)
5052

5153
sub = cli_shared.add_command_subparser(subparsers, "contract", "clean", "Clean a Smart Contract project.")
@@ -211,7 +213,9 @@ def build(args: Any):
211213
"verbose": args.verbose,
212214
"cargo_target_dir": args.cargo_target_dir,
213215
"wasm_symbols": args.wasm_symbols,
214-
"wasm_name": args.wasm_name
216+
"wasm_name": args.wasm_name,
217+
"skip-eei-checks": args.skip_eei_checks,
218+
"ignore-eei-checks": args.ignore_eei_checks
215219
}
216220

217221
for project in project_paths:

erdpy/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ def get_defaults() -> Dict[str, Any]:
177177
"dependencies.mcl_signer.urlTemplate.osx": "https://github.com/ElrondNetwork/elrond-sdk-go-tools/releases/download/{TAG}/mcl_signer_{TAG}_macos-latest.tar.gz",
178178
"dependencies.wasm-opt.tag": "latest",
179179
"dependencies.twiggy.tag": "latest",
180+
"dependencies.wabt.tag": "1.0.27",
181+
"dependencies.wabt.urlTemplate.linux": "https://github.com/WebAssembly/wabt/releases/download/{TAG}/wabt-{TAG}-ubuntu.tar.gz",
182+
"dependencies.wabt.urlTemplate.osx": "https://github.com/WebAssembly/wabt/releases/download/{TAG}/wabt-{TAG}-macos.tar.gz",
180183
"testnet.validate_expected_keys": "false",
181184
"github_api_token": "",
182185
}

erdpy/dependencies/install.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
from erdpy import config, errors
66
from erdpy.dependencies.modules import (CargoModule, NpmModule, VMToolsModule, DependencyModule,
77
GolangModule, MclSignerModule,
8-
NodejsModule, Rust, StandaloneModule)
8+
NodejsModule, Rust, StandaloneModule, WabtModule)
99

1010
logger = logging.getLogger("install")
1111

1212

1313
def install_module(key: str, tag: str = "", overwrite: bool = False):
1414
if key == 'all':
15-
modules = get_all_deps_installable_via_cli()
15+
modules = _get_all_deps_installable_via_cli()
1616
else:
1717
modules = [get_module_by_key(key)]
1818

@@ -28,36 +28,39 @@ def get_module_directory(key: str) -> Path:
2828

2929

3030
def get_module_by_key(key: str) -> DependencyModule:
31-
matches = [module for module in get_all_deps() if module.key == key or key in module.aliases]
31+
matches = [module for module in _get_all_deps() if module.key == key or key in module.aliases]
3232
if len(matches) != 1:
3333
raise errors.UnknownDependency(key)
3434

3535
return matches[0]
3636

3737

3838
def get_deps_dict() -> Dict[str, DependencyModule]:
39-
deps = dict()
40-
for module in get_all_deps():
39+
deps: Dict[str, DependencyModule] = dict()
40+
41+
for module in _get_all_deps():
4142
deps[module.key] = module
4243
for alias in module.aliases:
4344
deps[alias] = module
45+
4446
return deps
4547

4648

47-
def get_all_deps() -> List[DependencyModule]:
48-
return get_all_implicit_deps() + get_all_deps_installable_via_cli()
49+
def _get_all_deps() -> List[DependencyModule]:
50+
return _get_all_implicit_deps() + _get_all_deps_installable_via_cli()
4951

5052

51-
def get_all_implicit_deps() -> List[DependencyModule]:
53+
def _get_all_implicit_deps() -> List[DependencyModule]:
5254
return [
5355
StandaloneModule(key="llvm", aliases=["clang", "cpp"]),
5456
Rust(key="rust"),
5557
NodejsModule(key="nodejs", aliases=[]),
5658
GolangModule(key="golang"),
59+
WabtModule(key="wabt", aliases=[])
5760
]
5861

5962

60-
def get_all_deps_installable_via_cli() -> List[DependencyModule]:
63+
def _get_all_deps_installable_via_cli() -> List[DependencyModule]:
6164
return [
6265
VMToolsModule(key="vmtools"),
6366
StandaloneModule(key="elrond_go", repo_name="elrond-go", organisation="ElrondNetwork"),
@@ -68,7 +71,6 @@ def get_all_deps_installable_via_cli() -> List[DependencyModule]:
6871
]
6972

7073

71-
7274
def get_golang() -> GolangModule:
7375
golang = get_module_by_key('golang')
7476
assert isinstance(golang, GolangModule)

erdpy/dependencies/modules.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ def get_latest_release(self) -> str:
245245
raise errors.UnsupportedConfigurationValue("Nodejs tag must always be explicit, not latest")
246246

247247

248+
249+
class WabtModule(StandaloneModule):
250+
def __init__(self, key: str, aliases: List[str]):
251+
super().__init__(key, aliases)
252+
253+
def _post_install(self, tag: str):
254+
# We'll create a "latest" symlink
255+
link_target = path.join(self.get_directory(tag), f"wabt-{tag}")
256+
link = path.join(self.get_parent_directory(), "latest")
257+
utils.symlink(link_target, link)
258+
259+
def get_env(self):
260+
bin_folder = path.join(self.get_parent_directory(), "latest", "bin")
261+
262+
return {
263+
"PATH": f"{bin_folder}:{os.environ['PATH']}",
264+
}
265+
266+
def get_latest_release(self) -> str:
267+
raise errors.UnsupportedConfigurationValue("WABT tag must be explicit")
268+
269+
248270
class NpmModule(DependencyModule):
249271
def __init__(self, key: str, aliases: List[str] = []):
250272
super().__init__(key, aliases)

erdpy/diskcache.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from pathlib import Path
2+
import time
3+
from typing import Any, Callable, Dict, cast
4+
5+
from erdpy import utils, workstation
6+
7+
8+
class DiskCache:
9+
def __init__(self, cache_name: str, max_age: int) -> None:
10+
self.cache_name = Path(cache_name)
11+
self.max_age = max_age
12+
13+
def get_path(self) -> Path:
14+
return workstation.get_tools_folder() / f"{self.cache_name}.json"
15+
16+
def get_and_cache_item(self, key: str, item_provider: Callable[[], Any]) -> Any:
17+
if not self.has_item(key):
18+
item = item_provider()
19+
self.save_item(key, item)
20+
item = self._get_cached_item(key)
21+
return item
22+
23+
def has_item(self, key: str):
24+
payload = self.load_payload()
25+
item = payload.get(key, None)
26+
timestamp = payload.get(f"timestamp:{key}", 0)
27+
age = abs(self._now() - timestamp)
28+
expired = age > self.max_age
29+
return True if item is not None and not expired else False
30+
31+
def save_item(self, key: str, item: Any):
32+
cache = self.load_payload()
33+
cache[key] = item
34+
cache[f"timestamp:{key}"] = self._now()
35+
self.store_payload(cache)
36+
37+
def _get_cached_item(self, key: str):
38+
return self.load_payload().get(key)
39+
40+
def load_payload(self) -> Dict[str, Any]:
41+
path = self.get_path()
42+
if path.exists():
43+
payload = utils.read_json_file(path)
44+
return cast(Dict[str, Any], payload)
45+
return dict()
46+
47+
def store_payload(self, cache: Any):
48+
utils.write_json_file(str(self.get_path()), cache)
49+
50+
def _now(self):
51+
return int(time.time())

erdpy/errors.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ def __init__(self, directory: str):
6363
super().__init__(f"Directory is not a supported project: {directory}")
6464

6565

66+
class NotSupportedProjectFeature(KnownError):
67+
def __init__(self):
68+
super().__init__(f"Project feature not yet supported.")
69+
70+
6671
class PlatformNotSupported(KnownError):
6772
def __init__(self, action_or_item: str, platform: str):
6873
super().__init__(f"[{action_or_item}] is not supported on platform [{platform}].")

erdpy/projects/eei_activation.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
import logging
3+
import sys
4+
5+
import requests
6+
import toml
7+
from erdpy.diskcache import DiskCache
8+
from erdpy.proxy.core import ElrondProxy
9+
10+
logger = logging.getLogger("eei")
11+
12+
13+
class ActivationEpochsInfo(DiskCache):
14+
def __init__(self, network_name: str, proxy_url: str, enable_epochs_url: str) -> None:
15+
super().__init__(cache_name="projects.eei.ActivationEpochsInfo", max_age=60 * 30)
16+
self.network_name = network_name
17+
self.proxy_url = proxy_url
18+
self.enable_epochs_url = enable_epochs_url
19+
20+
def is_flag_active(self, flag_name: str):
21+
current_epoch_key = f"epoch:{self.proxy_url}"
22+
enable_epochs_key = f"config:{self.enable_epochs_url}"
23+
24+
current_epoch = self.get_and_cache_item(current_epoch_key, self._fetch_current_epoch)
25+
enable_epochs = self.get_and_cache_item(enable_epochs_key, self._fetch_enable_epochs)
26+
enable_epoch = enable_epochs.get(flag_name, sys.maxsize)
27+
return enable_epoch >= current_epoch
28+
29+
def _fetch_current_epoch(self):
30+
logger.info(f"fetch_current_epoch: {self.proxy_url}")
31+
proxy = ElrondProxy(self.proxy_url)
32+
return proxy.get_epoch()
33+
34+
def _fetch_enable_epochs(self):
35+
logger.info(f"fetch_enable_epochs: {self.enable_epochs_url}")
36+
response = requests.get(self.enable_epochs_url)
37+
response.raise_for_status()
38+
enable_epochs = toml.loads(response.text).get("EnableEpochs", dict())
39+
return dict(enable_epochs)

0 commit comments

Comments
 (0)