Methods needed to networks creation are inserted into newly created `shared_tools` package

This commit is contained in:
Mariusz 2022-10-13 14:36:50 +02:00 committed by Krzysztof Mochocki
parent 85506512b9
commit cd93185c44
25 changed files with 494 additions and 342 deletions

View File

@ -231,7 +231,7 @@ plugin_test:
before_script:
- python3 -m venv venv/
- . venv/bin/activate
- pip3 install pytest==${PYTEST_VERSION} pytest-xdist==${PYTEST_XDIST_VERSION} pytest-timeout==${PYTEST_TIMEOUT_VERSION} "$CI_PROJECT_DIR/tests/test_tools" "$CI_PROJECT_DIR/tests/schemas"
- pip3 install pytest==${PYTEST_VERSION} pytest-xdist==${PYTEST_XDIST_VERSION} pytest-timeout==${PYTEST_TIMEOUT_VERSION} "$CI_PROJECT_DIR/tests/test_tools" "$CI_PROJECT_DIR/tests/schemas" "$CI_PROJECT_DIR/tests/shared_tools"
artifacts:
reports:
junit: $JUNIT_REPORT

View File

@ -1,11 +1,7 @@
import datetime
import pytest
import test_tools as tt
from ..local_tools import parse_datetime
def test_transaction(wallet):
wallet.api.create_account('initminer', 'carol', '{}')
@ -39,7 +35,7 @@ def test_transaction(wallet):
_expiration = response['expiration']
parsed_t = parse_datetime(_expiration)
parsed_t = tt.Time.parse(_expiration)
t_in_seconds = parsed_t.timestamp()
tt.logger.info('_time: {} seconds:{}...'.format(_expiration, t_in_seconds))
@ -56,7 +52,7 @@ def test_transaction(wallet):
_expiration = response['expiration']
parsed_t = parse_datetime(_expiration)
parsed_t = tt.Time.parse(_expiration)
t_in_seconds = parsed_t.timestamp()
tt.logger.info('_time: {} seconds:{}...'.format(_expiration, t_in_seconds))

View File

@ -3,54 +3,22 @@ from typing import Dict
import pytest
import test_tools as tt
from shared_tools.complex_networks import (allow_generate_block_log,
prepare_network_with_many_witnesses,
prepare_sub_networks)
from .local_tools import run_networks, display_info, prepare_sub_networks, allow_generate_block_log, create_block_log_directory_name
def create_block_log_directory_name(name : str):
return str(Path(__file__).parent.absolute()) + '/' + name
@pytest.fixture
def prepared_networks() -> Dict:
"""
Fixture consists of 1 init node, 8 witness nodes and 2 api nodes.
After fixture creation there are 21 active witnesses, and last irreversible block
is behind head block like in real network.
"""
tt.logger.info('Preparing fixture prepared_networks')
alpha_witness_names = [f'witness{i}-alpha' for i in range(10)]
beta_witness_names = [f'witness{i}-beta' for i in range(10)]
all_witness_names = alpha_witness_names + beta_witness_names
# Create first network
alpha_net = tt.Network() # TODO: Add network name prefix, e.g. AlphaNetwork0 (Alpha- is custom prefix)
init_node = tt.InitNode(network=alpha_net)
tt.WitnessNode(witnesses=[f'witness{i}-alpha' for i in range(0, 3)], network=alpha_net)
tt.WitnessNode(witnesses=[f'witness{i}-alpha' for i in range(3, 6)], network=alpha_net)
tt.WitnessNode(witnesses=[f'witness{i}-alpha' for i in range(6, 8)], network=alpha_net)
tt.WitnessNode(witnesses=[f'witness{i}-alpha' for i in range(8, 10)], network=alpha_net)
alpha_api_node = tt.ApiNode(network=alpha_net)
# Create second network
beta_net = tt.Network() # TODO: Add network name prefix, e.g. AlphaNetwork0 (Alpha- is custom prefix)
tt.WitnessNode(witnesses=[f'witness{i}-beta' for i in range(0, 3)], network=beta_net)
tt.WitnessNode(witnesses=[f'witness{i}-beta' for i in range(3, 6)], network=beta_net)
tt.WitnessNode(witnesses=[f'witness{i}-beta' for i in range(6, 8)], network=beta_net)
tt.WitnessNode(witnesses=[f'witness{i}-beta' for i in range(8, 10)], network=beta_net)
tt.ApiNode(network=beta_net)
blocklog_directory = Path(__file__).parent / 'block_log'
run_networks([alpha_net, beta_net], blocklog_directory)
wallet = tt.Wallet(attach_to=init_node)
display_info(wallet)
def prepare_basic_networks() -> Dict:
alpha_net, beta_net = prepare_network_with_many_witnesses(create_block_log_directory_name('block_log'))
yield {
'Alpha': alpha_net,
'Beta': beta_net,
}
@pytest.fixture
def prepare_sub_networks_10_11() -> Dict:
yield { 'sub-networks-data': prepare_sub_networks([10, 11]) }

View File

@ -1,9 +1,9 @@
import test_tools as tt
def test_enum_virtual_ops(prepared_networks):
def test_enum_virtual_ops(prepare_basic_networks):
# Test enum_virtual_ops for head block returns only virtual ops
api_node = prepared_networks['Alpha'].node('ApiNode0')
api_node = prepare_basic_networks['Alpha'].node('ApiNode0')
wallet = tt.Wallet(attach_to=api_node)
account_name = 'gamma-1'

View File

@ -1,5 +1,4 @@
from .local_tools import assert_no_duplicates, connect_sub_networks, disconnect_sub_networks, wait, fork_log, \
get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, lib_true_condition
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_2_sub_networks_00(prepare_fork_2_sub_networks_00):
@ -21,8 +20,8 @@ def test_fork_2_sub_networks_00(prepare_fork_2_sub_networks_00):
logs = []
logs.append(fork_log("M", tt.Wallet(attach_to = majority_api_node)))
logs.append(fork_log("m", tt.Wallet(attach_to = minority_api_node)))
logs.append(NodeLog("M", tt.Wallet(attach_to = majority_api_node)))
logs.append(NodeLog("m", tt.Wallet(attach_to = minority_api_node)))
_M = logs[0].collector
_m = logs[1].collector
@ -30,7 +29,7 @@ def test_fork_2_sub_networks_00(prepare_fork_2_sub_networks_00):
blocks_before_disconnect = 10
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, majority_api_node)
@ -56,4 +55,4 @@ def test_fork_2_sub_networks_00(prepare_fork_2_sub_networks_00):
wait_for_final_block(majority_api_node, logs, [_m, _M], True, lib_true_condition, False)
assert_no_duplicates(minority_api_node, majority_api_node)
assert_no_duplicates(minority_api_node, majority_api_node)

View File

@ -1,9 +1,9 @@
from .local_tools import enable_witnesses, disable_witnesses, get_part_of_witness_details, assert_no_duplicates, connect_sub_networks, \
disconnect_sub_networks, wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, lib_custom_condition
import test_tools as tt
from functools import partial
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_2_sub_networks_01(prepare_fork_2_sub_networks_01):
# start - A network (consists of a 'minority' network(6 witnesses) + a 'majority' network(17 witnesses)) produces blocks
@ -38,8 +38,8 @@ def test_fork_2_sub_networks_01(prepare_fork_2_sub_networks_01):
logs = []
logs.append(fork_log("M", tt.Wallet(attach_to = majority_api_node)))
logs.append(fork_log("m", tt.Wallet(attach_to = minority_api_node)))
logs.append(NodeLog("M", tt.Wallet(attach_to = majority_api_node)))
logs.append(NodeLog("m", tt.Wallet(attach_to = minority_api_node)))
_M = logs[0].collector
_m = logs[1].collector
@ -54,7 +54,7 @@ def test_fork_2_sub_networks_01(prepare_fork_2_sub_networks_01):
blocks_after_enable_witness = 5
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, majority_api_node)

View File

@ -1,5 +1,4 @@
from .local_tools import enable_witnesses, disable_witnesses, get_part_of_witness_details, assert_no_duplicates, connect_sub_networks,\
disconnect_sub_networks, wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, lib_true_condition
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_2_sub_networks_02(prepare_fork_2_sub_networks_02):
@ -38,8 +37,8 @@ def test_fork_2_sub_networks_02(prepare_fork_2_sub_networks_02):
logs = []
logs.append(fork_log("M", majority_witness_wallet))
logs.append(fork_log("m", tt.Wallet(attach_to = minority_api_node)))
logs.append(NodeLog("M", majority_witness_wallet))
logs.append(NodeLog("m", tt.Wallet(attach_to = minority_api_node)))
_M = logs[0].collector
_m = logs[1].collector
@ -55,7 +54,7 @@ def test_fork_2_sub_networks_02(prepare_fork_2_sub_networks_02):
blocks_after_reconnect = 5
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, majority_api_node)
@ -98,4 +97,4 @@ def test_fork_2_sub_networks_02(prepare_fork_2_sub_networks_02):
wait_for_final_block(minority_api_node, logs, [_m, _M], True, lib_true_condition, False)
assert_no_duplicates(minority_api_node, majority_api_node)
assert_no_duplicates(minority_api_node, majority_api_node)

View File

@ -1,8 +1,8 @@
from .local_tools import enable_witnesses, disable_witnesses, get_part_of_witness_details, assert_no_duplicates, connect_sub_networks, \
disconnect_sub_networks, wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, lib_true_condition
import test_tools as tt
from time import sleep
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_2_sub_networks_03(prepare_fork_2_sub_networks_03):
# start - A network (consists of a 'minority' network(3 witnesses) + a 'majority' network(18 witnesses)) produces blocks
@ -40,8 +40,8 @@ def test_fork_2_sub_networks_03(prepare_fork_2_sub_networks_03):
logs = []
logs.append(fork_log("M", majority_witness_wallet))
logs.append(fork_log("m", tt.Wallet(attach_to = minority_api_node)))
logs.append(NodeLog("M", majority_witness_wallet))
logs.append(NodeLog("m", tt.Wallet(attach_to = minority_api_node)))
_M = logs[0].collector
_m = logs[1].collector
@ -51,7 +51,7 @@ def test_fork_2_sub_networks_03(prepare_fork_2_sub_networks_03):
blocks_after_disable_witness = 10
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, majority_api_node)
@ -74,7 +74,7 @@ def test_fork_2_sub_networks_03(prepare_fork_2_sub_networks_03):
tt.logger.info(f'Reconnect sub networks')
connect_sub_networks(sub_networks)
sleep_seconds = 20
tt.logger.info(f'Before sleep {sleep_seconds}')
sleep(sleep_seconds)

View File

@ -1,10 +1,8 @@
from .local_tools import connect_sub_networks, disconnect_sub_networks, wait, fork_log, get_last_head_block_number, \
get_last_irreversible_block_num, wait_for_final_block, lib_custom_condition
import test_tools as tt
from functools import partial
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_3_sub_networks_00(prepare_fork_3_sub_networks_00):
# start - A network consists of a 'minority_3' network(3 witnesses), a 'minority_4' network(4 witnesses), a 'majority' network(14 witnesses).
@ -23,9 +21,9 @@ def test_fork_3_sub_networks_00(prepare_fork_3_sub_networks_00):
logs = []
logs.append(fork_log("m3", tt.Wallet(attach_to = minority_api_node_3)))
logs.append(fork_log("m4", tt.Wallet(attach_to = minority_api_node_4)))
logs.append(fork_log("M", tt.Wallet(attach_to = majority_api_node)))
logs.append(NodeLog("m3", tt.Wallet(attach_to = minority_api_node_3)))
logs.append(NodeLog("m4", tt.Wallet(attach_to = minority_api_node_4)))
logs.append(NodeLog("M", tt.Wallet(attach_to = majority_api_node)))
_m3 = logs[0].collector
_m4 = logs[1].collector
@ -35,7 +33,7 @@ def test_fork_3_sub_networks_00(prepare_fork_3_sub_networks_00):
blocks_after_disconnect = 10
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, majority_api_node)
@ -60,4 +58,4 @@ def test_fork_3_sub_networks_00(prepare_fork_3_sub_networks_00):
tt.logger.info(f'Reconnect sub networks')
connect_sub_networks(sub_networks)
wait_for_final_block(majority_api_node, logs, [_m3, _m4, _M], True, partial(lib_custom_condition, _M, last_lib), False)
wait_for_final_block(majority_api_node, logs, [_m3, _m4, _M], True, partial(lib_custom_condition, _M, last_lib), False)

View File

@ -1,10 +1,8 @@
from .local_tools import connect_sub_networks, disconnect_sub_networks, wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, \
wait_for_final_block, lib_custom_condition
import test_tools as tt
from functools import partial
from shared_tools.complex_networks_helper_functions import *
import test_tools as tt
def test_fork_3_sub_networks_01(prepare_fork_3_sub_networks_01):
# start - A network consists of a 'minority_7a' network(7 witnesses), a 'minority_7b' network(7 witnesses), a 'minority_7c' network(7 witnesses).
@ -23,9 +21,9 @@ def test_fork_3_sub_networks_01(prepare_fork_3_sub_networks_01):
logs = []
logs.append(fork_log("m7a", tt.Wallet(attach_to = minority_api_node_7a)))
logs.append(fork_log("m7b", tt.Wallet(attach_to = minority_api_node_7b)))
logs.append(fork_log("m7c", tt.Wallet(attach_to = minority_api_node_7c)))
logs.append(NodeLog("m7a", tt.Wallet(attach_to = minority_api_node_7a)))
logs.append(NodeLog("m7b", tt.Wallet(attach_to = minority_api_node_7b)))
logs.append(NodeLog("m7c", tt.Wallet(attach_to = minority_api_node_7c)))
_m7a = logs[0].collector
_m7b = logs[1].collector
@ -35,7 +33,7 @@ def test_fork_3_sub_networks_01(prepare_fork_3_sub_networks_01):
blocks_after_disconnect = 10
tt.logger.info(f'Before disconnecting')
cnt = 0
cnt = 0
while True:
wait(1, logs, minority_api_node_7a)

View File

@ -1,11 +1,9 @@
import test_tools as tt
from .local_tools import assert_no_duplicates
from shared_tools.complex_networks_helper_functions import *
def test_no_duplicates_in_account_history_plugin_after_fork(prepared_networks):
alpha_net = prepared_networks['Alpha']
beta_net = prepared_networks['Beta']
def test_no_duplicates_in_account_history_plugin_after_fork(prepare_basic_networks):
alpha_net = prepare_basic_networks['Alpha']
beta_net = prepare_basic_networks['Beta']
alpha_node = alpha_net.node('ApiNode0')
beta_node = beta_net.node('ApiNode1')

View File

@ -1,12 +1,12 @@
import test_tools as tt
from .local_tools import assert_no_duplicates
from shared_tools.complex_networks_helper_functions import assert_no_duplicates
def test_no_duplicates_in_account_history_plugin_after_restart(prepared_networks):
def test_no_duplicates_in_account_history_plugin_after_restart(prepare_basic_networks):
# TRIGGER
# We restart one of nodes.
api_node = prepared_networks['Alpha'].node('ApiNode0')
api_node = prepare_basic_networks['Alpha'].node('ApiNode0')
head_block_num = api_node.api.condenser.get_dynamic_global_properties()['head_block_number']
head_block_timestamp = api_node.api.block.get_block(block_num=head_block_num)['block']['timestamp']

View File

@ -1,6 +1,13 @@
from .local_tools import wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, wait_for_specific_witnesses
import test_tools as tt
import time
from shared_tools.complex_networks_helper_functions import (
wait,
get_last_head_block_number,
get_last_irreversible_block_num,
wait_for_final_block,
wait_for_specific_witnesses,
NodeLog
)
def test_obi_throw_exception_00(prepare_obi_throw_exception_00):
# start - A network (consists of a 'A' network(10 witnesses) + a 'B' network(11 witnesses)) produces blocks
@ -20,11 +27,11 @@ def test_obi_throw_exception_00(prepare_obi_throw_exception_00):
logs = []
logs.append(fork_log("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(fork_log("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(NodeLog("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(NodeLog("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(fork_log("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(fork_log("w1", tt.Wallet(attach_to = witness_node_1)))
logs.append(NodeLog("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(NodeLog("w1", tt.Wallet(attach_to = witness_node_1)))
blocks_after_exception = 5
blocks_wait = 1
@ -52,4 +59,4 @@ def test_obi_throw_exception_00(prepare_obi_throw_exception_00):
assert get_last_head_block_number(_a0) > last_lib_01
wait_for_final_block(witness_node_0, logs, [_a0, _w0, _a1, _w1])
wait_for_final_block(witness_node_0, logs, [_a0, _w0, _a1, _w1])

View File

@ -1,7 +1,15 @@
from .local_tools import wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_specific_witnesses
import test_tools as tt
import time
import test_tools as tt
from shared_tools.complex_networks_helper_functions import (
wait,
get_last_head_block_number,
get_last_irreversible_block_num,
wait_for_specific_witnesses,
NodeLog
)
def test_obi_throw_exception_01(prepare_obi_throw_exception_01):
# start - A network (consists of a 'A' network(10 witnesses) + a 'B' network(11 witnesses)) produces blocks
@ -49,11 +57,11 @@ def test_obi_throw_exception_01(prepare_obi_throw_exception_01):
logs = []
logs.append(fork_log("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(fork_log("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(NodeLog("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(NodeLog("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(fork_log("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(fork_log("w1", tt.Wallet(attach_to = witness_node_1)))
logs.append(NodeLog("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(NodeLog("w1", tt.Wallet(attach_to = witness_node_1)))
blocks_after_exception = 20
delay_seconds = 5

View File

@ -1,7 +1,16 @@
from .local_tools import wait, fork_log, get_last_head_block_number, get_last_irreversible_block_num, wait_for_final_block, wait_for_specific_witnesses
import test_tools as tt
import time
import test_tools as tt
from shared_tools.complex_networks_helper_functions import (
wait,
get_last_head_block_number,
get_last_irreversible_block_num,
wait_for_final_block,
wait_for_specific_witnesses,
NodeLog
)
def test_obi_throw_exception_02(prepare_obi_throw_exception_02):
# start - A network (consists of a 'A' network(10 witnesses) + a 'B' network(11 witnesses)) produces blocks
@ -22,11 +31,11 @@ def test_obi_throw_exception_02(prepare_obi_throw_exception_02):
logs = []
logs.append(fork_log("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(fork_log("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(NodeLog("a0", tt.Wallet(attach_to = api_node_0)))
logs.append(NodeLog("w0", tt.Wallet(attach_to = witness_node_0)))
logs.append(fork_log("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(fork_log("w1", tt.Wallet(attach_to = witness_node_1)))
logs.append(NodeLog("a1", tt.Wallet(attach_to = api_node_1)))
logs.append(NodeLog("w1", tt.Wallet(attach_to = witness_node_1)))
_a0 = logs[0].collector
_w0 = logs[1].collector
@ -57,4 +66,4 @@ def test_obi_throw_exception_02(prepare_obi_throw_exception_02):
assert get_last_head_block_number(_a0) > last_lib_01 + 1
wait_for_final_block(witness_node_0, logs, [_a0, _w0, _a1, _w1])
wait_for_final_block(witness_node_0, logs, [_a0, _w0, _a1, _w1])

View File

@ -1,8 +1,15 @@
from typing import Dict, Optional
import pytest
import test_tools as tt
from .local_tools import run_with_faketime, prepare_environment, prepare_environment_with_2_sub_networks
from shared_tools.complex_networks import init_network
def run_with_faketime(node, time):
#time example: '2020-01-01T00:00:00'
requested_start_time = tt.Time.parse(time)
node.run(time_offset=f'{tt.Time.serialize(requested_start_time, format_="@%Y-%m-%d %H:%M:%S")}')
@pytest.fixture
def node_hf25() -> tt.InitNode:
@ -28,6 +35,81 @@ def wallet_hf26(node_hf26) -> tt.Wallet:
return tt.Wallet(attach_to=node_hf26)
def prepare_network(
witnesses_number: int, network_name: str, allow_create_init_node: bool, allow_create_api_node: bool
):
tt.logger.info(f'Prototypes of nodes(init, witness, api) are created...')
witness_names = [f'wit{i}-{network_name}' for i in range(witnesses_number)]
network = tt.Network()
init_node = None
if allow_create_init_node:
init_node = tt.InitNode(network=network)
tt.WitnessNode(witnesses=witness_names, network=network)
api_node = None
if allow_create_api_node:
api_node = tt.ApiNode(network=network)
return witness_names, network, init_node, api_node
def prepare_environment(hard_fork_26_time):
all_witness_names, alpha_net, init_node, api_node = prepare_network(
witnesses_number=20, network_name='alpha', allow_create_init_node=True, allow_create_api_node=True
)
# Run
tt.logger.info('Running networks, waiting for live...')
date_as_seconds = calculate_epoch_time(hard_fork_26_time)
environment_variables: Optional[Dict] = {'HIVE_HF26_TIME': f'{date_as_seconds}'}
alpha_net.run(environment_variables)
init_network(init_node, all_witness_names)
return alpha_net
def prepare_environment_with_2_sub_networks(hard_fork_26_time_alpha, hard_fork_26_time_beta):
#Because HIVE_HARDFORK_REQUIRED_WITNESSES = 17 // 17 of the 21 dpos witnesses (20 elected and 1 chosen) required for hardfork
witness_names_alpha, alpha_net, init_node, api_node = prepare_network(
witnesses_number=8, network_name='alpha', allow_create_init_node=True, allow_create_api_node=True
)
witness_names_beta, beta_net, init_node2, api_node2 = prepare_network(
witnesses_number=12, network_name='beta', allow_create_init_node=False, allow_create_api_node=False
)
all_witness_names = witness_names_alpha + witness_names_beta
alpha_net.connect_with(beta_net)
# Run
tt.logger.info('Running networks, waiting for live...')
date_as_seconds = calculate_epoch_time(hard_fork_26_time_alpha)
environment_variables_alpha: Optional[Dict] = {'HIVE_HF26_TIME': f'{date_as_seconds}'}
date_as_seconds = calculate_epoch_time(hard_fork_26_time_beta)
environment_variables_beta: Optional[Dict] = {'HIVE_HF26_TIME': f'{date_as_seconds}'}
# June 20, 2032 9:45:38 AM
alpha_net.run(environment_variables_alpha)
# June 1, 2022 7:41:41 AM
beta_net.run(environment_variables_beta)
init_network(init_node, all_witness_names)
return alpha_net, beta_net
def calculate_epoch_time(date):
return int(tt.Time.parse(date).timestamp())
@pytest.fixture
def network_before_hf26():
tt.logger.info('Preparing fixture network_before_hf26')

View File

@ -1,12 +1,14 @@
from datetime import timezone
from datetime import datetime, timezone
from typing import Dict, Optional
import pytest
import test_tools as tt
from ..local_tools import init_network, parse_datetime
from shared_tools.complex_networks import init_network
def parse_datetime(datetime_: str) -> datetime:
return datetime.strptime(datetime_, '%Y-%m-%dT%H:%M:%S')
def prepare_wallets(api_node):
tt.logger.info( "Attaching legacy/hf26 wallets..." )

View File

@ -1,79 +0,0 @@
from datetime import datetime
from typing import List
from pathlib import Path
import os
import test_tools as tt
def parse_datetime(datetime_: str) -> datetime:
return datetime.strptime(datetime_, '%Y-%m-%dT%H:%M:%S')
def init_network( init_node, all_witness_names : List[str], key : str = None, block_log_directory_name : str = None):
tt.logger.info('Attaching wallets...')
wallet = tt.Wallet(attach_to=init_node)
# We are waiting here for block 43, because witness participation is counting
# by dividing total produced blocks in last 128 slots by 128. When we were waiting
# too short, for example 42 blocks, then participation equals 42 / 128 = 32.81%.
# It is not enough, because 33% is required. 43 blocks guarantee, that this
# requirement is always fulfilled (43 / 128 = 33.59%, which is greater than 33%).
tt.logger.info('Wait for block 43 (to fulfill required 33% of witness participation)')
init_node.wait_for_block_with_number(43)
# Prepare witnesses on blockchain
with wallet.in_single_transaction():
for name in all_witness_names:
if key is None:
wallet.api.create_account('initminer', name, '')
else:
wallet.api.create_account_with_keys('initminer', name, '', key, key, key, key)
with wallet.in_single_transaction():
for name in all_witness_names:
wallet.api.transfer_to_vesting("initminer", name, tt.Asset.Test(1000))
with wallet.in_single_transaction():
for name in all_witness_names:
wallet.api.update_witness(
name, "https://" + name,
tt.Account(name).public_key,
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0}
)
tt.logger.info('Wait 21 blocks to schedule newly created witnesses into future slate')
init_node.wait_number_of_blocks(21)
future_witnesses = init_node.api.database.get_active_witnesses(include_future=True)["future_witnesses"]
tt.logger.info(f"Future witnesses after voting: {future_witnesses}")
assert len(future_witnesses) == 21
tt.logger.info('Wait 21 blocks for future slate to become active slate')
init_node.wait_number_of_blocks(21)
active_witnesses = init_node.api.database.get_active_witnesses()["witnesses"]
tt.logger.info(f"Witness state after voting: {active_witnesses}")
assert len(active_witnesses) == 21
# Reason of this wait is to enable moving forward of irreversible block
tt.logger.info('Wait 21 blocks (when every witness sign at least one block)')
init_node.wait_number_of_blocks(21)
result = wallet.api.info()
head_block_num = result['head_block_number']
timestamp = init_node.api.block.get_block(block_num=head_block_num)['block']['timestamp']
tt.logger.info(f'head block timestamp: {timestamp}')
if block_log_directory_name is not None:
if os.path.exists(block_log_directory_name):
Path(block_log_directory_name + '/block_log').unlink(missing_ok=True)
else:
os.mkdir(block_log_directory_name)
init_node.close()
init_node.block_log.copy_to(block_log_directory_name)
with open(block_log_directory_name + '/timestamp', 'w') as f:
f.write(f'{timestamp}')
return wallet

View File

View File

View File

@ -0,0 +1,233 @@
import os
from pathlib import Path
from typing import Dict, Iterable, List
import test_tools as tt
from .complex_networks_helper_functions import connect_sub_networks
def get_relative_time_offset_from_file(file: Path):
with open(file, "r", encoding="UTF-8") as file:
timestamp = file.read().strip()
delta = tt.Time.now(serialize=False) - tt.Time.parse(timestamp)
delta += tt.Time.seconds(5) # Node starting and entering live mode takes some time to complete
return f'-{delta.total_seconds():.3f}s'
def init_network(init_node, all_witness_names: List[str], key: str = None, block_log_directory_name: str = None):
tt.logger.info("Attaching wallets...")
wallet = tt.Wallet(attach_to=init_node)
# We are waiting here for block 43, because witness participation is counting
# by dividing total produced blocks in last 128 slots by 128. When we were waiting
# too short, for example 42 blocks, then participation equals 42 / 128 = 32.81%.
# It is not enough, because 33% is required. 43 blocks guarantee, that this
# requirement is always fulfilled (43 / 128 = 33.59%, which is greater than 33%).
tt.logger.info("Wait for block 43 (to fulfill required 33% of witness participation)")
init_node.wait_for_block_with_number(43)
# Prepare witnesses on blockchain
with wallet.in_single_transaction():
for name in all_witness_names:
if key is None:
wallet.api.create_account("initminer", name, "")
else:
wallet.api.create_account_with_keys("initminer", name, "", key, key, key, key)
with wallet.in_single_transaction():
for name in all_witness_names:
wallet.api.transfer_to_vesting("initminer", name, tt.Asset.Test(1000))
with wallet.in_single_transaction():
for name in all_witness_names:
wallet.api.update_witness(
name,
"https://" + name,
tt.Account(name).public_key,
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0},
)
future_witnesses = init_node.api.database.get_active_witnesses(include_future=True)["future_witnesses"]
tt.logger.info(f"Future witnesses after voting: {future_witnesses}")
assert len(future_witnesses) == 21
tt.logger.info("Wait 21 blocks to schedule newly created witnesses into future slate")
init_node.wait_number_of_blocks(21)
tt.logger.info("Wait 21 blocks for future slate to become active slate")
init_node.wait_number_of_blocks(21)
active_witnesses = init_node.api.database.get_active_witnesses()["witnesses"]
tt.logger.info(f"Witness state after voting: {active_witnesses}")
assert len(active_witnesses) == 21
# Reason of this wait is to enable moving forward of irreversible block
tt.logger.info("Wait 21 blocks (when every witness sign at least one block)")
init_node.wait_number_of_blocks(21)
result = wallet.api.info()
head_block_num = result["head_block_number"]
timestamp = init_node.api.block.get_block(block_num=head_block_num)["block"]["timestamp"]
tt.logger.info(f"head block timestamp: {timestamp}")
# If a directory of `block_log` is given then it"s possible to save 2 files:
# 1) "block_log" file that contains whole saved network
# 2) "timestamp" file that contains information about time what should be set by `libfaketime` library
if block_log_directory_name is not None:
# Prepare dedicated directory
if Path(block_log_directory_name).exists():
Path(block_log_directory_name + "/block_log").unlink(missing_ok=True)
else:
Path.mkdir(block_log_directory_name)
# Copy newly created "block_log" into dedicated directory
init_node.close()
init_node.block_log.copy_to(block_log_directory_name)
# Create "timestamp file"
with Path(block_log_directory_name + "/timestamp").open(mode="w", encoding="UTF-8") as file_handle:
file_handle.write(f"{timestamp}")
return wallet
def run_networks(networks: Iterable[tt.Network], blocklog_directory: Path):
if blocklog_directory is not None:
time_offset = get_relative_time_offset_from_file(blocklog_directory / "timestamp")
block_log = tt.BlockLog(blocklog_directory / "block_log")
tt.logger.info(f"block_log directory: {blocklog_directory}")
tt.logger.info("Running nodes...")
connect_sub_networks(networks)
nodes = [node for network in networks for node in network.nodes]
info_nodes = ", ".join(str(node) for node in nodes)
tt.logger.info(f"Following nodes exist in whole network: {info_nodes}")
if blocklog_directory is not None:
nodes[0].run(wait_for_live=False, replay_from=block_log, time_offset=time_offset)
else:
nodes[0].run(wait_for_live=False)
init_node_p2p_endpoint = nodes[0].p2p_endpoint
for node in nodes[1:]:
node.config.p2p_seed_node.append(init_node_p2p_endpoint)
if blocklog_directory is not None:
node.run(wait_for_live=False, replay_from=block_log, time_offset=time_offset)
else:
node.run(wait_for_live=False)
for network in networks:
network.is_running = True
for node in nodes:
tt.logger.debug(f"Waiting for {node} to be live...")
node.wait_for_live_mode(tt.InitNode.DEFAULT_WAIT_FOR_LIVE_TIMEOUT)
def display_info(wallet):
# Network should be set up at this time, with 21 active witnesses, enough participation rate
# and irreversible block number lagging behind around 15-20 blocks head block number
result = wallet.api.info()
irreversible = result["last_irreversible_block_num"]
head = result["head_block_num"]
tt.logger.info(f"Network prepared, irreversible block: {irreversible}, head block: {head}")
def prepare_network_with_many_witnesses(block_log_directory_name: str = None) -> Dict:
"""
Fixture consists of 1 init node, 8 witness nodes and 2 api nodes.
After fixture creation there are 21 active witnesses, and last irreversible block
is behind head block like in real network.
"""
tt.logger.info("Preparing network with many witnesses")
# Create first network
alpha_net = tt.Network()
init_node = tt.InitNode(network=alpha_net)
tt.WitnessNode(witnesses=[f"witness{i}-alpha" for i in range(0, 3)], network=alpha_net)
tt.WitnessNode(witnesses=[f"witness{i}-alpha" for i in range(3, 6)], network=alpha_net)
tt.WitnessNode(witnesses=[f"witness{i}-alpha" for i in range(6, 8)], network=alpha_net)
tt.WitnessNode(witnesses=[f"witness{i}-alpha" for i in range(8, 10)], network=alpha_net)
tt.ApiNode(network=alpha_net)
# Create second network
beta_net = tt.Network()
tt.WitnessNode(witnesses=[f"witness{i}-beta" for i in range(0, 3)], network=beta_net)
tt.WitnessNode(witnesses=[f"witness{i}-beta" for i in range(3, 6)], network=beta_net)
tt.WitnessNode(witnesses=[f"witness{i}-beta" for i in range(6, 8)], network=beta_net)
tt.WitnessNode(witnesses=[f"witness{i}-beta" for i in range(8, 10)], network=beta_net)
tt.ApiNode(network=beta_net)
run_networks([alpha_net, beta_net], Path(block_log_directory_name))
wallet = tt.Wallet(attach_to=init_node)
display_info(wallet)
return alpha_net, beta_net
def prepare_nodes(sub_networks_sizes: list) -> list:
assert len(sub_networks_sizes) > 0, "At least 1 sub-network is required"
cnt = 0
all_witness_names = []
sub_networks = []
init_node = None
for sub_networks_size in sub_networks_sizes:
tt.logger.info(f"Preparing sub-network nr: {cnt} that consists of {sub_networks_size} witnesses")
witness_names = [f"witness-{cnt}-{i}" for i in range(sub_networks_size)]
all_witness_names += witness_names
sub_network = tt.Network()
if cnt == 0:
init_node = tt.InitNode(network=sub_network)
sub_networks.append(sub_network)
tt.WitnessNode(witnesses=witness_names, network=sub_network)
tt.ApiNode(network=sub_network)
cnt += 1
return sub_networks, init_node, all_witness_names
def prepare_sub_networks_generation(sub_networks_sizes: list, block_log_directory_name: str = None) -> Dict:
sub_networks, init_node, all_witness_names = prepare_nodes(sub_networks_sizes)
run_networks(sub_networks, None)
initminer_public_key = "TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4"
init_network(init_node, all_witness_names, initminer_public_key, block_log_directory_name)
return None, None, None
def prepare_sub_networks_launch(sub_networks_sizes: list, block_log_directory_name: str = None) -> Dict:
sub_networks, init_node, all_witness_names = prepare_nodes(sub_networks_sizes)
run_networks(sub_networks, Path(block_log_directory_name))
init_wallet = tt.Wallet(attach_to=init_node)
display_info(init_wallet)
return sub_networks, all_witness_names, init_wallet
def prepare_sub_networks(
sub_networks_sizes: list, allow_generate_block_log: bool = False, block_log_directory_name: str = None
) -> Dict:
assert block_log_directory_name is not None, "Name of directory with block_log file must be given"
if allow_generate_block_log:
return prepare_sub_networks_generation(sub_networks_sizes, block_log_directory_name)
return prepare_sub_networks_launch(sub_networks_sizes, block_log_directory_name)
def allow_generate_block_log():
status = os.environ.get("GENERATE_FORK_BLOCK_LOG", None)
if status is None:
return False
return int(status) == 1

View File

@ -1,31 +1,22 @@
import os
from pathlib import Path
import re
import time
from typing import Dict, Iterable, List
from typing import List
import test_tools as tt
from test_tools.__private.init_node import InitNode
from test_tools.__private.user_handles.get_implementation import get_implementation
from test_tools.__private.wait_for import wait_for_event
from ..local_tools import init_network
def count_ops_by_type(node, op_type: str, start: int, limit: int = 50):
"""
:param op_type: type of operation (ex. 'producer_reward_operation')
:param op_type: type of operation (ex. "producer_reward_operation")
:param start: start queries with this block number
:param limit: limit queries until start-limit+1
"""
count = {}
for i in range(start, start-limit, -1):
for i in range(start, start - limit, -1):
response = node.api.account_history.get_ops_in_block(block_num=i, only_virtual=False)
ops = response["ops"]
count[i] = 0
for op in ops:
this_op_type = op["op"]["type"]
for current_op in ops:
this_op_type = current_op["op"]["type"]
if this_op_type == op_type:
count[i] += 1
return count
@ -33,19 +24,19 @@ def count_ops_by_type(node, op_type: str, start: int, limit: int = 50):
def check_account_history_duplicates(node, wallet):
last_irreversible_block = wallet.api.info()["last_irreversible_block_num"]
node_reward_operations = count_ops_by_type(node, 'producer_reward_operation', last_irreversible_block, limit=50)
assert sum(i==1 for i in node_reward_operations.values()) == 50
node_reward_operations = count_ops_by_type(node, "producer_reward_operation", last_irreversible_block, limit=50)
assert sum(i == 1 for i in node_reward_operations.values()) == 50
def assert_no_duplicates(node, *nodes):
nodes = [node, *nodes]
for node in nodes:
wallet = tt.Wallet(attach_to=node)
check_account_history_duplicates(node, wallet)
node.wait_number_of_blocks(10)
for node in nodes:
wallet = tt.Wallet(attach_to=node)
check_account_history_duplicates(node, wallet)
_nodes = [node, *nodes]
for _node in _nodes:
wallet = tt.Wallet(attach_to=_node)
check_account_history_duplicates(_node, wallet)
_node.wait_number_of_blocks(10)
for _node in _nodes:
wallet = tt.Wallet(attach_to=_node)
check_account_history_duplicates(_node, wallet)
tt.logger.info("No there are no duplicates in account_history.get_ops_in_block...")
@ -62,7 +53,7 @@ def connect_sub_networks(sub_networks : list):
current_idx += 1
def disconnect_sub_networks(sub_networks : list):
def disconnect_sub_networks(sub_networks: list):
assert len(sub_networks) > 1
current_idx = 0
@ -75,36 +66,38 @@ def disconnect_sub_networks(sub_networks : list):
current_idx += 1
def enable_witnesses(wallet : tt.Wallet, witness_details : list):
def enable_witnesses(wallet: tt.Wallet, witness_details: list):
with wallet.in_single_transaction():
for name in witness_details:
wallet.api.update_witness(
name, "https://" + name,
name,
"https://" + name,
tt.Account(name).public_key,
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0}
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0},
)
def disable_witnesses(wallet : tt.Wallet, witness_details : list):
key = 'TST5NUU7M7pmqMpMHUwscgUBMuwLQE56MYwCLF7q9ZGB6po1DMNoG'
def disable_witnesses(wallet: tt.Wallet, witness_details: list):
key = "TST5NUU7M7pmqMpMHUwscgUBMuwLQE56MYwCLF7q9ZGB6po1DMNoG"
with wallet.in_single_transaction():
for name in witness_details:
wallet.api.update_witness(
name, "https://" + name,
name,
"https://" + name,
key,
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0}
{"account_creation_fee": tt.Asset.Test(3), "maximum_block_size": 65536, "sbd_interest_rate": 0},
)
def get_last_head_block_number(blocks : list):
def get_last_head_block_number(blocks: list):
return blocks[len(blocks) - 1][0]
def get_last_irreversible_block_num(blocks : list):
def get_last_irreversible_block_num(blocks: list):
return blocks[len(blocks) - 1][1]
def get_part_of_witness_details(witness_details : list, start, length : int):
def get_part_of_witness_details(witness_details: list, start, length: int):
assert start >= 0 and start + length <= len(witness_details)
new_witness_details = []
for i in range(start, start + length):
@ -120,37 +113,38 @@ def info(msg : str, wallet : tt.Wallet):
tt.logger.info(f'network: \'{msg}\' head: {hb} lib: {lib} current witness: {current_witness}')
return hb, lib
class NodeLog:
class fork_log:
def __init__(self, name, wallet):
self.name = name
self.collector = []
self.wallet = wallet
self.name = name
self.collector = []
self.wallet = wallet
def append(self):
self.collector.append( info(self.name, self.wallet) )
self.collector.append(info(self.name, self.wallet))
def wait(blocks, log : List[fork_log], api_node):
def wait(blocks, log: List[NodeLog], api_node):
for i in range(blocks):
for current in log:
current.append()
api_node.wait_number_of_blocks(1)
tt.logger.info(f'{i+1}/{blocks} blocks')
tt.logger.info(f"{i+1}/{blocks} blocks")
def final_block_the_same(method, data : list):
def final_block_the_same(method, data: list):
current = None
for item in data:
if current is None:
current = item
else:
if method( current ) != method( item ):
if method(current) != method(item):
return False
return True
def lib_true_condition():
return True
@ -159,22 +153,25 @@ def lib_custom_condition(compared_item1, compared_item2):
return get_last_irreversible_block_num(compared_item1) > compared_item2
def wait_for_final_block(witness_node, logs, data : list, allow_lib = True, lib_cond = lib_true_condition, allow_last_head = True):
def wait_for_final_block(
witness_node, logs, data: list, allow_lib=True, lib_cond=lib_true_condition, allow_last_head=True
):
assert allow_lib or allow_last_head
#Hard to say when all nodes would have the same HEAD's/LIB's. All nodes are connected together in common network
#so sometimes one or two nodes are "delayed" - their LIB is lower than LIB others.
#The best option is to wait until every node has the same data: it doesn't matter if such situation occurs after 5 or 25 blocks.
#In case when nodes wouldn't have the same data, it's an obvious error and CI will finish this test.
# Hard to say when all nodes would have the same HEAD"s/LIB"s. All nodes are connected together in common network
# so sometimes one or two nodes are "delayed" - their LIB is lower than LIB others.
# The best option is to wait until every node has the same data.
# It doesn"t matter if such situation occurs after 5 or 25 blocks.
# In case when nodes wouldn"t have the same data, it"s an obvious error and CI will finish this test.
while True:
wait(1, logs, witness_node)
#Veryfing if all nodes have the same last irreversible block number
# Veryfing if all nodes have the same last irreversible block number
if allow_lib:
if lib_cond() and final_block_the_same(get_last_irreversible_block_num, data):
return False
#Veryfing if all nodes have the same last head block number
# Veryfing if all nodes have the same last head block number
if allow_last_head:
if final_block_the_same(get_last_head_block_number, data):
return False
@ -230,51 +227,6 @@ def wait_for_specific_witnesses(node, logs, witness_name_patterns):
tt.logger.info("Witnesses patterns can't be processed in the same schedule. Still waiting...")
def get_relative_time_offset_from_file(file: Path) -> str:
with open(file, 'r') as f:
timestamp = f.read().strip()
delta = tt.Time.now(serialize=False) - tt.Time.parse(timestamp)
delta += tt.Time.seconds(5) # Node starting and entering live mode takes some time to complete
return f'-{delta.total_seconds():.3f}s'
def run_networks(networks: Iterable[tt.Network], blocklog_directory: Path):
if blocklog_directory is not None:
time_offset = get_relative_time_offset_from_file(blocklog_directory / 'timestamp')
block_log = tt.BlockLog(blocklog_directory/'block_log')
tt.logger.info('Running nodes...')
connect_sub_networks(networks)
nodes = [node for network in networks for node in network.nodes]
if blocklog_directory is not None:
nodes[0].run(wait_for_live=False, replay_from=block_log, time_offset=time_offset)
else:
nodes[0].run(wait_for_live=False)
init_node: InitNode = get_implementation(nodes[0])
endpoint = init_node.get_p2p_endpoint()
for node in nodes[1:]:
node.config.p2p_seed_node.append(endpoint)
if blocklog_directory is not None:
node.run(wait_for_live=False, replay_from=block_log, time_offset=time_offset)
else:
node.run(wait_for_live=False)
for network in networks:
network.is_running = True
deadline = time.time() + InitNode.DEFAULT_WAIT_FOR_LIVE_TIMEOUT
for node in nodes:
tt.logger.debug(f'Waiting for {node} to be live...')
wait_for_event(
get_implementation(node)._Node__notifications.live_mode_entered_event,
deadline=deadline,
exception_message='Live mode not activated on time.'
)
def display_info(wallet):
# Network should be set up at this time, with 21 active witnesses, enough participation rate
# and irreversible block number lagging behind around 15-20 blocks head block number
@ -307,46 +259,3 @@ def prepare_nodes(sub_networks_sizes : list) -> list:
cnt += 1
return sub_networks, init_node, all_witness_names
def prepare_sub_networks_generation(sub_networks_sizes : list, block_log_directory_name : str = None) -> Dict:
sub_networks, init_node, all_witness_names = prepare_nodes(sub_networks_sizes)
run_networks(sub_networks, None)
initminer_public_key = 'TST6LLegbAgLAy28EHrffBVuANFWcFgmqRMW13wBmTExqFE9SCkg4'
init_network(init_node, all_witness_names, initminer_public_key, block_log_directory_name)
return None, None, None
def prepare_sub_networks_launch(sub_networks_sizes : list, block_log_directory_name : str = None) -> Dict:
sub_networks, init_node, all_witness_names = prepare_nodes(sub_networks_sizes)
run_networks(sub_networks, Path(block_log_directory_name))
init_wallet = tt.Wallet(attach_to=init_node)
display_info(init_wallet)
return sub_networks, all_witness_names, init_wallet
def prepare_sub_networks(sub_networks_sizes : list, allow_generate_block_log : bool = False, block_log_directory_name : str = None) -> Dict:
assert block_log_directory_name is not None, "Name of directory with block_log file must be given"
if allow_generate_block_log:
return prepare_sub_networks_generation(sub_networks_sizes, block_log_directory_name)
else:
return prepare_sub_networks_launch(sub_networks_sizes, block_log_directory_name)
def allow_generate_block_log():
status = os.environ.get('GENERATE_FORK_BLOCK_LOG', None)
if status is None:
return False
return int(status) == 1
def create_block_log_directory_name(name : str):
return str(Path(__file__).parent.absolute()) + '/' + name

8
tests/shared_tools/poetry.lock generated Normal file
View File

@ -0,0 +1,8 @@
package = []
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "935b488be9f11b23f14aa1ce3bed4013d88bd77462534b5e4fe5bb82b485bfe9"
[metadata.files]

View File

@ -0,0 +1,17 @@
[build-system]
requires = ["poetry-core==1.1.0"]
build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "shared-tools"
version = "0.0.0"
description = "Tools shared by tests in hive projects"
authors = ["Mariusz Trela"]
packages = [
{ include = "shared_tools", from = "package" },
]
[tool.poetry.dependencies]
python = "^3.8"