2019-11-13 19:54:50 +00:00
"""
This file is part of nucypher .
nucypher is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
nucypher is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with nucypher . If not , see < https : / / www . gnu . org / licenses / > .
"""
2019-12-13 02:44:53 +00:00
from unittest . mock import patch
2019-11-13 19:54:50 +00:00
2019-12-13 02:44:53 +00:00
import maya
import pytest
2019-11-13 19:55:17 +00:00
import time
2019-12-13 02:44:53 +00:00
from flask import Response
from umbral . keys import UmbralPublicKey
2019-11-13 19:55:17 +00:00
from nucypher . characters . lawful import Ursula
2019-11-14 03:09:18 +00:00
from tests . performance_mocks import mock_cert_storage , mock_cert_loading , mock_verify_node , \
2019-11-14 02:51:50 +00:00
mock_message_verification , \
2019-12-13 02:44:53 +00:00
mock_metadata_validation , mock_signature_bytes , mock_stamp_call , mock_pubkey_from_bytes , VerificationTracker , \
NotARestApp , mock_secret_source , NotAPublicKey
2019-11-13 19:55:17 +00:00
2019-11-13 19:54:50 +00:00
"""
Node Discovery happens in phases . The first step is for a network actor to learn about the mere existence of a Node .
This is a straightforward step which we currently do with our own logic , but which may someday be replaced by something
2019-12-13 02:44:53 +00:00
like libp2p , depending on the course of development of those sorts of tools . The introduction of hamming distance
in particular is useful when wanting to learn about a small number ( ~ 500 ) of nodes among a much larger ( 25 , 000 + ) swarm .
This toolchain is not built for that scenario at this time , although it is not a stated nongoal .
2019-11-13 19:54:50 +00:00
After this , our " Learning Loop " does four other things in sequence which are not part of the offering of node discovery tooling alone :
* Instantiation of an actual Node object ( currently , an Ursula object ) from node metadata .
* Validation of the node ' s metadata (non-interactive; shows that the Node ' s public material is indeed signed by the wallet holder of its Staker ) .
* Verification of the Node itself ( interactive ; shows that the REST server operating at the Node ' s interface matches the node ' s metadata ) .
* Verification of the Stake ( reads the blockchain ; shows that the Node is sponsored by a Staker with sufficient Stake to support a Policy ) .
These tests show that each phase of this process is done correctly , and in some cases , with attention to specific
performance bottlenecks .
"""
2019-11-13 19:55:17 +00:00
2019-12-13 02:37:33 +00:00
def test_alice_can_learn_about_a_whole_bunch_of_ursulas ( highperf_mocked_alice ) :
2019-11-14 03:09:18 +00:00
# During the fixture execution, Alice verified one node.
2019-11-13 19:54:50 +00:00
# TODO: Consider changing this - #1449
assert VerificationTracker . node_verifications == 1
2019-11-14 02:48:17 +00:00
with mock_cert_storage , mock_cert_loading , mock_verify_node , mock_message_verification , mock_metadata_validation :
with mock_pubkey_from_bytes , mock_stamp_call , mock_signature_bytes :
started = time . time ( )
2019-12-13 02:37:33 +00:00
highperf_mocked_alice . block_until_number_of_known_nodes_is ( 8 , learn_on_this_thread = True )
2019-11-14 02:48:17 +00:00
ended = time . time ( )
elapsed = ended - started
2019-11-13 19:54:50 +00:00
2019-11-13 19:55:17 +00:00
assert VerificationTracker . node_verifications == 1 # We have only verified the first Ursula.
2019-11-20 04:40:40 +00:00
assert sum (
isinstance ( u , Ursula ) for u in highperf_mocked_alice . known_nodes ) < 20 # We haven't instantiated many Ursulas.
2019-12-13 02:37:33 +00:00
assert elapsed < 6 # 6 seconds is still a little long to discover 8 out of 5000 nodes, but before starting the optimization that went with this test, this operation took about 18 minutes on jMyles' laptop.
2019-11-20 04:40:40 +00:00
VerificationTracker . node_verifications = 0 # Cleanup
2019-12-13 02:37:33 +00:00
@pytest.mark.parametrize ( ' fleet_of_highperf_mocked_ursulas ' , [ 100 ] , indirect = True )
def test_alice_verifies_ursula_just_in_time ( fleet_of_highperf_mocked_ursulas , highperf_mocked_alice ,
2019-11-20 04:40:40 +00:00
highperf_mocked_bob ) :
2019-12-13 02:37:33 +00:00
_umbral_pubkey_from_bytes = UmbralPublicKey . from_bytes
2019-11-20 04:40:40 +00:00
def actual_random_key_instead ( * args , * * kwargs ) :
2019-12-13 02:37:33 +00:00
_previous_bytes = args [ 0 ]
serial = _previous_bytes [ - 5 : ]
pubkey = NotAPublicKey ( serial = serial )
return pubkey
2019-11-20 04:40:40 +00:00
def mock_set_policy ( id_as_hex ) :
return " "
def mock_receive_treasure_map ( treasure_map_id ) :
return Response ( bytes ( ) , status = 202 )
with NotARestApp . replace_route ( " receive_treasure_map " , mock_receive_treasure_map ) :
with NotARestApp . replace_route ( " set_policy " , mock_set_policy ) :
with patch ( ' umbral.keys.UmbralPublicKey.__eq__ ' , lambda * args , * * kwargs : True ) :
with patch ( ' umbral.keys.UmbralPublicKey.from_bytes ' ,
2019-12-13 02:44:53 +00:00
new = actual_random_key_instead ) :
with mock_cert_loading , mock_metadata_validation , mock_message_verification :
with mock_secret_source :
policy = highperf_mocked_alice . grant (
highperf_mocked_bob , b " any label " , m = 20 , n = 30 ,
expiration = maya . when ( ' next week ' ) ,
publish_treasure_map = False )
# TODO: Make some assertions about policy.
total_verified = sum ( node . verified_node for node in highperf_mocked_alice . known_nodes )
assert total_verified == 30