Skip to content

Commit

Permalink
Merge pull request #55 from ElrondNetwork/vmtools-and-contracts
Browse files Browse the repository at this point in the history
Contract additions and `vmtools`
  • Loading branch information
camilbancioiu authored Nov 1, 2021
2 parents 8a54a0c + b214dd3 commit 52413dc
Show file tree
Hide file tree
Showing 16 changed files with 455 additions and 410 deletions.
668 changes: 344 additions & 324 deletions erdpy/CLI.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion erdpy/CLI.md.sh
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ generate() {
group "Account" "account"
command "Account.Get" "account get"
command "Account.GetTransactions" "account get-transactions"

group "Wallet" "wallet"
command "Wallet.New" "wallet new"
command "Wallet.Derive" "wallet derive"
command "Wallet.Bech32" "wallet bech32"

Expand Down
6 changes: 3 additions & 3 deletions erdpy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,10 +148,10 @@ def get_defaults() -> Dict[str, Any]:
"proxy": "https://testnet-gateway.elrond.com",
"chainID": "T",
"txVersion": "1",
"dependencies.arwentools.tag": "latest",
"dependencies.vmtools.tag": "latest",
"dependencies.elrond_wasm_rs.tag": "latest",
"dependencies.arwentools.urlTemplate.linux": "https://github.com/ElrondNetwork/arwen-wasm-vm/archive/{TAG}.tar.gz",
"dependencies.arwentools.urlTemplate.osx": "https://github.com/ElrondNetwork/arwen-wasm-vm/archive/{TAG}.tar.gz",
"dependencies.vmtools.urlTemplate.linux": "https://github.com/ElrondNetwork/wasm-vm/archive/{TAG}.tar.gz",
"dependencies.vmtools.urlTemplate.osx": "https://github.com/ElrondNetwork/wasm-vm/archive/{TAG}.tar.gz",
"dependencies.llvm.tag": "v9-19feb",
"dependencies.llvm.urlTemplate.linux": "https://ide.elrond.com/vendor-llvm/{TAG}/linux-amd64.tar.gz?t=19feb",
"dependencies.llvm.urlTemplate.osx": "https://ide.elrond.com/vendor-llvm/{TAG}/darwin-amd64.tar.gz?t=19feb",
Expand Down
4 changes: 2 additions & 2 deletions erdpy/constants.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
VM_TYPE_SYSTEM = "0001"
VM_TYPE_ARWEN = "0500"
VM_TYPE_WASM_VM = "0500"
SC_HEX_PUBKEY_PREFIX = "0" * 16
SC_HEX_PUBKEY_PREFIX_SYSTEM = SC_HEX_PUBKEY_PREFIX + VM_TYPE_SYSTEM + "0" * 30
SC_HEX_PUBKEY_PREFIX_ARWEN = SC_HEX_PUBKEY_PREFIX + VM_TYPE_ARWEN
SC_HEX_PUBKEY_PREFIX_WASM_VM = SC_HEX_PUBKEY_PREFIX + VM_TYPE_WASM_VM
2 changes: 1 addition & 1 deletion erdpy/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def deploy(self, owner: Account, arguments: List[Any], gas_price: int, gas_limit
return tx

def prepare_deploy_transaction_data(self, arguments: List[Any]):
tx_data = f"{self.bytecode}@{constants.VM_TYPE_ARWEN}@{self.metadata.to_hex()}"
tx_data = f"{self.bytecode}@{constants.VM_TYPE_WASM_VM}@{self.metadata.to_hex()}"

for arg in arguments:
tx_data += f"@{_prepare_argument(arg)}"
Expand Down
16 changes: 13 additions & 3 deletions erdpy/dependencies/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Dict, List

from erdpy import config, errors
from erdpy.dependencies.modules import (ArwenToolsModule, DependencyModule,
from erdpy.dependencies.modules import (VMToolsModule, DependencyModule,
GolangModule, MclSignerModule,
NodejsModule, Rust, StandaloneModule)

Expand All @@ -12,7 +12,7 @@

def install_module(key: str, tag: str = "", overwrite: bool = False):
if key == 'all':
modules = get_all_deps()
modules = get_all_deps_installable_via_cli()
else:
modules = [get_module_by_key(key)]

Expand Down Expand Up @@ -47,7 +47,7 @@ def get_deps_dict() -> Dict[str, DependencyModule]:
def get_all_deps() -> List[DependencyModule]:
return [
StandaloneModule(key="llvm", aliases=["clang", "cpp"]),
ArwenToolsModule(key="arwentools"),
VMToolsModule(key="vmtools"),
Rust(key="rust"),
NodejsModule(key="nodejs", aliases=[]),
StandaloneModule(key="elrond_go", repo_name="elrond-go", organisation="ElrondNetwork"),
Expand All @@ -57,6 +57,16 @@ def get_all_deps() -> List[DependencyModule]:
]


def get_all_deps_installable_via_cli() -> List[DependencyModule]:
return [
VMToolsModule(key="vmtools"),
StandaloneModule(key="elrond_go", repo_name="elrond-go", organisation="ElrondNetwork"),
StandaloneModule(key="elrond_proxy_go", repo_name="elrond-proxy-go", organisation="ElrondNetwork"),
MclSignerModule(key="mcl_signer")
]



def get_golang() -> GolangModule:
golang = get_module_by_key('golang')
assert isinstance(golang, GolangModule)
Expand Down
7 changes: 2 additions & 5 deletions erdpy/dependencies/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,22 +143,19 @@ def _get_archive_path(self, tag: str) -> Path:
return archive


class ArwenToolsModule(StandaloneModule):
class VMToolsModule(StandaloneModule):
def __init__(self, key: str, aliases: List[str] = None):
if aliases is None:
aliases = list()

super().__init__(key, aliases)
self.repo_name = 'arwen-wasm-vm'
self.repo_name = 'wasm-vm'
self.organisation = 'ElrondNetwork'

def _post_install(self, tag: str):
dependencies.install_module('golang')

self.build_binary(tag, 'arwendebug')
self.build_binary(tag, 'test')

self.make_binary_symlink_in_parent_folder(tag, 'arwendebug', 'arwendebug')
self.make_binary_symlink_in_parent_folder(tag, 'test', 'mandos-test')
self.copy_libwasmer_in_parent_directory(tag)

Expand Down
2 changes: 1 addition & 1 deletion erdpy/projects/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def run_tests(args: Any):

logger.info("run_tests.project: %s", project)

dependencies.install_module("arwentools")
dependencies.install_module("vmtools")

guards.is_directory(project)
project = load_project(project)
Expand Down
31 changes: 15 additions & 16 deletions erdpy/projects/project_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def build(self, options: Union[Dict[str, Any], None] = None) -> Path:
return self._do_after_build()

def clean(self):
utils.remove_folder(self._get_output_folder())
utils.remove_folder(self.get_output_folder())

def _ensure_dependencies_installed(self):
module_keys = self.get_dependencies()
Expand All @@ -42,36 +42,35 @@ def perform_build(self) -> None:
def get_file_wasm(self):
return self.find_file_in_output("*.wasm")

def find_file_globally(self, pattern):
folder = self.directory
return self.find_file_in_folder(folder, pattern)
def find_file_globally(self, pattern: str) -> Path:
return self.find_file_in_folder(self.path, pattern)

def find_file_in_output(self, pattern):
folder = path.join(self.directory, "output")
def find_file_in_output(self, pattern: str) -> Path:
folder = self.path / 'output'
return self.find_file_in_folder(folder, pattern)

def find_file_in_folder(self, folder, pattern):
files = list(Path(folder).rglob(pattern))
def find_file_in_folder(self, folder: Path, pattern: str) -> Path:
files = list(folder.rglob(pattern))

if len(files) == 0:
raise errors.KnownError(f"No file matches pattern [{pattern}].")
if len(files) > 1:
logger.warning(f"More files match pattern [{pattern}]. Will pick first:\n{files}")

file = path.join(folder, files[0])
file = folder / files[0]
return Path(file).resolve()

def _do_after_build(self) -> Path:
raise NotImplementedError()

def _copy_to_output(self, source: str, destination: str = None) -> Path:
output_folder = self._get_output_folder()
def _copy_to_output(self, source: Path, destination: str = None) -> Path:
output_folder = self.get_output_folder()
utils.ensure_folder(output_folder)
destination = path.join(output_folder, destination) if destination else output_folder
output_wasm_file = shutil.copy(source, destination)
output_wasm_file = shutil.copy(str(source), destination)
return Path(output_wasm_file)

def _get_output_folder(self):
def get_output_folder(self):
return path.join(self.directory, "output")

def get_bytecode(self):
Expand All @@ -97,9 +96,9 @@ def default_config(self):
return dict()

def run_tests(self, tests_directory: str, wildcard: str = ""):
arwentools = cast(StandaloneModule, dependencies.get_module_by_key("arwentools"))
tool_env = arwentools.get_env()
tool = path.join(arwentools.get_parent_directory(), "mandos-test")
vmtools = cast(StandaloneModule, dependencies.get_module_by_key("vmtools"))
tool_env = vmtools.get_env()
tool = path.join(vmtools.get_parent_directory(), "mandos-test")
test_folder = path.join(self.directory, tests_directory)

if not wildcard:
Expand Down
7 changes: 4 additions & 3 deletions erdpy/projects/project_clang.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import logging
import os
import subprocess
from os import path
from pathlib import Path

from typing import List

from erdpy import dependencies, errors, myprocess, utils
from erdpy.projects.project_base import Project

Expand Down Expand Up @@ -135,9 +136,9 @@ def ensure_source_files(self):

self.config['source_files'] = source_files

def get_exported_functions(self):
def get_exported_functions(self) -> List[str]:
file_export = self.find_file_globally('*.export')
lines = utils.read_lines(file_export)
lines = utils.read_lines(str(file_export))
return lines

def default_config(self):
Expand Down
83 changes: 55 additions & 28 deletions erdpy/projects/project_rust.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,107 +14,134 @@
class ProjectRust(Project):
def __init__(self, directory):
super().__init__(directory)
self.cargo_file = self._get_cargo_file()
self.cargo_file = self.get_cargo_file()

def clean(self):
super().clean()
utils.remove_folder(path.join(self.directory, "wasm", "target"))

def _get_cargo_file(self):
cargo_path = path.join(self.directory, "Cargo.toml")
def get_cargo_file(self):
cargo_path = self.path / 'Cargo.toml'
return CargoFile(cargo_path)

def get_meta_folder(self):
return self.path / 'meta'

def perform_build(self):
meta = self.has_meta()
try:
if meta:
# The meta crate allows contract developers to add extra
# preparation steps before building.
self.run_meta()
self.run_cargo()
self._generate_abi()

# ABI generated separately for backwards compatibility
if not meta:
self.generate_abi()
except subprocess.CalledProcessError as err:
raise errors.BuildError(err.output)

def run_cargo(self):
env = self._get_env()
env = self.get_env()

args = [
"cargo",
"build",
"--target=wasm32-unknown-unknown",
"--release",
"--out-dir",
self._get_output_folder(),
self.get_output_folder(),
"-Z"
"unstable-options"
]
self._decorate_cargo_args(args)
self.decorate_cargo_args(args)

if not self.options.get("wasm_symbols"):
env["RUSTFLAGS"] = "-C link-arg=-s"

cwd = path.join(self.directory, "wasm")
return_code = myprocess.run_process_async(args, env=env, cwd=cwd)
cwd = self.path / 'wasm'
return_code = myprocess.run_process_async(args, env=env, cwd=str(cwd))
if return_code != 0:
raise errors.BuildError(f"error code = {return_code}, see output")

def _decorate_cargo_args(self, args):
def run_meta(self):
cwd = self.get_meta_folder()
env = self.get_env()

args = [
"cargo",
"run",
]

return_code = myprocess.run_process_async(args, env=env, cwd=str(cwd))
if return_code != 0:
raise errors.BuildError(f"error code = {return_code}, see output")

def decorate_cargo_args(self, args):
target_dir = self.options.get("cargo_target_dir")
if target_dir:
args.extend(["--target-dir", target_dir])

def _generate_abi(self):
if not self._has_abi():
def generate_abi(self):
if not self.has_abi():
return

args = [
"cargo",
"run"
]
self._decorate_cargo_args(args)
self.decorate_cargo_args(args)

env = self._get_env()
env = self.get_env()
cwd = path.join(self.directory, "abi")
sink = myprocess.FileOutputSink(self._get_abi_filepath())
sink = myprocess.FileOutputSink(self.get_abi_filepath())
return_code = myprocess.run_process_async(args, env=env, cwd=cwd, stdout_sink=sink)
if return_code != 0:
raise errors.BuildError(f"error code = {return_code}, see output")

utils.prettify_json_file(self._get_abi_filepath())
utils.prettify_json_file(self.get_abi_filepath())

def has_meta(self):
return (self.get_meta_folder() / "Cargo.toml").exists()

def _has_abi(self):
return (self._get_abi_folder() / "Cargo.toml").exists()
def has_abi(self):
return (self.get_abi_folder() / "Cargo.toml").exists()

def _get_abi_filepath(self):
return self._get_abi_folder() / "abi.json"
def get_abi_filepath(self):
return self.get_abi_folder() / "abi.json"

def _get_abi_folder(self):
def get_abi_folder(self):
return Path(self.directory, "abi")

def _do_after_build(self) -> Path:
original_name = self.cargo_file.package_name
wasm_base_name = self.cargo_file.package_name.replace("-", "_")
wasm_file = Path(self._get_output_folder(), f"{wasm_base_name}_wasm.wasm").resolve()
wasm_file = Path(self.get_output_folder(), f"{wasm_base_name}_wasm.wasm").resolve()
wasm_file_renamed = self.options.get("wasm_name")
if not wasm_file_renamed:
wasm_file_renamed = f"{original_name}.wasm"
wasm_file_renamed_path = Path(self._get_output_folder(), wasm_file_renamed)
wasm_file_renamed_path = Path(self.get_output_folder(), wasm_file_renamed)
shutil.move(wasm_file, wasm_file_renamed_path)

if self._has_abi():
abi_file = self._get_abi_filepath()
abi_file_renamed = Path(self._get_output_folder(), f"{original_name}.abi.json")
if self.has_abi():
abi_file = self.get_abi_filepath()
abi_file_renamed = Path(self.get_output_folder(), f"{original_name}.abi.json")
shutil.move(abi_file, abi_file_renamed)

return wasm_file_renamed_path

def get_dependencies(self):
return ["rust"]

def _get_env(self):
def get_env(self):
return dependencies.get_module_by_key("rust").get_env()


class CargoFile:
data: Dict[str, Any]

def __init__(self, path):
def __init__(self, path: Path):
self.data = {}
self.path = path

Expand Down
2 changes: 1 addition & 1 deletion erdpy/scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize():
testnet_config = TestnetConfiguration.from_file(testnet_toml)
proxy = f"http://localhost:{testnet_config.proxy_port()}"
except FileNotFoundError:
logger.warn("components of the testnet may be missing")
pass


def get_chain_id():
Expand Down
Loading

0 comments on commit 52413dc

Please sign in to comment.