Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions tests/floresta-cli/getbestblockhash.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
and utreexod, respectively.
"""

import time
import pytest

TIMEOUT_SECONDS = 20
from test_framework.util import wait_until


@pytest.mark.rpc
Expand All @@ -27,14 +26,11 @@ def test_get_best_block_hash(florestad_utreexod):
assert floresta_best_block == utreexo_best_block

utreexod.rpc.generate(10)
end = time.time() + TIMEOUT_SECONDS
while time.time() < end:
floresta_block = florestad.rpc.get_block_count()
utreexo_block = utreexod.rpc.get_block_count()
if floresta_block == utreexo_block:
break

time.sleep(1)

wait_until(
predicate=lambda: florestad.rpc.get_block_count()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps you could give some specialized functions for common cases like this one?

== utreexod.rpc.get_block_count()
)

utreexo_chain = utreexod.rpc.get_blockchain_info()
floresta_best_block = florestad.rpc.get_bestblockhash()
Expand Down
15 changes: 5 additions & 10 deletions tests/floresta-cli/getblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
import time
import random
from typing import Any

import pytest

TIMEOUT_SECONDS = 20
from test_framework.util import wait_until


class TestGetBlock:
Expand Down Expand Up @@ -44,14 +43,10 @@ def test_get_block(
self.node_manager.connect_nodes(self.florestad, self.bitcoind)

block_count = self.bitcoind.rpc.get_block_count()
end = time.time() + TIMEOUT_SECONDS
while time.time() < end:
floresta_count = self.florestad.rpc.get_block_count()
if floresta_count == block_count:
break
time.sleep(0.5)

assert floresta_count == block_count

wait_until(
predicate=lambda: self.florestad.rpc.get_block_count() == block_count
)

self.log.info("Testing getblock RPC in the genesis block")
self.compare_block(0)
Expand Down
17 changes: 6 additions & 11 deletions tests/floresta-cli/getblockcount.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
`blocks` and `height/validated` fields given in `getblockchaininfo`
of utreexod/bitcoind and floresta, respectively"""

import time
import pytest
from test_framework.util import wait_until

MINE_BLOCKS = 10
TIMEOUT_SECONDS = 20


@pytest.mark.rpc
Expand All @@ -28,15 +27,11 @@ def test_get_block_count(florestad_utreexod):

# Mine blocks with utreexod
utreexod.rpc.generate(MINE_BLOCKS)
timeout = time.time() + TIMEOUT_SECONDS
while time.time() < timeout:
if (
florestad.rpc.get_block_count()
== utreexod.rpc.get_block_count()
== MINE_BLOCKS
):
break
time.sleep(1)
wait_until(
predicate=lambda: florestad.rpc.get_block_count()
== utreexod.rpc.get_block_count()
== MINE_BLOCKS
)

# Get final block counts
final_florestad_count = florestad.rpc.get_block_count()
Expand Down
17 changes: 6 additions & 11 deletions tests/floresta-cli/getblockhash.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@
This functional test cli utility to interact with a Floresta node with `getblockhash`
"""

import time
import pytest

from test_framework.constants import GENESIS_BLOCK_HASH
from test_framework.util import wait_until

MINED_BLOCKS = 10
TIMEOUT = 20


@pytest.mark.rpc
Expand All @@ -30,15 +29,11 @@ def test_get_block_hash(florestad_utreexod):

# Mine blocks with utreexod
utreexod.rpc.generate(MINED_BLOCKS)
timeout = time.time() + TIMEOUT
while time.time() < timeout:
if (
florestad.rpc.get_block_count()
== utreexod.rpc.get_block_count()
== MINED_BLOCKS
):
break
time.sleep(1)
wait_until(
predicate=lambda: florestad.rpc.get_block_count()
== utreexod.rpc.get_block_count()
== MINED_BLOCKS
)

# Get final block hashes
final_florestad_hash = florestad.rpc.get_blockhash(MINED_BLOCKS)
Expand Down
29 changes: 14 additions & 15 deletions tests/floresta-cli/gettxout.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
This functional test cli utility to interact with a Floresta node with `gettxout` command.
"""

import time
import pytest

TIMEOUT_SECONDS = 120
from test_framework.util import wait_until


# pylint: disable=too-many-locals
Expand All @@ -27,27 +26,27 @@ def test_get_txout(setup_logging, florestad_bitcoind_utreexod_with_chain):
best_block_hash = utreexod.rpc.get_blockhash(blocks)

log.info("Waiting for Floresta and Bitcoind to sync with Utreexod...")
timeout = time.time() + TIMEOUT_SECONDS
while time.time() < timeout:
floresta_info = florestad.rpc.get_blockchain_info()
if (
floresta_info["height"]
== utreexod.rpc.get_block_count()
== bitcoind.rpc.get_block_count()
== blocks
and not floresta_info["ibd"]
):
break

time.sleep(1)
def check_sync():
# Forcing a re-fetch of the block from the peer
try:
bitcoind.rpc.get_block_from_peer(best_block_hash, peer_id)
# pylint: disable=broad-exception-caught
except Exception as e:
log.error(f"Error fetching block from peer: {e}")

assert floresta_info["height"] == blocks and not floresta_info["ibd"]
floresta_info = florestad.rpc.get_blockchain_info()
return (
floresta_info["height"]
== utreexod.rpc.get_block_count()
== bitcoind.rpc.get_block_count()
and not floresta_info["ibd"]
)

wait_until(
check_sync,
error_msg="Floresta and Bitcoind did not sync with Utreexod within the timeout period.",
)

log.info("Comparing gettxout results between Floresta and Bitcoind...")
for height in range(2, blocks):
Expand Down
21 changes: 7 additions & 14 deletions tests/florestad/reorg_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
accumulator to make sure they are the same.
"""

import time
import pytest

from test_framework.util import wait_until


@pytest.mark.florestad
def test_reorg_chain(setup_logging, florestad_utreexod):
Expand Down Expand Up @@ -74,16 +75,8 @@ def mine_blocks(self, blocks):
self.log.info(f"Utreexod node mine {blocks} blocks")
self.utreexod.rpc.generate(blocks)

timeout = 30
end = time.time() + timeout
while time.time() < end:
florestad_block = self.florestad.rpc.get_block_count()
utreexod_block = self.utreexod.rpc.get_block_count()
if florestad_block == utreexod_block:
self.log.info(f"Nodes are in sync: {florestad_block} blocks")
break

time.sleep(1)

if florestad_block != utreexod_block:
pytest.fail("Florestad node did not sync with Utreexod node in time")
wait_until(
predicate=lambda: self.florestad.rpc.get_block_count()
== self.utreexod.rpc.get_block_count(),
error_msg="Florestad node did not sync with Utreexod node in time.",
)
61 changes: 31 additions & 30 deletions tests/test_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from test_framework.rpc import ConfigRPC
from test_framework.electrum import ConfigElectrum, ConfigTls
from test_framework.node import Node, NodeType
from test_framework.util import Utility
from test_framework.util import Utility, wait_until


# pylint: disable=too-many-public-methods
Expand Down Expand Up @@ -274,6 +274,9 @@ def check_connection(self, peer_one: Node, peer_two: Node, is_connected: bool):
f"Peer one running: {peer_one_running}, Peer two running: {peer_two_running}"
)

# Send pings to both peers to trigger a peer state update
self._send_peer_pings(peer_one, peer_two)

peer_two_in_peer_one = (
peer_one.is_peer_connected(peer_two) if peer_one_running else False
)
Expand All @@ -293,42 +296,40 @@ def wait_for_peers_connections(
Wait for two peers to connect/disconnect to each other.
"""
attempts = 0
timeout = time.time() + 30
while time.time() < timeout:
if self.check_connection(peer_one, peer_two, is_connected):
self.log.debug(
f"Peers {peer_one.variant} and {peer_two.variant} are in the expected "
f"connection state."
)
return

if attempts < 10:
def check_peers_connection():
nonlocal attempts

if attempts > 10:
time.sleep(1)
else:
time.sleep(2)

attempts += 1

# Send a ping to both peers to trigger a peer state update
if peer_one.daemon.is_running:
peer_one.rpc.ping()
self.log.debug(
f"Peer one {peer_one.variant} is connected to peer two {peer_two.variant}: "
f"{peer_one.is_peer_connected(peer_two)}"
)

if peer_two.daemon.is_running:
peer_two.rpc.ping()
self.log.debug(
f"Peer two {peer_two.variant} is connected to peer one {peer_one.variant}: "
f"{peer_two.is_peer_connected(peer_one)}"
)

raise AssertionError(
f"Peers {peer_one.variant} and {peer_two.variant} failed to reach the expected "
f"connection state within the timeout. Expected connected: {is_connected}."
return self.check_connection(peer_one, peer_two, is_connected)

wait_until(predicate=check_peers_connection)

self.log.debug(
f"Peers {peer_one.variant} and {peer_two.variant} are "
f"{'connected' if is_connected else 'disconnected'}"
)

def _send_peer_pings(self, peer_one: Node, peer_two: Node):
"""Send pings to both peers and log connection status."""
if peer_one.daemon.is_running:
peer_one.rpc.ping()
self.log.debug(
f"Peer one {peer_one.variant} is connected to peer two {peer_two.variant}: "
f"{peer_one.is_peer_connected(peer_two)}"
)

if peer_two.daemon.is_running:
peer_two.rpc.ping()
self.log.debug(
f"Peer two {peer_two.variant} is connected to peer one {peer_one.variant}: "
f"{peer_two.is_peer_connected(peer_one)}"
)

def connect_nodes(
self,
peer_one: Node,
Expand Down
2 changes: 1 addition & 1 deletion tests/test_framework/rpc/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class BaseRPC(ABC):
Subclasses should use `perform_request` to implement RPC calls.
"""

TIMEOUT: int = 15 # seconds
TIMEOUT: int = 30 # seconds

def __init__(self, config: ConfigRPC, log):
self._config = config
Expand Down
14 changes: 14 additions & 0 deletions tests/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""Utility helpers used by the test framework (paths, ports, TLS helpers)."""

import os
import time
import random
import socket
import subprocess
Expand Down Expand Up @@ -87,3 +88,16 @@ def create_tls_key_cert() -> tuple[str, str]:
)

return (pk_path, cert_path)


def wait_until(predicate, timeout=60, interval=0.5, error_msg="Condition not met"):
"""
Wait until a predicate returns True or timeout is reached.
"""
start = time.time()
while time.time() - start < timeout:
if predicate():
return True
time.sleep(interval)

raise TimeoutError(f"{error_msg} after {timeout} seconds")