-
Notifications
You must be signed in to change notification settings - Fork 353
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Solution: solo machine binary injected via Nix environment + a custom test set for a solo machine
- Loading branch information
1 parent
ef0bb6d
commit 3fdc974
Showing
6 changed files
with
326 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
devnet-solomachine: | ||
validators: | ||
- coins: 1000cro | ||
staked: 1000cro | ||
accounts: | ||
- name: solo-signer | ||
mnemonic: 'awesome there minute cash write immune tag reopen price congress trouble reunion south wisdom donate credit below leave wisdom eagle sail siege rice train' | ||
coins: 1500cro | ||
consensus: | ||
timeout_commit: "5s" | ||
genesis: | ||
consensus_params: | ||
block: | ||
max_bytes: "1048576" | ||
max_gas: "81500000" | ||
time_iota_ms: "1000" | ||
evidence: | ||
max_age_num_blocks: "403200" | ||
max_age_duration: "2419200000000000" | ||
max_bytes: "150000" | ||
app_state: | ||
distribution: | ||
params: | ||
community_tax: "0" | ||
base_proposer_reward: "0" | ||
bonus_proposer_reward: "0" | ||
gov: | ||
deposit_params: | ||
max_deposit_period: "21600000000000ns" | ||
min_deposit: [{"denom":"basecro","amount":"2000000000000"}] | ||
voting_params: | ||
voting_period: "21600000000000ns" | ||
mint: | ||
minter: | ||
inflation: "0.000000000000000000" | ||
params: | ||
blocks_per_year: "6311520" | ||
mint_denom: "basecro" | ||
inflation_rate_change: "0" | ||
inflation_max: "0" | ||
inflation_min: "0" | ||
goal_bonded: "1" | ||
slashing: | ||
params: | ||
downtime_jail_duration: "3600s" | ||
min_signed_per_window: "0.5" | ||
signed_blocks_window: "5000" | ||
slash_fraction_double_sign: "0" | ||
slash_fraction_downtime: "0" | ||
staking: | ||
params: | ||
bond_denom: "basecro" | ||
historical_entries: "10000" | ||
max_entries: "7" | ||
max_validators: "50" | ||
unbonding_time: "2419200000000000ns" | ||
transfer: | ||
params: | ||
receive_enabled: true | ||
send_enabled: true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ pkgs ? import <nixpkgs> { } }: | ||
let | ||
version = "v0.1.2"; | ||
srcUrl = { | ||
x86_64-linux = { | ||
url = | ||
"https://github.com/crypto-com/ibc-solo-machine/releases/download/${version}/ubuntu-latest-${version}.tar.gz"; | ||
sha256 = "sha256-GEfHyUKvq69RAGWv29PAG3pFlBraXXhdkTcG045dePw="; | ||
}; | ||
x86_64-darwin = { | ||
url = | ||
"https://github.com/crypto-com/ibc-solo-machine/releases/download/${version}/macos-latest-${version}.tar.gz"; | ||
sha256 = "sha256-zx4342stMYzgQDXAKwnZKSfdLynGIApOFKZ+CjRCyaE="; | ||
}; | ||
}.${pkgs.stdenv.system} or (throw | ||
"Unsupported system: ${pkgs.stdenv.system}"); | ||
in | ||
pkgs.stdenv.mkDerivation { | ||
name = "solomachine"; | ||
inherit version; | ||
src = pkgs.fetchurl srcUrl; | ||
sourceRoot = "."; | ||
installPhase = '' | ||
echo "installing solomachine ..." | ||
echo $out | ||
mkdir -p $out/solomachine | ||
install -m 755 -v -D * $out/solomachine | ||
echo `env` | ||
''; | ||
meta = with pkgs.lib; { platforms = with platforms; linux ++ darwin; }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
import json | ||
import os | ||
import platform | ||
from pathlib import Path | ||
|
||
import pytest | ||
import requests | ||
import yaml | ||
from pystarport import ports | ||
from pystarport.utils import interact | ||
|
||
from .utils import cluster_fixture, wait_for_block, wait_for_port | ||
|
||
pytestmark = pytest.mark.solomachine | ||
|
||
|
||
@pytest.fixture(scope="module") | ||
def cluster(worker_index, pytestconfig, tmp_path_factory): | ||
"override cluster fixture for this test module" | ||
try: | ||
yield from cluster_fixture( | ||
Path(__file__).parent / "configs/solo_machine.yaml", | ||
worker_index, | ||
tmp_path_factory.mktemp("data"), | ||
) | ||
finally: | ||
pass | ||
|
||
|
||
def parse_output(output, return_json=True): | ||
s = output.decode("utf-8") | ||
s = s.replace("\u001b[0m", "") | ||
print(s) | ||
if return_json: | ||
data = json.loads(s) | ||
return data | ||
else: | ||
return s | ||
|
||
|
||
CRO_DECIMALS = 10 ** 8 | ||
SOLO_HD_PATH = "m/44'/394'/0'/0/0" | ||
SOLO_ACCOUNT_PREFIX = "cro" | ||
SOLO_ADDRESS_ALGO = "secp256k1" | ||
SOLO_FEE_DENOM = "basecro" | ||
SOLO_DENOM = "solotoken" | ||
|
||
|
||
class SoloMachine(object): | ||
def __init__( | ||
self, temp_path, mnemonic, base_port=26650, chain_id="devnet-solomachine" | ||
): | ||
self.chain_id = chain_id | ||
self.grpc_port = ports.grpc_port(base_port) | ||
self.rpc_port = ports.rpc_port(base_port) | ||
self.solomachine_home = os.path.join(os.environ["SOLO_MACHINE_HOME"]) | ||
self.bin_file = os.path.join(self.solomachine_home, "solo-machine") | ||
self.mnemonic = mnemonic | ||
|
||
os_platform = platform.system() | ||
if os_platform == "Darwin": | ||
self.sign_file = os.path.join( | ||
self.solomachine_home, "libmnemonic_signer.dylib" | ||
) | ||
else: | ||
self.sign_file = os.path.join( | ||
self.solomachine_home, "libmnemonic_signer.so" | ||
) | ||
self.trusted_height = None | ||
self.trusted_hash = None | ||
self.db_path = f'sqlite://{temp_path.join("solo-machine.db")}' | ||
|
||
def get_chain_info(self): | ||
result = requests.get(f"http://127.0.0.1:{self.rpc_port}/block").json() | ||
self.trusted_hash = result["result"]["block_id"]["hash"] | ||
self.trusted_height = result["result"]["block"]["header"]["height"] | ||
|
||
def set_env(self): | ||
os.environ["SOLO_DB_URI"] = self.db_path | ||
os.environ["SOLO_SIGNER"] = self.sign_file | ||
os.environ["SOLO_MNEMONIC"] = self.mnemonic | ||
os.environ["SOLO_HD_PATH"] = SOLO_HD_PATH | ||
os.environ["SOLO_ACCOUNT_PREFIX"] = SOLO_ACCOUNT_PREFIX | ||
os.environ["SOLO_ADDRESS_ALGO"] = SOLO_ADDRESS_ALGO | ||
os.environ["SOLO_FEE_DENOM"] = SOLO_FEE_DENOM | ||
os.environ["SOLO_FEE_AMOUNT"] = "1000" | ||
os.environ["SOLO_GAS_LIMIT"] = "300000" | ||
os.environ["SOLO_GRPC_ADDRESS"] = f"http://0.0.0.0:{self.grpc_port}" | ||
os.environ["SOLO_RPC_ADDRESS"] = f"http://0.0.0.0:{self.rpc_port}" | ||
os.environ["SOLO_TRUSTED_HASH"] = self.trusted_hash | ||
os.environ["SOLO_TRUSTED_HEIGHT"] = self.trusted_height | ||
|
||
def prepare(self): | ||
self.get_chain_info() | ||
self.set_env() | ||
|
||
def run_sub_cmd(self, sub_cmd, json_output=True): | ||
if json_output: | ||
cmd = f"{self.bin_file} --output json {sub_cmd}" | ||
else: | ||
cmd = f"{self.bin_file} {sub_cmd}" | ||
output = interact(cmd) | ||
data = parse_output(output, json_output) | ||
return data | ||
|
||
def init(self): | ||
sub_cmd = "init" | ||
return self.run_sub_cmd(sub_cmd) | ||
|
||
def add_chain(self): | ||
sub_cmd = "chain add" | ||
return self.run_sub_cmd(sub_cmd) | ||
|
||
def connect_chain(self): | ||
sub_cmd = f"ibc connect {self.chain_id}" | ||
result = self.run_sub_cmd(sub_cmd, False) | ||
if "error" in result: | ||
raise Exception(result) | ||
|
||
def get_balance(self): | ||
sub_cmd = f"chain balance {self.chain_id} {SOLO_DENOM}" | ||
return self.run_sub_cmd(sub_cmd)["data"]["balance"] | ||
|
||
def mint(self, amount=20): | ||
sub_cmd = f"ibc mint {self.chain_id} {amount} {SOLO_DENOM}" | ||
return self.run_sub_cmd(sub_cmd) | ||
|
||
def burn(self, amount=10): | ||
sub_cmd = f"ibc burn {self.chain_id} {amount} {SOLO_DENOM}" | ||
return self.run_sub_cmd(sub_cmd) | ||
|
||
|
||
def get_balance(cluster, addr): | ||
raw = cluster.cosmos_cli(0).raw | ||
node = cluster.node_rpc(0) | ||
coin = json.loads(raw("query", "bank", "balances", addr, output="json", node=node))[ | ||
"balances" | ||
] | ||
if len(coin) == 0: | ||
return None | ||
return coin[0] | ||
|
||
|
||
def get_mnemonic(cli): | ||
config = yaml.safe_load(open(Path(__file__).parent / "configs/solo_machine.yaml")) | ||
return config[cli.chain_id]["accounts"][0]["mnemonic"] | ||
|
||
|
||
def test_solo_machine(cluster, tmpdir_factory): | ||
""" | ||
check solo machine | ||
""" | ||
cli = cluster | ||
wait_for_block(cli, 1) | ||
|
||
# get the chain balance | ||
chain_solo_addr = cluster.address("solo-signer") | ||
chain_balance_1 = cluster.balance(chain_solo_addr) | ||
assert chain_balance_1 == 1500 * CRO_DECIMALS | ||
|
||
base_port = cli.base_port(0) | ||
wait_for_port(ports.grpc_port(base_port)) | ||
tmp_path = tmpdir_factory.mktemp("db") | ||
mnemonic = get_mnemonic(cli) | ||
solo_machine = SoloMachine(tmp_path, mnemonic, base_port=base_port) | ||
solo_machine.prepare() | ||
data = solo_machine.init() | ||
assert data["result"] == "success" | ||
data = solo_machine.add_chain() | ||
assert data["result"] == "success" | ||
wait_for_block(cli, 2) | ||
solo_machine.connect_chain() | ||
wait_for_block(cli, 2) | ||
balance_0 = int(solo_machine.get_balance()) | ||
assert balance_0 == 0 | ||
|
||
# mint | ||
data = solo_machine.mint(20) | ||
assert data["result"] == "success" | ||
assert int(data["data"]["amount"], 16) == 20 | ||
wait_for_block(cli, 2) | ||
balance_1 = int(solo_machine.get_balance()) | ||
assert balance_1 == 20 | ||
|
||
# check the chain balance | ||
|
||
chain_balance_2 = get_balance(cli, chain_solo_addr) | ||
assert int(chain_balance_2["amount"]) < chain_balance_1 | ||
assert chain_balance_2["denom"] == SOLO_FEE_DENOM | ||
|
||
# burn | ||
data = solo_machine.burn(10) | ||
assert data["result"] == "success" | ||
assert int(data["data"]["amount"], 16) == 10 | ||
wait_for_block(cli, 2) | ||
balance_2 = int(solo_machine.get_balance()) | ||
assert balance_2 == balance_1 - 10 | ||
|
||
# check the chain balance | ||
chain_balance_3 = get_balance(cli, chain_solo_addr) | ||
assert int(chain_balance_3["amount"]) < int(chain_balance_2["amount"]) | ||
assert chain_balance_3["denom"] == SOLO_FEE_DENOM |