-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #23 from multiversx/testing-suite-for-staking-v4
Testing suite for staking v4
- Loading branch information
Showing
81 changed files
with
1,576 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Testing suite using mvx python sdk and chain-simulator for staking-v4 feature | ||
|
||
## Overview: | ||
- All tests are written based on scenarios from the internal testing plan. | ||
|
||
## How to run: | ||
|
||
### 1) Create a virtual env | ||
`python3 -m venv ./venv` | ||
`source ./venv/bin/activate` | ||
|
||
### 2) Install all dependencies | ||
`pip3 install -r ./req.txt` | ||
|
||
### 3) Export PythonPath | ||
`export PYTHONPATH=.` | ||
|
||
### 4) Make sure [chain-simulator](https://github.com/multiversx/mx-chain-simulator-go) is: | ||
- Running | ||
- Running with a correct config (specific config can be found at the begging of every `./scenarios/_test.py`) | ||
- If you run chain-simulator on different port, you can edit it in `./scenarios/config.py` | ||
|
||
### 5) RUN | ||
`pytest scenarios/` - to run all scenarios | ||
`pytest scenarios/_17.py` - to run a specific scenario | ||
|
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,79 @@ | ||
import requests | ||
import json | ||
|
||
from config import * | ||
from get_info import * | ||
from constants import * | ||
import time | ||
|
||
|
||
def send_egld_to_address(egld_amount, erd_address): | ||
details = { | ||
'address': f'{erd_address}', | ||
'balance': f'{egld_amount}' | ||
} | ||
|
||
details_list = [details] | ||
json_structure = json.dumps(details_list) | ||
response = requests.post(f"{DEFAULT_PROXY}/simulator/set-state", data=json_structure) | ||
response.raise_for_status() | ||
|
||
return response.text | ||
|
||
|
||
def add_blocks(nr_of_blocks): | ||
req = requests.post(f"{DEFAULT_PROXY}/simulator/generate-blocks/{nr_of_blocks}") | ||
return req.text | ||
|
||
|
||
def add_blocks_until_epoch_reached(epoch_to_be_reached: int): | ||
req = requests.post(f"{DEFAULT_PROXY}/simulator/generate-blocks-until-epoch-reached/{str(epoch_to_be_reached)}") | ||
return req.text | ||
|
||
|
||
def add_blocks_until_tx_fully_executed(tx_hash) -> str: | ||
print("Checking: ", tx_hash) | ||
counter = 0 | ||
|
||
while counter < MAX_NUM_OF_BLOCKS_UNTIL_TX_SHOULD_BE_EXECUTED: | ||
add_blocks(1) | ||
|
||
time.sleep(WAIT_UNTIL_API_REQUEST_IN_SEC) | ||
if get_status_of_tx(tx_hash) == "pending": | ||
counter += 1 | ||
else: | ||
print("Tx fully executed after", counter, " blocks.") | ||
return get_status_of_tx(tx_hash) | ||
|
||
|
||
def is_chain_online() -> bool: | ||
flag = False | ||
|
||
while not flag: | ||
time.sleep(1) | ||
try: | ||
response = requests.get(f"{DEFAULT_PROXY}/network/status/0") | ||
print(response) | ||
flag = True | ||
except requests.exceptions.ConnectionError: | ||
print("Chain not started jet") | ||
|
||
return flag | ||
|
||
|
||
def force_reset_validator_statistics(): | ||
req = requests.post(f"{DEFAULT_PROXY}/simulator/force-reset-validator-statistics") | ||
print(req.text) | ||
|
||
return req.text | ||
|
||
|
||
def add_key(private_keys: list) -> str: | ||
post_body = { | ||
"privateKeysBase64": private_keys | ||
} | ||
|
||
json_structure = json.dumps(post_body) | ||
req = requests.post(f"{DEFAULT_PROXY}/simulator/add-keys", data=json_structure) | ||
|
||
return req.text |
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,28 @@ | ||
from pathlib import Path | ||
from multiversx_sdk_network_providers import ProxyNetworkProvider | ||
|
||
|
||
PROXY_PUBLIC_TESTNET = "https://testnet-gateway.multiversx.com" | ||
PROXY_PUBLIC_DEVNET = "https://devnet-gateway.multiversx.com" | ||
PROXY_CHAIN_SIMULATOR = "http://localhost:8085" | ||
|
||
DEFAULT_PROXY = PROXY_CHAIN_SIMULATOR | ||
|
||
try: | ||
proxy_default = ProxyNetworkProvider(DEFAULT_PROXY) | ||
except: | ||
Exception | ||
|
||
chain_id = "chain" | ||
|
||
# relative path to chain-simulator | ||
chain_simulator_path = Path("../../cmd/chainsimulator") | ||
|
||
# config for cli flags for starting chain simulator | ||
log_level = '"*:DEBUG,process:TRACE"' | ||
num_validators_per_shard = "10" | ||
num_validators_meta = "10" | ||
num_waiting_validators_per_shard = "6" | ||
num_waiting_validators_meta = "6" | ||
|
||
rounds_per_epoch = "50" |
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,17 @@ | ||
# contracts | ||
VALIDATOR_CONTRACT = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqplllst77y4l" | ||
SYSTEM_DELEGATION_MANAGER_CONTRACT = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqylllslmq6y6" | ||
STAKING_CONTRACT = "erd1qqqqqqqqqqqqqqqpqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqllls0lczs7" | ||
|
||
|
||
# timing | ||
WAIT_UNTIL_API_REQUEST_IN_SEC = 0.5 | ||
|
||
# chain | ||
MAX_NUM_OF_BLOCKS_UNTIL_TX_SHOULD_BE_EXECUTED = 8 | ||
|
||
# staking_v4 | ||
EPOCH_WITH_STAKING_V3_5 = 3 | ||
EPOCH_STAKING_QUEUE_BECOMES_AUCTION_LIST = 4 | ||
EPOCH_SHUFFLING_FROM_ELIGIBLE_TO_AUCTION_LIST = 5 | ||
EPOCH_STAKING_V4_FULLY_FUNCTIONAL = 6 |
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,49 @@ | ||
import stat | ||
|
||
from constants import * | ||
from config import * | ||
import os | ||
import signal | ||
import subprocess | ||
from subprocess import Popen | ||
from threading import Thread | ||
import threading | ||
|
||
|
||
class ChainSimulator: | ||
def __init__(self, path: Path) -> None: | ||
self.path = path | ||
self.log_level = log_level | ||
self.num_validators_per_shard = num_validators_per_shard | ||
self.num_validators_meta = num_validators_meta | ||
self.num_waiting_validators_per_shard = num_waiting_validators_per_shard | ||
self.num_waiting_validators_meta = num_waiting_validators_meta | ||
self.rounds_per_epoch = rounds_per_epoch | ||
self.process = None | ||
|
||
def start(self): | ||
command = f"./chainsimulator --log-level {self.log_level} --rounds-per-epoch {rounds_per_epoch}\ | ||
-num-validators-per-shard {self.num_validators_per_shard} \ | ||
-num-waiting-validators-per-shard {num_waiting_validators_per_shard} \ | ||
-num-validators-meta {num_validators_meta} \ | ||
-num-waiting-validators-meta {num_waiting_validators_meta}" | ||
|
||
flag = True | ||
while flag: | ||
if " " in command: | ||
command = command.replace(" ", " ") | ||
else: | ||
flag = False | ||
print(command) | ||
|
||
self.process = subprocess.Popen(command, stdout=subprocess.PIPE, | ||
shell=True, preexec_fn=os.setsid, cwd=chain_simulator_path) | ||
|
||
out, err = self.process.communicate() | ||
if err: | ||
print(err) | ||
|
||
def stop(self) -> None: | ||
self.process.terminate() | ||
|
||
|
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,76 @@ | ||
import requests | ||
|
||
from core.wallet import * | ||
from pathlib import Path | ||
from helpers import * | ||
from get_info import * | ||
from constants import * | ||
from chain_commander import * | ||
|
||
|
||
class ValidatorKey: | ||
def __init__(self, path: Path) -> None: | ||
self.path = path | ||
|
||
def public_address(self) -> str: | ||
f = open(self.path) | ||
lines = f.readlines() | ||
for line in lines: | ||
if "BEGIN" in line: | ||
line = line.split(" ") | ||
address = line[-1].replace("-----", "") | ||
if "\n" in address: | ||
address = address.replace("\n", "") | ||
break | ||
return address | ||
|
||
# is using vm-query with "getBlsKeysStatus" function | ||
def get_status(self, owner_address: str) -> str: | ||
owner_address = Address.from_bech32(owner_address).to_hex() | ||
key_status_pair = get_bls_key_status([owner_address]) | ||
if key_status_pair is None: | ||
return "no bls keys on this owner" | ||
for key, status in key_status_pair.items(): | ||
if key == self.public_address(): | ||
return status | ||
|
||
# is using /validator/statistics route | ||
def get_state(self) -> str: | ||
force_reset_validator_statistics() | ||
|
||
# sometimes it needs a second until cache is resetting | ||
time.sleep(1) | ||
|
||
response = requests.get(f"{DEFAULT_PROXY}/validator/statistics") | ||
response.raise_for_status() | ||
parsed = response.json() | ||
|
||
general_data = parsed.get("data") | ||
general_statistics = general_data.get("statistics") | ||
key_data = general_statistics.get(self.public_address()) | ||
if key_data is None: | ||
return "Key not present in validator/statistics" | ||
else: | ||
status = key_data.get("validatorStatus") | ||
return status | ||
|
||
# using getOwner vm-query | ||
def belongs_to(self, address: str) -> bool: | ||
owner = get_owner([self.public_address()]) | ||
if owner == address: | ||
return True | ||
else: | ||
return False | ||
|
||
def get_private_key(self) -> str: | ||
private_key = "" | ||
|
||
f = open(self.path) | ||
lines = f.readlines() | ||
for line in lines: | ||
if not "BEGIN" in line and not "END" in line: | ||
private_key += line | ||
if "\n" in private_key: | ||
private_key = private_key.replace("\n", "") | ||
|
||
return private_key |
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,61 @@ | ||
from pathlib import Path | ||
from config import * | ||
import requests | ||
import json | ||
from multiversx_sdk_network_providers import ProxyNetworkProvider | ||
from multiversx_sdk_wallet import UserSigner | ||
from multiversx_sdk_core import Address | ||
from multiversx_sdk_network_providers import accounts | ||
from helpers import * | ||
from constants import * | ||
|
||
|
||
class Wallet: | ||
def __init__(self, path: Path) -> None: | ||
self.path = path | ||
|
||
def public_address(self) -> str: | ||
f = open(self.path) | ||
|
||
lines = f.readlines() | ||
for line in lines: | ||
if "BEGIN" in line: | ||
line = line.split(" ") | ||
address = line[-1].replace("-----", "") | ||
if "\n" in address: | ||
address = address.replace("\n", "") | ||
break | ||
|
||
return address | ||
|
||
def get_balance(self) -> int: | ||
response = requests.get(f"{DEFAULT_PROXY}/address/{self.public_address()}/balance") | ||
response.raise_for_status() | ||
parsed = response.json() | ||
|
||
general_data = parsed.get("data") | ||
balance = general_data.get("balance") | ||
|
||
return balance | ||
|
||
|
||
def set_balance(self, egld_amount): | ||
details = { | ||
'address': f'{self.public_address()}', | ||
'balance': f'{egld_amount}' | ||
} | ||
|
||
details_list = [details] | ||
json_structure = json.dumps(details_list) | ||
req = requests.post(f"{DEFAULT_PROXY}/simulator/set-state", data=json_structure) | ||
|
||
return req.text | ||
|
||
def get_signer(self) -> UserSigner: | ||
return UserSigner.from_pem_file(self.path) | ||
|
||
def get_address(self) -> Address: | ||
return Address.from_bech32(self.public_address()) | ||
|
||
def get_account(self): | ||
return proxy_default.get_account(self.get_address()) |
Oops, something went wrong.