From 62f5e332a840c58cf02b6879f2ba89b7d07e1329 Mon Sep 17 00:00:00 2001 From: Jonathan Zernik Date: Thu, 30 Sep 2021 21:59:55 -0700 Subject: [PATCH] Refactor core interest functions (#1449) * Convert iterable to list in interest unit tests * Refactor interests functions into separate module * Simplify assertions in test interests unit tests --- squeaknode/core/interests.py | 75 +++++++++++++++++++ squeaknode/core/util.py | 50 ------------- squeaknode/network/peer.py | 4 +- squeaknode/node/squeak_controller.py | 2 +- squeaknode/node/temporary_interest_manager.py | 2 +- .../core/{test_util.py => test_interests.py} | 70 ++++++++++------- 6 files changed, 121 insertions(+), 82 deletions(-) create mode 100644 squeaknode/core/interests.py rename tests/core/{test_util.py => test_interests.py} (75%) diff --git a/squeaknode/core/interests.py b/squeaknode/core/interests.py new file mode 100644 index 00000000..3317de0e --- /dev/null +++ b/squeaknode/core/interests.py @@ -0,0 +1,75 @@ +# MIT License +# +# Copyright (c) 2020 Jonathan Zernik +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +from typing import Iterable + +from squeak.core import CSqueak +from squeak.net import CInterested + + +EMPTY_HASH = b'\x00' * 32 + + +def squeak_matches_interest(squeak: CSqueak, interest: CInterested) -> bool: + if len(interest.addresses) > 0 \ + and squeak.GetAddress() not in interest.addresses: + return False + if interest.nMinBlockHeight != -1 \ + and squeak.nBlockHeight < interest.nMinBlockHeight: + return False + if interest.nMaxBlockHeight != -1 \ + and squeak.nBlockHeight > interest.nMaxBlockHeight: + return False + if interest.hashReplySqk != EMPTY_HASH \ + and squeak.hashReplySqk != interest.hashReplySqk: + return False + return True + + +def get_differential_squeaks( + interest: CInterested, + old_interest: CInterested, +) -> Iterable[CInterested]: + # Get new squeaks below the current min_block + if interest.nMinBlockHeight < old_interest.nMinBlockHeight: + yield CInterested( + addresses=old_interest.addresses, + nMinBlockHeight=interest.nMinBlockHeight, + nMaxBlockHeight=old_interest.nMinBlockHeight - 1, + ) + # Get new squeaks above the current max_block + if (interest.nMaxBlockHeight == -1 and old_interest.nMaxBlockHeight != -1) or \ + interest.nMaxBlockHeight > old_interest.nMaxBlockHeight: + yield CInterested( + addresses=old_interest.addresses, + nMinBlockHeight=old_interest.nMaxBlockHeight + 1, + nMaxBlockHeight=interest.nMaxBlockHeight, + ) + # Get new squeaks for new addresses + follow_addresses = set(interest.addresses) + old_follow_addresses = set(old_interest.addresses) + new_addresses = tuple(follow_addresses - old_follow_addresses) + if len(new_addresses) > 0: + yield CInterested( + addresses=new_addresses, + nMinBlockHeight=interest.nMinBlockHeight, + nMaxBlockHeight=interest.nMaxBlockHeight, + ) diff --git a/squeaknode/core/util.py b/squeaknode/core/util.py index d65efe95..0d128ab0 100644 --- a/squeaknode/core/util.py +++ b/squeaknode/core/util.py @@ -21,18 +21,15 @@ # SOFTWARE. import os import random -from typing import Iterable from bitcoin.base58 import Base58ChecksumError from bitcoin.wallet import CBitcoinAddressError -from squeak.core import CSqueak from squeak.core.elliptic import generate_random_scalar from squeak.core.elliptic import scalar_difference from squeak.core.elliptic import scalar_from_bytes from squeak.core.elliptic import scalar_sum from squeak.core.elliptic import scalar_to_bytes from squeak.core.signing import CSqueakAddress -from squeak.net import CInterested DATA_KEY_LENGTH = 32 @@ -96,50 +93,3 @@ def is_address_valid(address: str) -> bool: except (Base58ChecksumError, CBitcoinAddressError): return False return True - - -def squeak_matches_interest(squeak: CSqueak, interest: CInterested) -> bool: - if len(interest.addresses) > 0 \ - and squeak.GetAddress() not in interest.addresses: - return False - if interest.nMinBlockHeight != -1 \ - and squeak.nBlockHeight < interest.nMinBlockHeight: - return False - if interest.nMaxBlockHeight != -1 \ - and squeak.nBlockHeight > interest.nMaxBlockHeight: - return False - if interest.hashReplySqk != EMPTY_HASH \ - and squeak.hashReplySqk != interest.hashReplySqk: - return False - return True - - -def get_differential_squeaks( - interest: CInterested, - old_interest: CInterested, -) -> Iterable[CInterested]: - # Get new squeaks below the current min_block - if interest.nMinBlockHeight < old_interest.nMinBlockHeight: - yield CInterested( - addresses=old_interest.addresses, - nMinBlockHeight=interest.nMinBlockHeight, - nMaxBlockHeight=old_interest.nMinBlockHeight - 1, - ) - # Get new squeaks above the current max_block - if (interest.nMaxBlockHeight == -1 and old_interest.nMaxBlockHeight != -1) or \ - interest.nMaxBlockHeight > old_interest.nMaxBlockHeight: - yield CInterested( - addresses=old_interest.addresses, - nMinBlockHeight=old_interest.nMaxBlockHeight + 1, - nMaxBlockHeight=interest.nMaxBlockHeight, - ) - # Get new squeaks for new addresses - follow_addresses = set(interest.addresses) - old_follow_addresses = set(old_interest.addresses) - new_addresses = tuple(follow_addresses - old_follow_addresses) - if len(new_addresses) > 0: - yield CInterested( - addresses=new_addresses, - nMinBlockHeight=interest.nMinBlockHeight, - nMaxBlockHeight=interest.nMaxBlockHeight, - ) diff --git a/squeaknode/network/peer.py b/squeaknode/network/peer.py index b510b50b..bc9a4edb 100644 --- a/squeaknode/network/peer.py +++ b/squeaknode/network/peer.py @@ -36,10 +36,10 @@ from squeak.messages import msg_version from squeak.messages import MsgSerializable from squeak.net import CSqueakLocator +from squeaknode.core.interests import get_differential_squeaks +from squeaknode.core.interests import squeak_matches_interest from squeaknode.core.peer_address import PeerAddress from squeaknode.core.util import generate_version_nonce -from squeaknode.core.util import get_differential_squeaks -from squeaknode.core.util import squeak_matches_interest from squeaknode.network.util import time_now from squeaknode.node.listener_subscription_client import EventListener diff --git a/squeaknode/node/squeak_controller.py b/squeaknode/node/squeak_controller.py index f044eb9d..7adedda2 100644 --- a/squeaknode/node/squeak_controller.py +++ b/squeaknode/node/squeak_controller.py @@ -40,6 +40,7 @@ from squeak.net import CSqueakLocator from squeaknode.core.block_range import BlockRange from squeaknode.core.connected_peer import ConnectedPeer +from squeaknode.core.interests import squeak_matches_interest from squeaknode.core.lightning_address import LightningAddressHostPort from squeaknode.core.offer import Offer from squeaknode.core.peer_address import PeerAddress @@ -54,7 +55,6 @@ from squeaknode.core.squeak_peer import SqueakPeer from squeaknode.core.squeak_profile import SqueakProfile from squeaknode.core.util import get_hash from squeaknode.core.util import is_address_valid -from squeaknode.core.util import squeak_matches_interest from squeaknode.node.listener_subscription_client import EventListener from squeaknode.node.received_payments_subscription_client import ReceivedPaymentsSubscriptionClient from squeaknode.node.temporary_interest_manager import TemporaryInterest diff --git a/squeaknode/node/temporary_interest_manager.py b/squeaknode/node/temporary_interest_manager.py index 1df9f3e3..b0edd3f6 100644 --- a/squeaknode/node/temporary_interest_manager.py +++ b/squeaknode/node/temporary_interest_manager.py @@ -31,8 +31,8 @@ from expiringdict import ExpiringDict from squeak.core import CSqueak from squeak.net import CInterested +from squeaknode.core.interests import squeak_matches_interest from squeaknode.core.util import get_hash -from squeaknode.core.util import squeak_matches_interest logger = logging.getLogger(__name__) diff --git a/tests/core/test_util.py b/tests/core/test_interests.py similarity index 75% rename from tests/core/test_util.py rename to tests/core/test_interests.py index ade244c7..0ae9be48 100644 --- a/tests/core/test_util.py +++ b/tests/core/test_interests.py @@ -19,12 +19,11 @@ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. -import pytest from squeak.core.signing import CSigningKey from squeak.core.signing import CSqueakAddress from squeak.net import CInterested -from squeaknode.core.util import get_differential_squeaks +from squeaknode.core.interests import get_differential_squeaks def gen_address(): @@ -49,12 +48,16 @@ def test_get_differential_squeaks(): nMinBlockHeight=11, nMaxBlockHeight=21, ) + differential_results = list( + get_differential_squeaks(interest, old_interest)) - differential_results = get_differential_squeaks(interest, old_interest) - first_result = next(differential_results) - assert first_result.addresses == squeak_addresses - assert first_result.nMinBlockHeight == 21 - assert first_result.nMaxBlockHeight == 21 + assert differential_results == [ + CInterested( + addresses=squeak_addresses, + nMinBlockHeight=21, + nMaxBlockHeight=21, + ) + ] def test_get_differential_squeaks_no_difference(): @@ -69,10 +72,10 @@ def test_get_differential_squeaks_no_difference(): nMinBlockHeight=10, nMaxBlockHeight=20, ) + differential_results = list( + get_differential_squeaks(interest, old_interest)) - differential_results = get_differential_squeaks(interest, old_interest) - with pytest.raises(StopIteration): - next(differential_results) + assert differential_results == [] def test_get_differential_squeaks_new_addresses(): @@ -88,11 +91,11 @@ def test_get_differential_squeaks_new_addresses(): nMinBlockHeight=10, nMaxBlockHeight=20, ) + differential_results = list( + get_differential_squeaks(interest, old_interest)) - differential_results = get_differential_squeaks(interest, old_interest) - first_result = next(differential_results) - print(first_result.addresses) - print(additional_addresses) + assert len(differential_results) == 1 + first_result = differential_results[0] assert set(first_result.addresses) == set(additional_addresses) assert first_result.nMinBlockHeight == 10 assert first_result.nMaxBlockHeight == 20 @@ -110,12 +113,16 @@ def test_get_differential_squeaks_default_min(): nMinBlockHeight=-1, nMaxBlockHeight=20, ) + differential_results = list( + get_differential_squeaks(interest, old_interest)) - differential_results = get_differential_squeaks(interest, old_interest) - first_result = next(differential_results) - assert first_result.addresses == squeak_addresses - assert first_result.nMinBlockHeight == -1 - assert first_result.nMaxBlockHeight == 9 + assert differential_results == [ + CInterested( + addresses=squeak_addresses, + nMinBlockHeight=-1, + nMaxBlockHeight=9, + ) + ] def test_get_differential_squeaks_default_max(): @@ -130,12 +137,16 @@ def test_get_differential_squeaks_default_max(): nMinBlockHeight=10, nMaxBlockHeight=-1, ) + differential_results = list( + get_differential_squeaks(interest, old_interest)) - differential_results = get_differential_squeaks(interest, old_interest) - first_result = next(differential_results) - assert first_result.addresses == squeak_addresses - assert first_result.nMinBlockHeight == 21 - assert first_result.nMaxBlockHeight == -1 + assert differential_results == [ + CInterested( + addresses=squeak_addresses, + nMinBlockHeight=21, + nMaxBlockHeight=-1, + ) + ] def test_get_differential_squeaks_new_addresses_and_min_max(): @@ -152,18 +163,21 @@ def test_get_differential_squeaks_new_addresses_and_min_max(): nMaxBlockHeight=-1, ) - differential_results = get_differential_squeaks(interest, old_interest) - first_result = next(differential_results) + differential_results = list( + get_differential_squeaks(interest, old_interest)) + assert len(differential_results) == 3 + + first_result = differential_results[0] assert set(first_result.addresses) == set(squeak_addresses) assert first_result.nMinBlockHeight == -1 assert first_result.nMaxBlockHeight == 9 - second_result = next(differential_results) + second_result = differential_results[1] assert set(second_result.addresses) == set(squeak_addresses) assert second_result.nMinBlockHeight == 21 assert second_result.nMaxBlockHeight == -1 - third_result = next(differential_results) + third_result = differential_results[2] assert set(third_result.addresses) == set(new_addresses) assert third_result.nMinBlockHeight == -1 assert third_result.nMaxBlockHeight == -1