Revision 23f150d0e7f123ca90c178def2978523e10606c7 authored by Marge Bot on 08 September 2022, 14:58:56 UTC, committed by Marge Bot on 08 September 2022, 14:58:56 UTC
Co-authored-by: Killian Delarue <killian.delarue@nomadic-labs.com>

Approved-by: Pierre Boutillier <pierre.boutillier@nomadic-labs.com>
Approved-by: Victor Allombert <victor.allombert@tezcore.com>

See merge request https://gitlab.com/tezos/tezos/-/merge_requests/6223
2 parent s c5c5bd3 + f289ab2
Raw File
test_bootstrap.py
import time

import pytest
from launchers.sandbox import Sandbox
from . import protocol

LOG_LEVEL = {"validator.chain": "debug", "validator.peer": "debug"}


def params(threshold=0, latency=3):
    return [
        '--sync-latency',
        str(latency),
        '--synchronisation-threshold',
        str(threshold),
        '--connections',
        '100',
    ]


def add_fully_delegated_baker(sandbox: Sandbox, node: int, protocol: str):
    """Add a baker that has all known bootstrap accounts delegated to it."""
    sandbox.add_baker(
        node,
        [],
        proto=protocol,
        run_params=['--liquidity-baking-toggle-vote', 'pass'],
    )


@pytest.mark.baker
@pytest.mark.incremental
class TestThresholdZero:
    """Threshold 0, peer always bootstrapped."""

    def test_setup_network(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL)
        sandbox.add_baker(
            0,
            ['bootstrap5'],
            proto=protocol.DAEMON,
            run_params=['--liquidity-baking-toggle-vote', 'pass'],
        )

    def test_bootstrap(self, sandbox: Sandbox):
        client = sandbox.client(0)
        assert client.sync_state() == 'synced'


@pytest.mark.baker
@pytest.mark.multinode
@pytest.mark.incremental
class TestThresholdOne:
    """First peer has threshold zero, second peer has threshold one"""

    def test_setup_network(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL)
        protocol.activate(sandbox.client(0))
        sandbox.add_baker(
            0,
            ['bootstrap5'],
            proto=protocol.DAEMON,
            run_params=['--liquidity-baking-toggle-vote', 'pass'],
        )

    def test_bootstrap(self, sandbox: Sandbox):
        client = sandbox.client(0)
        assert client.sync_state() == 'synced'

    def test_add_node(self, sandbox: Sandbox):
        sandbox.add_node(
            1, params=params(1), log_levels=LOG_LEVEL, config_client=False
        )
        sandbox.client(1).bootstrapped()


@pytest.mark.baker
@pytest.mark.multinode
@pytest.mark.incremental
class TestThresholdTwo:
    def test_setup_network(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(0), log_levels=LOG_LEVEL)
        protocol.activate(sandbox.client(0))
        time.sleep(3)
        sandbox.add_baker(
            0,
            ['bootstrap5'],
            proto=protocol.DAEMON,
            run_params=['--liquidity-baking-toggle-vote', 'pass'],
        )

    def test_add_nodes(self, sandbox: Sandbox):
        sandbox.add_node(
            1, params=params(2), log_levels=LOG_LEVEL, config_client=False
        )
        sandbox.add_node(
            2, params=params(2), log_levels=LOG_LEVEL, config_client=False
        )
        sandbox.add_node(
            3, params=params(1), log_levels=LOG_LEVEL, config_client=False
        )

    # Some lower timeouts (5, 10) make the test fails. 15 seems to be enough
    # If the test fails again, look at increasing this timeout first.
    @pytest.mark.timeout(15)
    def test_node_3_bootstrapped(self, sandbox: Sandbox):
        sandbox.client(3).bootstrapped()

    # See comment for previous test
    @pytest.mark.timeout(5)
    def test_node_1_bootstrapped(self, sandbox: Sandbox):
        sandbox.client(1).bootstrapped()


@pytest.mark.slow
@pytest.mark.baker
@pytest.mark.multinode
@pytest.mark.incremental
class TestStuck:
    def test_setup_network(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL)
        protocol.activate(sandbox.client(0))
        add_fully_delegated_baker(sandbox, 0, protocol.DAEMON)

    def test_kill_baker(self, sandbox: Sandbox):
        """Bake a few blocks and kill baker"""
        time.sleep(14)
        sandbox.rm_baker(0, proto=protocol.DAEMON)
        time.sleep(5)

    def test_progress(self, sandbox: Sandbox):
        assert sandbox.client(0).get_level() >= 2

    def test_add_node(self, sandbox: Sandbox):
        sandbox.add_node(
            1, params=params(2), config_client=False, log_levels=LOG_LEVEL
        )
        sandbox.add_node(
            2, params=params(2), config_client=False, log_levels=LOG_LEVEL
        )

    def test_all_nodes_boostrap(self, sandbox: Sandbox):
        """Eventually, 1 and 2 are bootstrapped with the chain stuck."""
        sandbox.client(1).bootstrapped()
        sandbox.client(2).bootstrapped()
        assert sandbox.client(1).sync_state() == 'stuck'
        assert sandbox.client(2).sync_state() == 'stuck'


@pytest.mark.baker
@pytest.mark.multinode
@pytest.mark.incremental
class TestSplitView:
    def test_setup_network(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL)
        protocol.activate(sandbox.client(0))
        sandbox.add_node(
            1, params=params(), config_client=False, log_levels=LOG_LEVEL
        )
        sandbox.add_node(
            2,
            params=params(2, latency=15),
            config_client=False,
            log_levels=LOG_LEVEL,
        )
        add_fully_delegated_baker(sandbox, 0, protocol.DAEMON)

    @pytest.mark.timeout(10)
    def test_all_nodes_boostrap(self, sandbox: Sandbox):
        assert sandbox.client(0).sync_state() == 'synced'
        assert sandbox.client(1).sync_state() == 'synced'
        sandbox.client(2).bootstrapped()

    def test_pause(self):
        time.sleep(2)

    def test_disconnect_node(self, sandbox: Sandbox):
        """node 1 is disconnected from baker"""
        sandbox.client(1).ban_peer(sandbox.node(0).p2p_port)
        sandbox.client(0).ban_peer(sandbox.node(1).p2p_port)

    def test_sync_status(self, sandbox: Sandbox):
        assert sandbox.client(0).sync_state() == 'synced'
        assert sandbox.client(1).sync_state() == 'synced'
        assert sandbox.client(2).sync_state() == 'synced'


NUM_NODES = 8
RUNNING_TIME = 10


@pytest.mark.baker
@pytest.mark.multinode
@pytest.mark.slow
@pytest.mark.incremental
class TestManyNodesBootstrap:
    """Run many nodes, bake for a while, add a node and check it's bootstrapped
    when it should be."""

    def test_init(self, sandbox: Sandbox):
        sandbox.add_node(0, params=params(), log_levels=LOG_LEVEL)
        parameters = protocol.get_parameters()
        protocol.activate(sandbox.client(0), parameters=parameters)
        time.sleep(3)
        add_fully_delegated_baker(sandbox, 0, protocol.DAEMON)
        sandbox.add_node(
            1, params=params(), log_levels=LOG_LEVEL, config_client=False
        )

    def test_bootstrap(self, sandbox: Sandbox):
        sandbox.client(0).bootstrapped()
        sandbox.client(1).bootstrapped()

    def test_add_nodes(self, sandbox: Sandbox):
        for i in range(2, NUM_NODES):
            sandbox.add_node(
                i, params=params(), config_client=False, log_levels=LOG_LEVEL
            )

    def test_let_baking(self):
        time.sleep(RUNNING_TIME)

    def test_progress(self, sandbox, session):
        cur_level = sandbox.client(NUM_NODES - 1).get_level()
        assert cur_level > RUNNING_TIME // 2  # check progress
        session['cur_level'] = cur_level

    @pytest.mark.timeout(50)
    def test_add_one_more_node(self, sandbox, session):
        new_node = NUM_NODES
        sandbox.add_node(
            new_node,
            params=params(NUM_NODES),
            config_client=False,
            log_levels=LOG_LEVEL,
        )
        time.sleep(1)
        sandbox.client(new_node).p2p_stat()
        sandbox.client(new_node).bootstrapped()
        cur_level = session['cur_level']
        assert sandbox.client(new_node).get_level() >= cur_level
back to top