Beispiel #1
0
    def test_create_wait_certificate_before_create_wait_timer(self):
        # Need to create signup information
        SignupInfo.create_signup_info(
            originator_public_key_hash=self._originator_public_key_hash,
            most_recent_wait_certificate_id=NullIdentifier)

        with self.assertRaises(WaitCertificateError):
            WaitCertificate.create_wait_certificate("Reader's Digest")
Beispiel #2
0
    def test_create_wait_certificate_before_create_wait_timer(self):
        # Need to create signup information
        SignupInfo.create_signup_info(
            originator_public_key=self._originator_public_key,
            validator_network_basename="America's Most Watched Network",
            most_recent_wait_certificate_id=NullIdentifier)

        with self.assertRaises(WaitCertificateError):
            WaitCertificate.create_wait_certificate("Reader's Digest")
Beispiel #3
0
    def __init__(self,
                 gossip,
                 kwargs,
                 minimum_transactions_per_block=None,
                 max_transactions_per_block=None,
                 max_txn_age=None,
                 genesis_ledger=None,
                 restore=None,
                 data_directory=None,
                 store_type=None):
        """Constructor for the PoetJournal class.

        Args:
            node (Node): The local node.
        """
        super(PoetJournal,
              self).__init__(gossip, minimum_transactions_per_block,
                             max_transactions_per_block, max_txn_age,
                             genesis_ledger, restore, data_directory,
                             store_type)

        if 'PoetEnclaveImplementation' in kwargs:
            enclave_module = kwargs['PoetEnclaveImplementation']
        else:
            enclave_module = 'journal.consensus.poet1.poet_enclave_simulator' \
                             '.poet_enclave_simulator'

        poet_enclave = importlib.import_module(enclave_module)
        poet_enclave.initialize(**kwargs)
        WaitCertificate.poet_enclave = poet_enclave
        WaitTimer.poet_enclave = poet_enclave
        SignupInfo.poet_enclave = poet_enclave

        # initialize the poet handlers
        poet_transaction_block.register_message_handlers(self)

        # initialize stats specifically for the block chain journal
        self.JournalStats.add_metric(stats.Value('LocalMeanTime', 0))
        self.JournalStats.add_metric(stats.Value('AggregateLocalMean', '0'))
        self.JournalStats.add_metric(stats.Value('PopulationEstimate', '0'))
        self.JournalStats.add_metric(stats.Value('ExpectedExpirationTime',
                                                 '0'))
        self.JournalStats.add_metric(stats.Value('Duration', '0'))

        # propagate the maximum blocks to keep
        self.MaximumBlocksToKeep = max(self.MaximumBlocksToKeep,
                                       WaitTimer.certificate_sample_length)

        # Check to see if there is any pre-existing sealed signup data stored
        # in the local store
        sealed_signup_data = self.LocalStore.get('sealed_signup_data')

        # If we haven't signed up, we need to do that first.
        SignupInfo.create_signup_info(self.gossip.LocalNode.public_key())

        self.dispatcher.on_heartbeat += self._check_certificate
Beispiel #4
0
    def test_verify_unsealing_data(self):
        signup_info = \
            SignupInfo.create_signup_info(
                self._create_random_public_key())
        encoded_poet_public_key = \
            SignupInfo.unseal_signup_data(signup_info.sealed_signup_data)

        self.assertEqual(
            signup_info.poet_public_key,
            encoded_poet_public_key,
            msg="PoET public key in signup info and sealed data don't match")
    def test_verify_unsealing_data(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)
        poet_public_key = \
            SignupInfo.unseal_signup_data(signup_info.sealed_signup_data)

        self.assertEqual(
            signup_info.poet_public_key,
            poet_public_key,
            msg="PoET public key in signup info and sealed data don't match")
Beispiel #6
0
    def test_verify_serialized_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                self._create_random_public_key())
        serialized = signup_info.serialize()
        copy_signup_info = SignupInfo.signup_info_from_serialized(serialized)

        self.assertEqual(signup_info.poet_public_key,
                         copy_signup_info.poet_public_key)
        self.assertEqual(signup_info.anti_sybil_id,
                         copy_signup_info.anti_sybil_id)
        self.assertEqual(signup_info.proof_data, copy_signup_info.proof_data)
        self.assertIsNone(copy_signup_info.sealed_signup_data)
    def test_verify_unsealing_data(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)
        encoded_poet_public_key = \
            SignupInfo.unseal_signup_data(signup_info.sealed_signup_data)

        self.assertEqual(
            signup_info.poet_public_key,
            encoded_poet_public_key,
            msg="PoET public key in signup info and sealed data don't match")
    def test_verify_serialized_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)
        serialized = signup_info.serialize()
        copy_signup_info = SignupInfo.signup_info_from_serialized(serialized)

        self.assertEqual(signup_info.poet_public_key,
                         copy_signup_info.poet_public_key)
        self.assertEqual(signup_info.proof_data, copy_signup_info.proof_data)
        self.assertIsNone(copy_signup_info.sealed_signup_data)
    def test_verify_unsealing_data(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)
        encoded_poet_public_key = \
            SignupInfo.unseal_signup_data(signup_info.sealed_signup_data)

        self.assertEqual(
            signup_info.poet_public_key,
            encoded_poet_public_key,
            msg="PoET public key in signup info and sealed data don't match")
    def test_verify_serialized_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)
        serialized = signup_info.serialize()
        copy_signup_info = SignupInfo.signup_info_from_serialized(serialized)

        self.assertEqual(
            signup_info.poet_public_key,
            copy_signup_info.poet_public_key)
        self.assertEqual(signup_info.proof_data, copy_signup_info.proof_data)
        self.assertIsNone(copy_signup_info.sealed_signup_data)
    def test_verify_serialized_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)
        serialized = signup_info.serialize()
        copy_signup_info = SignupInfo.signup_info_from_serialized(serialized)

        self.assertEqual(signup_info.poet_public_key,
                         copy_signup_info.poet_public_key)
        self.assertEqual(signup_info.proof_data, copy_signup_info.proof_data)
        self.assertEqual(signup_info.anti_sybil_id,
                         copy_signup_info.anti_sybil_id)
        self.assertIsNone(copy_signup_info.sealed_signup_data)
Beispiel #12
0
    def test_create_wait_certificate(self):
        # Need to create signup information and wait timer first
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        wt = WaitTimer.create_wait_timer([])

        # Now we can create a wait certificate and verify that it correlates
        # to the wait timer we just created
        wc = WaitCertificate.create_wait_certificate("Reader's Digest")

        self.assertIsNotNone(wc)

        self.assertEquals(wc.previous_certificate_id,
                          wt.previous_certificate_id)
        self.assertEqual(wc.local_mean, wt.local_mean)
        self.assertEqual(wc.request_time, wt.request_time)
        self.assertEqual(wc.duration, wt.duration)
        self.assertEqual(wc.block_digest, "Reader's Digest")
        self.assertIsNotNone(wc.signature)
        self.assertIsNotNone(wc.identifier)

        # A newly-created wait certificate should be valid
        self.assertTrue(wc.is_valid([], signup_info.poet_public_key))
Beispiel #13
0
    def test_register_validator_re_register(self):
        key = signed_object.generate_signing_key()
        validator_id = signed_object.generate_identifier(key)
        name = 'DasValidator'
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=pybitcointools.privtopub(key),
                validator_network_basename='Intel Validator Network',
                most_recent_wait_certificate_id='0' * 16)

        store = KeyValueStore()
        transaction = \
            ValidatorRegistryTransaction.register_validator(
                name,
                validator_id,
                signup_info)
        transaction.sign_object(key)
        try:
            transaction.check_valid(store)
            transaction.apply(store)
        except InvalidTransactionError as e:
            self.fail('Failed valid transaction: {}'.format(e))
        try:  # check if valid to register again
            transaction.check_valid(store)
        except InvalidTransactionError as e:
            self.fail('Failure: Double registered validator: {}'.format(e))
Beispiel #14
0
    def test_wait_certificate_serialization(self):
        # Need to create signup information and wait timer first
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        wt = WaitTimer.create_wait_timer([])

        # Now we can create a wait certificate and serialize
        wc = WaitCertificate.create_wait_certificate("Reader's Digest")

        dumped = wc.dump()

        self.assertIsNotNone(dumped.get('SerializedCertificate'))
        self.assertIsNotNone(dumped.get('Signature'))

        # Deserialize and verify that wait certificates are the same
        # and that deserialized one is valid
        wc_copy = \
            WaitCertificate.wait_certificate_from_serialized(
                dumped.get('SerializedCertificate'),
                dumped.get('Signature'),
                signup_info.poet_public_key)

        self.assertEquals(wc.previous_certificate_id,
                          wc_copy.previous_certificate_id)
        self.assertEqual(wc.local_mean, wc_copy.local_mean)
        self.assertEqual(wc.request_time, wc_copy.request_time)
        self.assertEqual(wc.duration, wc_copy.duration)
        self.assertEqual(wc.block_digest, wc_copy.block_digest)
        self.assertEqual(wc.signature, wc_copy.signature)
        self.assertEqual(wc.identifier, wc_copy.identifier)

        self.assertTrue(wc_copy.is_valid([], signup_info.poet_public_key))
    def __init__(self, minfo=None):
        """Constructor for Update class.

        Args:
            minfo (dict): Update values extracted from a message
                {'verb', 'validator_name', 'validator_id', 'signup_info'}
        """

        if minfo is None:
            minfo = {}
        self.verb = minfo.get('verb', 'reg')
        self.validator_name = minfo.get('validator_name', '')
        self.validator_id = minfo.get('validator_id', NullIdentifier)
        signup_info = SignupInfo.deserialize(minfo.get('signup_info'))
        self.signup_info = SignupInfo(signup_info.get('anti_sybil_id', ''),
                                      signup_info.get('poet_pubkey', ''),
                                      signup_info.get('proof_data', ''))
Beispiel #16
0
    def test_basic_create_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                self._create_random_public_key())

        self.assertIsNotNone(signup_info.poet_public_key)
        self.assertIsNotNone(signup_info.anti_sybil_id)
        self.assertIsNotNone(signup_info.proof_data)
        self.assertIsNotNone(signup_info.sealed_signup_data)
    def test_basic_create_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        self.assertIsNotNone(signup_info.poet_public_key)
        self.assertIsNotNone(signup_info.proof_data)
        self.assertIsNotNone(signup_info.sealed_signup_data)
    def test_basic_create_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        self.assertIsNotNone(signup_info.poet_public_key)
        self.assertIsNotNone(signup_info.proof_data)
        self.assertIsNotNone(signup_info.sealed_signup_data)
    def test_non_matching_originator_public_key(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        with self.assertRaises(SignupInfoError):
            signup_info.check_valid(
                originator_public_key_hash=self._another_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)
    def test_basic_create_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        self.assertIsNotNone(signup_info.poet_public_key)
        self.assertIsNotNone(signup_info.proof_data)
        self.assertIsNotNone(signup_info.anti_sybil_id)
        self.assertIsNotNone(signup_info.sealed_signup_data)
    def test_has_expired(self):
        # Need to create signup information first
        SignupInfo.create_signup_info(
            originator_public_key=self._originator_public_key,
            validator_network_basename="America's Most Watched Network",
            most_recent_wait_certificate_id=NullIdentifier)

        # Verify that a timer doesn't expire before its creation time
        wt = wait_timer.WaitTimer.create_wait_timer([])
        self.assertFalse(wt.has_expired(wt.request_time - 1))

        # Create a timer and when it has expired, verify that the duration is
        # not greater than actual elapsed time.
        wt = wait_timer.WaitTimer.create_wait_timer([])

        while not wt.has_expired(time.time()):
            time.sleep(1)

        self.assertLessEqual(wt.duration, time.time() - wt.request_time)

        # Tampering with the duration should not affect wait timer expiration
        wt = wait_timer.WaitTimer.create_wait_timer([])

        assigned_duration = wt.duration
        wt.duration = 0

        while not wt.has_expired(time.time()):
            time.sleep(1)

        self.assertLessEqual(assigned_duration, time.time() - wt.request_time)

        # Tampering with the request time should not affect wait timer
        # expiration
        wt = wait_timer.WaitTimer.create_wait_timer([])
        assigned_request_time = wt.request_time
        wt.request_time -= wt.duration

        while not wt.has_expired(time.time()):
            time.sleep(1)

        self.assertLessEqual(wt.duration, time.time() - assigned_request_time)
    def test_non_matching_validator_network_basename(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        with self.assertRaises(SignupInfoError):
            signup_info.check_valid(
                originator_public_key=self._originator_public_key,
                validator_network_basename="This is Fox News.",
                most_recent_wait_certificate_id=NullIdentifier)
    def test_verify_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        try:
            signup_info.check_valid(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)
        except SignupInfoError as e:
            self.fail('Error with SignupInfo: {}'.format(e))
    def test_non_matching_validator_network_basename(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        with self.assertRaises(SignupInfoError):
            signup_info.check_valid(
                originator_public_key=self._originator_public_key,
                validator_network_basename="This is Fox News.",
                most_recent_wait_certificate_id=NullIdentifier)
    def test_verify_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        try:
            signup_info.check_valid(
                originator_public_key=self._originator_public_key,
                validator_network_basename="This is CNN.",
                most_recent_wait_certificate_id=NullIdentifier)
        except SignupInfoError as e:
            self.fail('Error with SignupInfo: {}'.format(e))
    def test_verify_signup_info(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        try:
            signup_info.check_valid(
                originator_public_key=self._originator_public_key,
                validator_network_basename="This is CNN.",
                most_recent_wait_certificate_id=NullIdentifier)
        except SignupInfoError as e:
            self.fail('Error with SignupInfo: {}'.format(e))
    def __init__(self, minfo=None):
        """Constructor for Update class.

        Args:
            minfo (dict): Update values extracted from a message
                {'verb', 'validator_name', 'validator_id', 'signup_info'}
        """

        if minfo is None:
            minfo = {}
        self.verb = minfo.get('verb', 'reg')
        self.validator_name = minfo.get('validator_name', '')
        self.validator_id = minfo.get('validator_id', NullIdentifier)
        self.signup_info = \
            SignupInfo.signup_info_from_serialized(minfo.get('signup_info'))
    def test_non_matching_most_recent_wait_certificate_id(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key_hash=self._originator_public_key_hash,
                most_recent_wait_certificate_id=NullIdentifier)

        # NOTE - this requires that the signup information check for validity
        #        actually make this check.  Currently the check is not done.
        #        Once the check is added back, it should raise a
        #        SignupInfoError exception and this test will fail, alerting
        #        you that you need to wrap the call in self.assertRaises
        #
        # with self.assertRaises(SignupInfoError):
        signup_info.check_valid(
            originator_public_key_hash=self._originator_public_key_hash,
            most_recent_wait_certificate_id='SomeFunkyCertificateID')
    def test_non_matching_most_recent_wait_certificate_id(self):
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename='This is CNN.',
                most_recent_wait_certificate_id=NullIdentifier)

        # NOTE - this requires that the signup information check for validity
        #        actually make this check.  Currently the check is not done.
        #        Once the check is added back, it should raise a
        #        SignupInfoError exception and this test will fail, alerting
        #        you that you need to wrap the call in self.assertRaises
        #
        # with self.assertRaises(SignupInfoError):
        signup_info.check_valid(
            originator_public_key=self._originator_public_key,
            validator_network_basename="This is CNN.",
            most_recent_wait_certificate_id='SomeFunkyCertificateID')
Beispiel #30
0
    def test_register_validator_key_mismatch(self):
        key = signed_object.generate_signing_key()
        key2 = signed_object.generate_signing_key()
        validator_id = signed_object.generate_identifier(key)
        name = 'DasValidator'
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=pybitcointools.privtopub(key),
                validator_network_basename='Intel Validator Network',
                most_recent_wait_certificate_id='0' * 16)

        store = KeyValueStore()
        transaction = \
            ValidatorRegistryTransaction.register_validator(
                name,
                validator_id,
                signup_info)
        transaction.sign_object(key2)
        with self.assertRaises(InvalidTransactionError):
            transaction.check_valid(store)
            self.fail("Failure: Verified an invalid transaction")
Beispiel #31
0
    def initialization_complete(self, journal):
        """Processes all invocations that arrived while the ledger was
        being initialized.
        """
        # Before we allow the base journal to do anything that might result
        # in a wait timer or wait certificate from being created, we have to
        # ensure that the PoET enclave has been initialized.  This can be done
        # in one of two ways:
        # 1. If we have sealed signup data (meaning that we have previously
        #    created signup info), we can request that the enclave unseal it,
        #    in the process restoring the enclave to its previous state.
        # 2. Create new signup information.
        signup_info = None
        sealed_signup_data = journal.local_store.get('sealed_signup_data')

        if sealed_signup_data is not None:
            SignupInfo.unseal_signup_data(
                sealed_signup_data=sealed_signup_data)
        else:
            wait_certificate_id = journal.most_recent_committed_block_id
            signup_info = \
                SignupInfo.create_signup_info(
                    originator_public_key=journal.local_node.public_key(),
                    validator_network_basename='Intel Validator Network',
                    most_recent_wait_certificate_id=wait_certificate_id)

            # Save off the sealed signup data
            self.local_store.set('sealed_signup_data',
                                 signup_info.sealed_signup_data)
            self.local_store.sync()

            # initialize the poet handlers
            poet_transaction_block.register_message_handlers(journal)

            # initialize stats specifically for the block chain journal
            journal.JournalStats.add_metric(stats.Value('LocalMeanTime', 0))
            journal.JournalStats.add_metric(
                stats.Value('AggregateLocalMean', '0'))
            journal.JournalStats.add_metric(
                stats.Value('PopulationEstimate', '0'))
            journal.JournalStats.add_metric(
                stats.Value('ExpectedExpirationTime', '0'))
            journal.JournalStats.add_metric(stats.Value('Duration', '0'))

        # If we created signup information, then insert ourselves into the
        # validator registry.
        if signup_info is not None:
            # Create a validator register transaction and sign it.  Wrap
            # the transaction in a message.  Broadcast it to out.
            transaction = \
                val_reg.ValidatorRegistryTransaction.register_validator(
                    self.local_node.Name,
                    self.local_node.Identifier,
                    signup_info)
            transaction.sign_from_node(self.local_node)

            message = \
                val_reg.ValidatorRegistryTransactionMessage()
            message.Transaction = transaction

            LOGGER.info('Register PoET 1 validator with name %s',
                        journal.local_node.Name)

            journal.gossip.broadcast_message(message)
    def test_create_wait_timer(self):
        # Need to create signup information first
        signup_info = \
            SignupInfo.create_signup_info(
                originator_public_key=self._originator_public_key,
                validator_network_basename="America's Most Watched Network",
                most_recent_wait_certificate_id=NullIdentifier)

        stake_in_the_sand = time.time()

        # An empty certificate list should result in a local mean that is
        # the target wait time
        wt = wait_timer.WaitTimer.create_wait_timer([])

        self.assertIsNotNone(wt)
        self.assertEqual(wt.local_mean, wait_timer.WaitTimer.target_wait_time)
        self.assertEquals(wt.previous_certificate_id, NullIdentifier)
        self.assertGreaterEqual(wt.request_time, stake_in_the_sand)
        self.assertLessEqual(wt.request_time, time.time())
        self.assertGreaterEqual(
            wt.duration,
            wait_timer.WaitTimer.minimum_wait_time)

        wt = wait_timer.WaitTimer.create_wait_timer(tuple())

        self.assertIsNotNone(wt)
        self.assertEqual(wt.local_mean, wait_timer.WaitTimer.target_wait_time)
        self.assertEquals(wt.previous_certificate_id, NullIdentifier)
        self.assertGreaterEqual(wt.request_time, stake_in_the_sand)
        self.assertLessEqual(wt.request_time, time.time())
        self.assertGreaterEqual(
            wt.duration,
            wait_timer.WaitTimer.minimum_wait_time)

        # Ensure that the enclave is set back to initial state
        SignupInfo.poet_enclave = reload(poet_enclave)
        wait_timer.WaitTimer.poet_enclave = SignupInfo.poet_enclave

        # Make sure that trying to create a wait timer before signup
        # information is provided causes an error
        with self.assertRaises(wait_timer.WaitTimerError):
            wait_timer.WaitTimer.create_wait_timer([])

        with self.assertRaises(wait_timer.WaitTimerError):
            wait_timer.WaitTimer.create_wait_timer(tuple())

        # Initialize the enclave with sealed signup data
        SignupInfo.unseal_signup_data(signup_info.sealed_signup_data)

        stake_in_the_sand = time.time()

        # An empty certificate list should result in a local mean that is
        # the target wait time
        wt = wait_timer.WaitTimer.create_wait_timer([])

        self.assertIsNotNone(wt)
        self.assertEqual(wt.local_mean, wait_timer.WaitTimer.target_wait_time)
        self.assertEquals(wt.previous_certificate_id, NullIdentifier)
        self.assertGreaterEqual(wt.request_time, stake_in_the_sand)
        self.assertLessEqual(wt.request_time, time.time())
        self.assertGreaterEqual(
            wt.duration,
            wait_timer.WaitTimer.minimum_wait_time)

        wt = wait_timer.WaitTimer.create_wait_timer(tuple())

        self.assertIsNotNone(wt)
        self.assertEqual(wt.local_mean, wait_timer.WaitTimer.target_wait_time)
        self.assertEquals(wt.previous_certificate_id, NullIdentifier)
        self.assertGreaterEqual(wt.request_time, stake_in_the_sand)
        self.assertLessEqual(wt.request_time, time.time())
        self.assertGreaterEqual(
            wt.duration,
            wait_timer.WaitTimer.minimum_wait_time)
class Update(object):
    """Updates represent potential changes to the endpoint registry.

    Attributes:
        validator_registry.Update.KnownVerbs (list): A list of possible update
            actions. Currently register. In the future may include revoke.
        verb (str): The action of this update, defaults to 'reg'.
        validator_name (str): The name of the endpoint.
        validator_id (str): The identifier of the endpoint.
        poet_pubkey: Public key used by this poet to sign wait certificates
        anti_sybil_id: A token, such as an EPID pseudonym, to restrict the
            number of identities an entity can assume in the network.
        signup_info: Serialized authorization data for network enrollment
            Contains required elements poet_pubkey and anti_sybil_token
    """
    KnownVerbs = ['reg']

    @staticmethod
    def register_validator(validator_name, validator_id, signup_info):
        """Creates a new Update object to register a validator.

        Args:
            validator_name: Human readable name of the validator
            validator_id: Bitcoin-style address of the validators public key
            signup_info: Serialized dict of SignupData with keys...
                anti_sybil_token, poet_pubkey, proof_data

        Returns:
            validator_registry.Update: An update object for registering the
                validator's details.
        """
        minfo = {}
        minfo['validator_name'] = validator_name
        minfo['validator_id'] = validator_id
        minfo['signup_info'] = signup_info
        update = Update(minfo)
        update.verb = 'reg'
        return update

    def __init__(self, minfo=None):
        """Constructor for Update class.

        Args:
            minfo (dict): Update values extracted from a message
                {'verb', 'validator_name', 'validator_id', 'signup_info'}
        """

        if minfo is None:
            minfo = {}
        self.verb = minfo.get('verb', 'reg')
        self.validator_name = minfo.get('validator_name', '')
        self.validator_id = minfo.get('validator_id', NullIdentifier)
        signup_info = SignupInfo.deserialize(minfo.get('signup_info'))
        self.signup_info = SignupInfo(signup_info.get('anti_sybil_id', ''),
                                      signup_info.get('poet_pubkey', ''),
                                      signup_info.get('proof_data', ''))

    def __str__(self):
        return str(self.dump())

    def is_valid_name(self):
        """
        Ensure that the name property meets syntactic requirements.
        """

        if self.validator_name == '':
            return True

        if len(self.validator_name) >= 64:
            LOGGER.debug('invalid name %s; must be less than 64 bytes',
                         self.validator_name)
            return False

        return True

    def check_valid(self, store, txn):
        """Determines if the update is valid.
            Check policy on each element of validator_name, validator_id,
            and signup_info

        Args:
            store (Store): Transaction store.
            txn (Transaction): Transaction encompassing this update.
        """
        LOGGER.debug('check update %s from %s', str(self), self.validator_id)

        # Check name
        if not self.is_valid_name():
            raise InvalidTransactionError(
                'Illegal validator name {}'.format(self.validator_name[:64]))

        # Check registering validator matches transaction signer.
        if self.validator_id != txn.OriginatorID:
            raise InvalidTransactionError(
                'Signature mismatch on validator registration with validator'
                ' {} signed by {}'.format(self.validator_id,
                                          txn.OriginatorID))

        # Nothing to check for anti_sybil_id
        # Apply will invalidate any previous entries for this anti_sybil_id
        # and create a new entry.

        # Check signup_info. Policy is encapsulated by SignupInfo.
        if not self.signup_info.is_valid():
            raise InvalidTransactionError(
                'Invalid Signup Info: {}'.format(self.signup_info))
        return True

    def apply(self, store, txn):
        """Applies the update to the validator entry in the store.

        Args:
            store (Store): Transaction store.
            txn (Transaction): Transaction encompassing this update.
        """
        LOGGER.debug('apply %s', str(self))

        # invalidate any previous entries
        for validator, registration in store.iteritems():
            if registration['anti_sybil_id'] == self.signup_info.anti_sybil_id:
                if registration['revoked'] is not None:
                    registration['revoked'] = txn.Identifier

        if self.verb == 'reg':
            store[self.validator_id] = {
                'validator_name': self.validator_name,
                'validator_id': self.validator_id,
                'poet_pubkey': self.signup_info.poet_pubkey,
                'anti_sybil_id': self.signup_info.anti_sybil_id,
                'proof_data': self.signup_info.proof_data,
                'revoked': None,
            }
        else:
            LOGGER.info('unknown verb %s', self.verb)

    def dump(self):
        """Returns a dict with attributes from the update object.

        Returns:
            dict: A dictionary containing attributes from the update
                object.
        """

        result = {
            'verb': self.verb,
            'validator_name': self.validator_name,
            'validator_id': self.validator_id,
            'signup_info': self.signup_info.serialize(),
        }
        return result
    def initialization_complete(self, journal):
        """Processes all invocations that arrived while the ledger was
        being initialized.
        """
        # Before we allow the base journal to do anything that might result
        # in a wait timer or wait certificate being created, we have to ensure
        # the PoET enclave has been initialized.  This can be done in one of
        # two ways:
        # 1. If we have sealed signup data (meaning that we have previously
        #    created signup info), we can request that the enclave unseal it,
        #    in the process restoring the enclave to its previous state.
        # 2. Create new signup information.
        signup_info = None
        sealed_signup_data = journal.local_store.get('sealed_signup_data')

        if sealed_signup_data is not None:
            SignupInfo.unseal_signup_data(
                sealed_signup_data=sealed_signup_data)
        else:
            wait_certificate_id = journal.most_recent_committed_block_id
            signup_info = \
                SignupInfo.create_signup_info(
                    originator_public_key=journal.local_node.public_key(),
                    validator_network_basename='Intel Validator Network',
                    most_recent_wait_certificate_id=wait_certificate_id)

            # Save off the sealed signup data
            journal.local_store.set(
                'sealed_signup_data',
                signup_info.sealed_signup_data)
            journal.local_store.sync()

        # propagate the maximum blocks to keep
        journal.maximum_blocks_to_keep = max(
            journal.maximum_blocks_to_keep,
            WaitTimer.certificate_sample_length)

        # initialize stats specifically for the block chain journal
        journal.JournalStats.add_metric(stats.Value('LocalMeanTime', 0))
        journal.JournalStats.add_metric(stats.Value('AggregateLocalMean', '0'))
        journal.JournalStats.add_metric(stats.Value('PopulationEstimate', '0'))
        journal.JournalStats.add_metric(stats.Value('ExpectedExpirationTime',
                                                    '0'))
        journal.JournalStats.add_metric(stats.Value('Duration', '0'))

        # initialize the block handlers
        poet_transaction_block.register_message_handlers(journal)

        # If we created signup information, then insert ourselves into the
        # validator registry.
        if signup_info is not None:
            # Create a validator register transaction and sign it.  Wrap
            # the transaction in a message.  Broadcast it to out.
            transaction = \
                val_reg.ValidatorRegistryTransaction.register_validator(
                    journal.local_node.Name,
                    journal.local_node.Identifier,
                    signup_info)
            transaction.sign_from_node(journal.local_node)

            message = \
                val_reg.ValidatorRegistryTransactionMessage()
            message.Transaction = transaction

            LOGGER.info(
                'Register PoET 1 validator with name %s',
                journal.local_node.Name)

            journal.gossip.broadcast_message(message)