Example #1
0
 def _read_injector_setting(self, state_root_hash):
     state_view = self._state_view_factory.create_view(state_root_hash)
     settings_view = SettingsView(state_view)
     batch_injector_setting = settings_view.get_setting(
         "sawtooth.validator.batch_injectors")
     return [] if not batch_injector_setting \
         else batch_injector_setting.split(',')
    def initialize_block(self, block_header):
        """Do initialization necessary for the consensus to claim a block,
        this may include initiating voting activates, starting proof of work
        hash generation, or create a PoET wait timer.

        Args:
            block_header (BlockHeader): the BlockHeader to initialize.
        Returns:
            True
        """
        # Using the current chain head, we need to create a state view so we
        # can get our config values.
        state_view = \
            BlockWrapper.state_view_for_block(
                self._block_cache.block_store.chain_head,
                self._state_view_factory)

        settings_view = SettingsView(state_view)
        self._min_wait_time = settings_view.get_setting(
            "sawtooth.consensus.min_wait_time", self._min_wait_time, int)
        self._max_wait_time = settings_view.get_setting(
            "sawtooth.consensus.max_wait_time", self._max_wait_time, int)
        self._valid_block_publishers = settings_view.get_setting(
            "sawtooth.consensus.valid_block_publishers",
            self._valid_block_publishers,
            list)

        block_header.consensus = b"Devmode"
        self._start_time = time.time()
        self._wait_time = random.uniform(
            self._min_wait_time, self._max_wait_time)
        return True
Example #3
0
    def _build_candidate_block(self, chain_head):
        """ Build a candidate block and construct the consensus object to
        validate it.
        :param chain_head: The block to build on top of.
        :return: (BlockBuilder) - The candidate block in a BlockBuilder
        wrapper.
        """
        state_view = BlockWrapper.state_view_for_block(
            chain_head,
            self._state_view_factory)
        consensus_module = ConsensusFactory.get_configured_consensus_module(
            chain_head.header_signature,
            state_view)

        settings_view = SettingsView(state_view)
        max_batches = settings_view.get_setting(
            'sawtooth.publisher.max_batches_per_block',
            default_value=0, value_type=int)

        consensus = consensus_module.\
            BlockPublisher(block_cache=self._block_cache,
                           state_view_factory=self._state_view_factory,
                           batch_publisher=self._batch_publisher,
                           data_dir=self._data_dir,
                           config_dir=self._config_dir,
                           validator_id=self._identity_public_key)

        block_header = BlockHeader(
            block_num=chain_head.block_num + 1,
            previous_block_id=chain_head.header_signature,
            signer_pubkey=self._identity_public_key)
        block_builder = BlockBuilder(block_header)
        if not consensus.initialize_block(block_builder.block_header):
            LOGGER.debug("Consensus not ready to build candidate block.")
            return None

        # create a new scheduler
        scheduler = self._transaction_executor.create_scheduler(
            self._squash_handler, chain_head.state_root_hash)

        # build the TransactionCache
        committed_txn_cache = TransactionCache(self._block_cache.block_store)

        self._transaction_executor.execute(scheduler)
        self._candidate_block = _CandidateBlock(self._block_cache.block_store,
                                                consensus, scheduler,
                                                committed_txn_cache,
                                                block_builder,
                                                max_batches)
        for batch in self._pending_batches:
            if self._candidate_block.can_add_batch:
                self._candidate_block.add_batch(batch)
            else:
                break
Example #4
0
    def _build_candidate_block(self, chain_head):
        """ Build a candidate block and construct the consensus object to
        validate it.
        :param chain_head: The block to build on top of.
        :return: (BlockBuilder) - The candidate block in a BlockBuilder
        wrapper.
        """
        state_view = BlockWrapper.state_view_for_block(
            chain_head, self._state_view_factory)
        consensus_module = ConsensusFactory.get_configured_consensus_module(
            chain_head.header_signature, state_view)

        settings_view = SettingsView(state_view)
        max_batches = settings_view.get_setting(
            'sawtooth.publisher.max_batches_per_block',
            default_value=0,
            value_type=int)

        consensus = consensus_module.\
            BlockPublisher(block_cache=self._block_cache,
                           state_view_factory=self._state_view_factory,
                           batch_publisher=self._batch_publisher,
                           data_dir=self._data_dir,
                           config_dir=self._config_dir,
                           validator_id=self._identity_public_key)

        block_header = BlockHeader(
            block_num=chain_head.block_num + 1,
            previous_block_id=chain_head.header_signature,
            signer_pubkey=self._identity_public_key)
        block_builder = BlockBuilder(block_header)
        if not consensus.initialize_block(block_builder.block_header):
            LOGGER.debug("Consensus not ready to build candidate block.")
            return None

        # create a new scheduler
        scheduler = self._transaction_executor.create_scheduler(
            self._squash_handler, chain_head.state_root_hash)

        # build the TransactionCache
        committed_txn_cache = TransactionCache(self._block_cache.block_store)

        self._transaction_executor.execute(scheduler)
        self._candidate_block = _CandidateBlock(self._block_cache.block_store,
                                                consensus, scheduler,
                                                committed_txn_cache,
                                                block_builder, max_batches)
        for batch in self._pending_batches:
            if self._candidate_block.can_add_batch:
                self._candidate_block.add_batch(batch)
            else:
                break
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(DictDatabase())
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        self.signing_key = signing.generate_privkey()
        self.public_key = signing.generate_pubkey(self.signing_key)

        self.identity_signing_key = signing.generate_privkey()
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            self.set_chain_head(self.genesis_block)
            chain_head = self.genesis_block

        self.block_publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_cache,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            squash_handler=None,
            chain_head=chain_head,
            identity_signing_key=self.identity_signing_key,
            data_dir=None,
            config_dir=None)
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(DictDatabase())
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        self.signing_key = signing.generate_privkey()
        self.public_key = signing.generate_pubkey(self.signing_key)

        self.identity_signing_key = signing.generate_privkey()
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            self.set_chain_head(self.genesis_block)
            chain_head = self.genesis_block

        self.block_publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_cache,
            state_view_factory=self.state_view_factory,
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            squash_handler=None,
            chain_head=chain_head,
            identity_signing_key=self.identity_signing_key,
            data_dir=None,
            config_dir=None)
Example #7
0
    def create_state_view_factory(self, values):
        state_db = {}
        if values is not None:
            for key, value in values.items():
                state_db[SettingsView.setting_address(key)] = \
                    TestCheckPublishBlock._setting_entry(key, repr(value))

        return MockStateViewFactory(state_db)
Example #8
0
    def create_state_view_factory(self, values):
        state_db = {}
        if values is not None:
            for key, value in values.items():
                state_db[SettingsView.setting_address(key)] = \
                    TestCheckPublishBlock._setting_entry(key, repr(value))

        return MockStateViewFactory(state_db)
Example #9
0
def CreateSetting(key, value):
    """
    Create a setting object to include in a MockStateFactory.
    """
    addr = SettingsView.setting_address(key)

    setting = Setting()
    setting.entries.add(key=key, value=str(value))
    return addr, setting.SerializeToString()
Example #10
0
def CreateSetting(key, value):
    """
    Create a setting object to include in a MockStateFactory.
    """
    addr = SettingsView.setting_address(key)

    setting = Setting()
    setting.entries.add(key=key, value=str(value))
    return addr, setting.SerializeToString()
Example #11
0
    def get_configured_consensus_module(block_id, state_view):
        """Returns the consensus_module based on the consensus module set by
        the "sawtooth_settings" transaction family.

        Args:
            block_id (str): the block id associated with the current state_view
            state_view (:obj:`StateView`): the current state view to use for
                setting values
        Raises:
            UnknownConsensusModuleError: Thrown when an invalid consensus
                module has been configured.
        """
        settings_view = SettingsView(state_view)

        default_consensus = \
            'genesis' if block_id == NULL_BLOCK_IDENTIFIER else 'devmode'
        consensus_module_name = settings_view.get_setting(
            'sawtooth.consensus.algorithm', default_value=default_consensus)
        return ConsensusFactory.get_consensus_module(consensus_module_name)
    def get_configured_consensus_module(block_id, state_view):
        """Returns the consensus_module based on the consensus module set by
        the "sawtooth_settings" transaction family.

        Args:
            block_id (str): the block id associated with the current state_view
            state_view (:obj:`StateView`): the current state view to use for
                setting values
        Raises:
            UnknownConsensusModuleError: Thrown when an invalid consensus
                module has been configured.
        """
        settings_view = SettingsView(state_view)

        default_consensus = \
            'genesis' if block_id == NULL_BLOCK_IDENTIFIER else 'devmode'
        consensus_module_name = settings_view.get_setting(
            'sawtooth.consensus.algorithm', default_value=default_consensus)
        return ConsensusFactory.get_consensus_module(
            consensus_module_name)
Example #13
0
    def initialize_block(self, previous_block):
        """Begin building a new candidate block.

        Args:
            previous_block (BlockWrapper): The block to base the new block on.

        Raises:
            ConsensusNotReady
                Consensus is not ready to build a block
        """

        # using previous_block so so we can use the setting_cache
        max_batches = int(
            self._settings_cache.get_setting(
                'sawtooth.publisher.max_batches_per_block',
                previous_block.state_root_hash,
                default_value=0))

        state_view = BlockWrapper.state_view_for_block(
            previous_block, self._state_view_factory)

        public_key = self._identity_signer.get_public_key().as_hex()
        consensus = self._load_consensus(previous_block, state_view,
                                         public_key)
        batch_injectors = self._load_injectors(previous_block)

        block_header = BlockHeader(
            block_num=previous_block.block_num + 1,
            previous_block_id=previous_block.header_signature,
            signer_public_key=public_key)
        block_builder = BlockBuilder(block_header)

        if not consensus.initialize_block(block_builder.block_header):
            raise ConsensusNotReady()

        # create a new scheduler
        scheduler = self._transaction_executor.create_scheduler(
            previous_block.state_root_hash)

        # build the TransactionCommitCache
        committed_txn_cache = TransactionCommitCache(
            self._block_cache.block_store)

        self._transaction_executor.execute(scheduler)
        self._candidate_block = _CandidateBlock(
            self._block_cache.block_store, consensus, scheduler,
            committed_txn_cache, block_builder, max_batches, batch_injectors,
            SettingsView(state_view), self._identity_signer)

        for batch in self._pending_batches:
            if self._candidate_block.can_add_batch():
                self._candidate_block.add_batch(batch)
            else:
                break
    def __init__(self, state_view):
        """Initialize a PoetSettingsView object.

        Args:
            state_view (StateView): The current state view.

        Returns:
            None
        """

        self._settings_view = SettingsView(state_view)

        self._block_claim_delay = None
        self._enclave_module_name = None
        self._initial_wait_time = None
        self._key_block_claim_limit = None
        self._minimum_wait_time = None
        self._population_estimate_sample_size = None
        self._target_wait_time = None
        self._signup_commit_maximum_delay = None
        self._ztest_maximum_win_deviation = None
        self._ztest_minimum_win_count = None
Example #15
0
    def __init__(self,
                 block_cache,
                 state_view_factory,
                 data_dir,
                 config_dir,
                 validator_id):
        super().__init__(
            block_cache,
            state_view_factory,
            data_dir,
            config_dir,
            validator_id)
        self._block_cache = block_cache
        self._state_view_factory = state_view_factory

        state_view = \
            BlockWrapper.state_view_for_block(
                self._block_cache.block_store.chain_head,
                self._state_view_factory)

        settings_view = SettingsView(state_view)
        self._difficulty = settings_view.get_setting(
            "sawtooth.truss.difficulty", self._difficulty, int)
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(
            DictDatabase(indexes=BlockStore.create_index_configuration()))
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        self.block_manager = BlockManager()
        self.block_manager.add_store("commit_store", self.block_store)

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            chain_head = self.genesis_block
            self.block_manager.put([chain_head.block])
            self.block_manager.persist(chain_head.block.header_signature,
                                       "commit_store")

        self.block_publisher = BlockPublisher(
            block_manager=self.block_manager,
            transaction_executor=MockTransactionExecutor(),
            transaction_committed=self.block_store.has_transaction,
            batch_committed=self.block_store.has_batch,
            state_view_factory=self.state_view_factory,
            settings_cache=SettingsCache(
                SettingsViewFactory(self.state_view_factory), ),
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            chain_head=chain_head.block,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            batch_observers=[])
Example #17
0
    def check_publish_block(self, block_header):
        """Check if a candidate block is ready to be claimed.

        block_header (BlockHeader): the block_header to be checked if it
            should be claimed
        Returns:
            Boolean: True if the candidate block_header should be claimed.
        """
        # Using the current chain head, we need to create a state view so we
        # can get our config values.
        state_view = \
            BlockWrapper.state_view_for_block(
                self._block_cache.block_store.chain_head,
                self._state_view_factory)

        settings_view = SettingsView(state_view)
        self._difficulty = settings_view.get_setting(
            "sawtooth.truss.difficulty", self._difficulty, int)

        if any(publisher_key != block_header.signer_public_key
               for publisher_key in self._valid_block_publishers):
            return False

         return proof_of_work(block_header.state_hash, self._nonce)
    def initialize_block(self, block_header):
        """Do initialization necessary for the consensus to claim a block,
        this may include initiating voting activates, starting proof of work
        hash generation, or create a PoET wait timer.

        Args:
            block_header (BlockHeader): the BlockHeader to initialize.
        Returns:
            True
        """
        if not self._consensus:
            LOGGER.debug(
                "initialize_block: external consensus not regitered\n")
            return False
        # Using the current chain head, we need to create a state view so we
        # can get our config values.
        state_view = BlockWrapper.state_view_for_block(
            self._block_cache.block_store.chain_head, self._state_view_factory)

        settings_view = SettingsView(state_view)
        self._min_wait_time = settings_view.get_setting(
            "bgx.consensus.min_wait_time", self._min_wait_time, float)
        self._max_wait_time = settings_view.get_setting(
            "bgx.consensus.max_wait_time", self._max_wait_time, float)
        self._valid_block_publishers = settings_view.get_setting(
            "bgx.consensus.valid_block_publishers",
            self._valid_block_publishers, list)

        block_header.consensus = self._consensus  # b"Devmode"
        self._start_time = time.time()
        self._wait_time = random.uniform(self._min_wait_time,
                                         self._max_wait_time)
        LOGGER.debug(
            "PROXY:initialize_block min_wait_time=%s max_wait_time=%s",
            self._min_wait_time, self._max_wait_time)
        return True
Example #19
0
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(DictDatabase(
            indexes=BlockStore.create_index_configuration()))
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            self.set_chain_head(self.genesis_block)
            chain_head = self.genesis_block

        self.block_publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_cache,
            state_view_factory=self.state_view_factory,
            settings_cache=SettingsCache(
                SettingsViewFactory(self.state_view_factory),
            ),
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            squash_handler=None,
            chain_head=chain_head,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            check_publish_block_frequency=0.1,
            batch_observers=[])
    def __init__(self, with_genesis=True):
        self.block_sender = MockBlockSender()
        self.batch_sender = MockBatchSender()
        self.block_store = BlockStore(DictDatabase(
            indexes=BlockStore.create_index_configuration()))
        self.block_cache = BlockCache(self.block_store)
        self.state_db = {}

        # add the mock reference to the consensus
        consensus_setting_addr = SettingsView.setting_address(
            'sawtooth.consensus.algorithm')
        self.state_db[consensus_setting_addr] = _setting_entry(
            'sawtooth.consensus.algorithm', 'test_journal.mock_consensus')

        self.state_view_factory = MockStateViewFactory(self.state_db)
        context = create_context('secp256k1')
        private_key = context.new_random_private_key()
        crypto_factory = CryptoFactory(context)
        self.signer = crypto_factory.new_signer(private_key)

        identity_private_key = context.new_random_private_key()
        self.identity_signer = crypto_factory.new_signer(identity_private_key)
        chain_head = None
        if with_genesis:
            self.genesis_block = self.generate_genesis_block()
            self.set_chain_head(self.genesis_block)
            chain_head = self.genesis_block

        self.block_publisher = BlockPublisher(
            transaction_executor=MockTransactionExecutor(),
            block_cache=self.block_cache,
            state_view_factory=self.state_view_factory,
            settings_cache=SettingsCache(
                SettingsViewFactory(self.state_view_factory),
            ),
            block_sender=self.block_sender,
            batch_sender=self.block_sender,
            squash_handler=None,
            chain_head=chain_head,
            identity_signer=self.identity_signer,
            data_dir=None,
            config_dir=None,
            permission_verifier=MockPermissionVerifier(),
            check_publish_block_frequency=0.1,
            batch_observers=[])
Example #21
0
    def initialize_block(self, block_header):
        """Do initialization necessary for the consensus to claim a block,
        this may include initiating voting activates, starting proof of work
        hash generation, or create a PoET wait timer.

        Args:
            block_header (BlockHeader): the BlockHeader to initialize.
        Returns:
            True
        """

        # Using the current chain head, we need to create a state view so we
        # can get our config values.
        state_view = BlockWrapper.state_view_for_block(
            self._block_cache.block_store.chain_head, self._state_view_factory)

        self._start_time = time.time()

        settings_view = SettingsView(state_view)
        self._expected_block_interval = settings_view.get_setting(
            "sawtooth.consensus.pow.seconds_between_blocks",
            self._expected_block_interval, int)
        self._difficulty_adjustment_block_count = settings_view.get_setting(
            "sawtooth.consensus.pow.difficulty_adjustment_block_count",
            self._difficulty_adjustment_block_count, int)
        self._difficulty_tuning_block_count = settings_view.get_setting(
            "sawtooth.consensus.pow.difficulty_tuning_block_count",
            self._difficulty_tuning_block_count, int)
        self._valid_block_publishers = settings_view.get_setting(
            "sawtooth.consensus.valid_block_publishers",
            self._valid_block_publishers, list)

        prev_block = self._block_cache[block_header.previous_block_id]
        prev_consensus = prev_block.consensus.split(GLUE)

        if prev_consensus[IDX_POW] != POW:
            difficulty = INITIAL_DIFFICULTY
        else:
            difficulty = self._get_adjusted_difficulty(prev_block,
                                                       prev_consensus,
                                                       self._start_time)

        SOLVER._comm.send([
            self._start_time, difficulty,
            block_header.previous_block_id.encode(),
            block_header.signer_public_key.encode()
        ])
        LOGGER.info('New block using Gluwa PoW consensus')

        return True
Example #22
0
    def start(self, on_done):
        """
        Starts the genesis block creation process.  Will call the given
        `on_done` callback on successful completion.

        Args:
            on_done (function): a function called on completion

        Raises:
            InvalidGenesisStateError: raises this error if a genesis block is
                unable to be produced, or the resulting block-chain-id saved.
        """
        genesis_file = os.path.join(self._data_dir, 'genesis.batch')
        try:
            with open(genesis_file, 'rb') as batch_file:
                genesis_data = genesis_pb2.GenesisData()
                genesis_data.ParseFromString(batch_file.read())
            LOGGER.info('Producing genesis block from %s', genesis_file)
        except IOError:
            raise InvalidGenesisStateError(
                "Genesis File {} specified, but unreadable".format(
                    genesis_file))

        initial_state_root = self._context_manager.get_first_root()

        genesis_batches = [batch for batch in genesis_data.batches]
        if genesis_batches:
            scheduler = SerialScheduler(
                self._context_manager.get_squash_handler(),
                initial_state_root,
                always_persist=True)

            LOGGER.debug('Adding %s batches', len(genesis_data.batches))
            for batch in genesis_data.batches:
                scheduler.add_batch(batch)

            self._transaction_executor.execute(scheduler)

            scheduler.finalize()
            scheduler.complete(block=True)

        txn_receipts = []
        state_hash = initial_state_root
        for batch in genesis_batches:
            result = scheduler.get_batch_execution_result(
                batch.header_signature)
            if result is None or not result.is_valid:
                raise InvalidGenesisStateError(
                    'Unable to create genesis block, due to batch {}'.format(
                        batch.header_signature))
            if result.state_hash is not None:
                state_hash = result.state_hash

            txn_results = scheduler.get_transaction_execution_results(
                batch.header_signature)
            txn_receipts += self._make_receipts(txn_results)

        settings_view = SettingsView(
            self._state_view_factory.create_view(state_hash))
        name = settings_view.get_setting('sawtooth.consensus.algorithm.name')
        version = settings_view.get_setting(
            'sawtooth.consensus.algorithm.version')
        if name is None or version is None:
            raise LocalConfigurationError(
                'Unable to start validator; sawtooth.consensus.algorithm.name '
                'and sawtooth.consensus.algorithm.version must be set in the '
                'genesis block.')

        LOGGER.debug('Produced state hash %s for genesis block.', state_hash)

        block_builder = self._generate_genesis_block()
        block_builder.add_batches(genesis_batches)
        block_builder.set_state_hash(state_hash)

        block_publisher = self._get_block_publisher(initial_state_root)
        if not block_publisher.initialize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to initialize consensus block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to initialize genesis block.')

        if not block_publisher.finalize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to finalize genesis block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to finalize genesis block.')

        self._sign_block(block_builder)

        block = block_builder.build_block()

        blkw = BlockWrapper(block=block)

        LOGGER.info('Genesis block created: %s', blkw)

        self._block_manager.put([blkw.block])
        self._block_manager.persist(blkw.identifier, "commit_store")

        self._txn_receipt_store.chain_update(block, txn_receipts)
        self._chain_id_manager.save_block_chain_id(block.header_signature)

        LOGGER.debug('Deleting genesis data.')
        os.remove(genesis_file)

        if on_done is not None:
            on_done()
Example #23
0
    def _build_candidate_block(self, chain_head):
        """ Build a candidate block and construct the consensus object to
        validate it.
        :param chain_head: The block to build on top of.
        :return: (BlockBuilder) - The candidate block in a BlockBuilder
        wrapper.
        """
        state_view = BlockWrapper.state_view_for_block(
            chain_head, self._state_view_factory)
        consensus_module = ConsensusFactory.get_configured_consensus_module(
            chain_head.header_signature, state_view)

        # using chain_head so so we can use the setting_cache
        max_batches = int(
            self._settings_cache.get_setting(
                'sawtooth.publisher.max_batches_per_block',
                chain_head.state_root_hash,
                default_value=0))

        public_key = self._identity_signer.get_public_key().as_hex()
        consensus = consensus_module.\
            BlockPublisher(block_cache=self._block_cache,
                           state_view_factory=self._state_view_factory,
                           batch_publisher=self._batch_publisher,
                           data_dir=self._data_dir,
                           config_dir=self._config_dir,
                           validator_id=public_key)

        batch_injectors = []
        if self._batch_injector_factory is not None:
            batch_injectors = self._batch_injector_factory.create_injectors(
                chain_head.identifier)
            if batch_injectors:
                LOGGER.debug("Loaded batch injectors: %s", batch_injectors)

        block_header = BlockHeader(
            block_num=chain_head.block_num + 1,
            previous_block_id=chain_head.header_signature,
            signer_public_key=public_key)
        block_builder = BlockBuilder(block_header)

        if not consensus.initialize_block(block_builder.block_header):
            if not self._logging_states.consensus_not_ready:
                self._logging_states.consensus_not_ready = True
                LOGGER.debug("Consensus not ready to build candidate block.")
            return None

        if self._logging_states.consensus_not_ready:
            self._logging_states.consensus_not_ready = False
            LOGGER.debug("Consensus is ready to build candidate block.")

        # create a new scheduler
        scheduler = self._transaction_executor.create_scheduler(
            self._squash_handler, chain_head.state_root_hash)

        # build the TransactionCommitCache
        committed_txn_cache = TransactionCommitCache(
            self._block_cache.block_store)

        self._transaction_executor.execute(scheduler)
        self._candidate_block = _CandidateBlock(
            self._block_cache.block_store, consensus, scheduler,
            committed_txn_cache, block_builder, max_batches, batch_injectors,
            SettingsView(state_view), public_key)

        for batch in self._pending_batches:
            if self._candidate_block.can_add_batch:
                self._candidate_block.add_batch(batch)
            else:
                break
Example #24
0
    def _register_signup_information(self, block_header, poet_enclave_module):
        # Create signup information for this validator, putting the block ID
        # of the block previous to the block referenced by block_header in the
        # nonce.  Block ID is better than wait certificate ID for testing
        # freshness as we need to account for non-PoET blocks.
        public_key_hash = \
            hashlib.sha256(
                block_header.signer_pubkey.encode()).hexdigest()
        nonce = SignupInfo.block_id_to_nonce(block_header.previous_block_id)
        signup_info = \
            SignupInfo.create_signup_info(
                poet_enclave_module=poet_enclave_module,
                originator_public_key_hash=public_key_hash,
                nonce=nonce)

        # Create the validator registry payload
        payload = \
            vr_pb.ValidatorRegistryPayload(
                verb='register',
                name='validator-{}'.format(block_header.signer_pubkey[:8]),
                id=block_header.signer_pubkey,
                signup_info=vr_pb.SignUpInfo(
                    poet_public_key=signup_info.poet_public_key,
                    proof_data=signup_info.proof_data,
                    anti_sybil_id=signup_info.anti_sybil_id,
                    nonce=nonce),
            )
        serialized = payload.SerializeToString()

        # Create the address that will be used to look up this validator
        # registry transaction.  Seems like a potential for refactoring..
        validator_entry_address = \
            PoetBlockPublisher._validator_registry_namespace + \
            hashlib.sha256(block_header.signer_pubkey.encode()).hexdigest()

        # Create a transaction header and transaction for the validator
        # registry update amd then hand it off to the batch publisher to
        # send out.
        output_addresses = \
            [validator_entry_address,
             PoetBlockPublisher._validator_map_address]
        input_addresses = \
            output_addresses + \
            [SettingsView.setting_address(
                'sawtooth.poet.report_public_key_pem'),
             SettingsView.setting_address(
                 'sawtooth.poet.valid_enclave_measurements'),
             SettingsView.setting_address(
                 'sawtooth.poet.valid_enclave_basenames')]

        header = \
            txn_pb.TransactionHeader(
                signer_pubkey=block_header.signer_pubkey,
                family_name='sawtooth_validator_registry',
                family_version='1.0',
                inputs=input_addresses,
                outputs=output_addresses,
                dependencies=[],
                payload_sha512=hashlib.sha512(serialized).hexdigest(),
                batcher_pubkey=block_header.signer_pubkey,
                nonce=time.time().hex().encode()).SerializeToString()
        signature = \
            signing.sign(header, self._batch_publisher.identity_signing_key)

        transaction = \
            txn_pb.Transaction(
                header=header,
                payload=serialized,
                header_signature=signature)

        LOGGER.info(
            'Register Validator Name=%s, ID=%s...%s, PoET public key=%s...%s, '
            'Nonce=%s',
            payload.name,
            payload.id[:8],
            payload.id[-8:],
            payload.signup_info.poet_public_key[:8],
            payload.signup_info.poet_public_key[-8:],
            nonce)

        self._batch_publisher.send([transaction])

        # Store the key state so that we can look it up later if need be and
        # set the new key as our active key
        LOGGER.info(
            'Save key state PPK=%s...%s => SSD=%s...%s',
            signup_info.poet_public_key[:8],
            signup_info.poet_public_key[-8:],
            signup_info.sealed_signup_data[:8],
            signup_info.sealed_signup_data[-8:])
        self._poet_key_state_store[signup_info.poet_public_key] = \
            PoetKeyState(
                sealed_signup_data=signup_info.sealed_signup_data,
                has_been_refreshed=False)
        self._poet_key_state_store.active_key = signup_info.poet_public_key
Example #25
0
def do_create(args):
    """Executes the `poet registration` subcommand.

    This command generates a validator registry transaction and saves it to a
    file, whose location is determined by the args.  The signup data, generated
    by the selected enclave, is also stored in a well-known location.
    """
    signer = _read_signer(args.key)
    public_key = signer.get_public_key().as_hex()

    public_key_hash = sha256(public_key.encode()).hexdigest()

    with PoetEnclaveModuleWrapper(
            enclave_module=args.enclave_module,
            config_dir=config.get_config_dir(),
            data_dir=config.get_data_dir()) as poet_enclave_module:
        signup_info = SignupInfo.create_signup_info(
            poet_enclave_module=poet_enclave_module,
            originator_public_key_hash=public_key_hash,
            nonce=SignupInfo.block_id_to_nonce(args.block))

    print('Writing key state for PoET public key: {}...{}'.format(
        signup_info.poet_public_key[:8], signup_info.poet_public_key[-8:]))

    # Store the newly-created PoET key state, associating it with its
    # corresponding public key
    poet_key_state_store = \
        PoetKeyStateStore(
            data_dir=config.get_data_dir(),
            validator_id=public_key)
    poet_key_state_store[signup_info.poet_public_key] = \
        PoetKeyState(
            sealed_signup_data=signup_info.sealed_signup_data,
            has_been_refreshed=False)

    # Create the validator registry payload
    payload = \
        vr_pb.ValidatorRegistryPayload(
            verb='register',
            name='validator-{}'.format(public_key[:8]),
            id=public_key,
            signup_info=vr_pb.SignUpInfo(
                poet_public_key=signup_info.poet_public_key,
                proof_data=signup_info.proof_data,
                anti_sybil_id=signup_info.anti_sybil_id,
                nonce=SignupInfo.block_id_to_nonce(args.block)))
    serialized = payload.SerializeToString()

    # Create the address that will be used to look up this validator
    # registry transaction.  Seems like a potential for refactoring..
    validator_entry_address = \
        VR_NAMESPACE + sha256(public_key.encode()).hexdigest()

    # Create a transaction header and transaction for the validator
    # registry update amd then hand it off to the batch publisher to
    # send out.
    output_addresses = [validator_entry_address, VALIDATOR_MAP_ADDRESS]
    input_addresses = \
        output_addresses + \
        [SettingsView.setting_address('sawtooth.poet.report_public_key_pem'),
         SettingsView.setting_address('sawtooth.poet.'
                                      'valid_enclave_measurements'),
         SettingsView.setting_address('sawtooth.poet.valid_enclave_basenames')]

    header = \
        txn_pb.TransactionHeader(
            signer_public_key=public_key,
            family_name='sawtooth_validator_registry',
            family_version='1.0',
            inputs=input_addresses,
            outputs=output_addresses,
            dependencies=[],
            payload_sha512=sha512(serialized).hexdigest(),
            batcher_public_key=public_key,
            nonce=time.time().hex().encode()).SerializeToString()
    signature = signer.sign(header)

    transaction = \
        txn_pb.Transaction(
            header=header,
            payload=serialized,
            header_signature=signature)

    batch = _create_batch(signer, [transaction])
    batch_list = batch_pb.BatchList(batches=[batch])
    try:
        print('Generating {}'.format(args.output))
        with open(args.output, 'wb') as batch_file:
            batch_file.write(batch_list.SerializeToString())
    except IOError as e:
        raise CliException('Unable to write to batch file: {}'.format(str(e)))
    def _register_signup_information(self, block_header, poet_enclave_module):
        # Create signup information for this validator, putting the block ID
        # of the block previous to the block referenced by block_header in the
        # nonce.  Block ID is better than wait certificate ID for testing
        # freshness as we need to account for non-PoET blocks.
        public_key_hash = \
            hashlib.sha256(
                block_header.signer_public_key.encode()).hexdigest()
        nonce = SignupInfo.block_id_to_nonce(block_header.previous_block_id)
        signup_info = \
            SignupInfo.create_signup_info(
                poet_enclave_module=poet_enclave_module,
                originator_public_key_hash=public_key_hash,
                nonce=nonce)

        # Create the validator registry payload
        payload = \
            vr_pb.ValidatorRegistryPayload(
                verb='register',
                name='validator-{}'.format(block_header.signer_public_key[:8]),
                id=block_header.signer_public_key,
                signup_info=vr_pb.SignUpInfo(
                    poet_public_key=signup_info.poet_public_key,
                    proof_data=signup_info.proof_data,
                    anti_sybil_id=signup_info.anti_sybil_id,
                    nonce=nonce),
            )
        serialized = payload.SerializeToString()

        # Create the address that will be used to look up this validator
        # registry transaction.  Seems like a potential for refactoring..
        validator_entry_address = \
            PoetBlockPublisher._validator_registry_namespace + \
            hashlib.sha256(block_header.signer_public_key.encode()).hexdigest()

        # Create a transaction header and transaction for the validator
        # registry update amd then hand it off to the batch publisher to
        # send out.
        output_addresses = \
            [validator_entry_address,
             PoetBlockPublisher._validator_map_address]
        input_addresses = \
            output_addresses + \
            [SettingsView.setting_address(
                'sawtooth.poet.report_public_key_pem'),
             SettingsView.setting_address(
                 'sawtooth.poet.valid_enclave_measurements'),
             SettingsView.setting_address(
                 'sawtooth.poet.valid_enclave_basenames')]

        header = \
            txn_pb.TransactionHeader(
                signer_public_key=block_header.signer_public_key,
                family_name='sawtooth_validator_registry',
                family_version='1.0',
                inputs=input_addresses,
                outputs=output_addresses,
                dependencies=[],
                payload_sha512=hashlib.sha512(serialized).hexdigest(),
                batcher_public_key=block_header.signer_public_key,
                nonce=time.time().hex().encode()).SerializeToString()

        signature = self._batch_publisher.identity_signer.sign(header)

        transaction = \
            txn_pb.Transaction(
                header=header,
                payload=serialized,
                header_signature=signature)

        LOGGER.info(
            'Register Validator Name=%s, ID=%s...%s, PoET public key=%s...%s, '
            'Nonce=%s',
            payload.name,
            payload.id[:8],
            payload.id[-8:],
            payload.signup_info.poet_public_key[:8],
            payload.signup_info.poet_public_key[-8:],
            nonce)

        self._batch_publisher.send([transaction])

        # Store the key state so that we can look it up later if need be and
        # set the new key as our active key
        LOGGER.info(
            'Save key state PPK=%s...%s => SSD=%s...%s',
            signup_info.poet_public_key[:8],
            signup_info.poet_public_key[-8:],
            signup_info.sealed_signup_data[:8],
            signup_info.sealed_signup_data[-8:])
        self._poet_key_state_store[signup_info.poet_public_key] = \
            PoetKeyState(
                sealed_signup_data=signup_info.sealed_signup_data,
                has_been_refreshed=False,
                signup_nonce=nonce)
        self._poet_key_state_store.active_key = signup_info.poet_public_key
Example #27
0
    def start(self, on_done):
        """
        Starts the genesis block creation process.  Will call the given
        `on_done` callback on successful completion.

        Args:
            on_done (function): a function called on completion

        Raises:
            InvalidGenesisStateError: raises this error if a genesis block is
                unable to be produced, or the resulting block-chain-id saved.
        """
        genesis_file = os.path.join(self._data_dir, 'genesis.batch')
        try:
            with open(genesis_file, 'rb') as batch_file:
                genesis_data = genesis_pb2.GenesisData()
                genesis_data.ParseFromString(batch_file.read())
            LOGGER.info('Producing genesis block from %s', genesis_file)
        except IOError:
            raise InvalidGenesisStateError(
                "Genesis File {} specified, but unreadable".format(
                    genesis_file))

        initial_state_root = self._context_manager.get_first_root()

        genesis_batches = [batch for batch in genesis_data.batches]
        if genesis_batches:
            scheduler = SerialScheduler(
                self._context_manager.get_squash_handler(),
                initial_state_root,
                always_persist=True)

            LOGGER.debug('Adding %s batches', len(genesis_data.batches))
            for batch in genesis_data.batches:
                scheduler.add_batch(batch)

            self._transaction_executor.execute(scheduler)

            scheduler.finalize()
            scheduler.complete(block=True)

        txn_receipts = []
        state_hash = initial_state_root
        for batch in genesis_batches:
            result = scheduler.get_batch_execution_result(
                batch.header_signature)
            if result is None or not result.is_valid:
                raise InvalidGenesisStateError(
                    'Unable to create genesis block, due to batch {}'
                    .format(batch.header_signature))
            if result.state_hash is not None:
                state_hash = result.state_hash

            txn_results = scheduler.get_transaction_execution_results(
                batch.header_signature)
            txn_receipts += self._make_receipts(txn_results)

        settings_view = SettingsView(
            self._state_view_factory.create_view(state_hash))
        name = settings_view.get_setting('sawtooth.consensus.algorithm.name')
        version = settings_view.get_setting(
            'sawtooth.consensus.algorithm.version')
        if name is None or version is None:
            raise LocalConfigurationError(
                'Unable to start validator; sawtooth.consensus.algorithm.name '
                'and sawtooth.consensus.algorithm.version must be set in the '
                'genesis block.')

        LOGGER.debug('Produced state hash %s for genesis block.', state_hash)

        block_builder = self._generate_genesis_block()
        block_builder.add_batches(genesis_batches)
        block_builder.set_state_hash(state_hash)

        block_publisher = self._get_block_publisher(initial_state_root)
        if not block_publisher.initialize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to initialize consensus block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to initialize genesis block.')

        if not block_publisher.finalize_block(block_builder.block_header):
            LOGGER.error('Consensus refused to finalize genesis block.')
            raise InvalidGenesisConsensusError(
                'Consensus refused to finalize genesis block.')

        self._sign_block(block_builder)

        block = block_builder.build_block()

        blkw = BlockWrapper(block=block)

        LOGGER.info('Genesis block created: %s', blkw)

        self._completer.add_block(block)
        self._block_manager.put([blkw.block])
        self._block_manager.persist(blkw.identifier, "commit_store")

        self._txn_receipt_store.chain_update(block, txn_receipts)
        self._chain_id_manager.save_block_chain_id(block.header_signature)

        LOGGER.debug('Deleting genesis data.')
        os.remove(genesis_file)

        if on_done is not None:
            on_done()
Example #28
0
def do_create(args):
    """Executes the `poet registration` subcommand.

    This command generates a validator registry transaction and saves it to a
    file, whose location is determined by the args.  The signup data, generated
    by the selected enclave, is also stored in a well-known location.
    """
    signer = _read_signer(args.key)
    public_key = signer.get_public_key().as_hex()

    public_key_hash = sha256(public_key.encode()).hexdigest()
    nonce = SignupInfo.block_id_to_nonce(args.block)
    with PoetEnclaveModuleWrapper(
            enclave_module=args.enclave_module,
            config_dir=config.get_config_dir(),
            data_dir=config.get_data_dir()) as poet_enclave_module:
        signup_info = SignupInfo.create_signup_info(
            poet_enclave_module=poet_enclave_module,
            originator_public_key_hash=public_key_hash,
            nonce=nonce)

    print(
        'Writing key state for PoET public key: {}...{}'.format(
            signup_info.poet_public_key[:8],
            signup_info.poet_public_key[-8:]))

    # Store the newly-created PoET key state, associating it with its
    # corresponding public key
    poet_key_state_store = \
        PoetKeyStateStore(
            data_dir=config.get_data_dir(),
            validator_id=public_key)
    poet_key_state_store[signup_info.poet_public_key] = \
        PoetKeyState(
            sealed_signup_data=signup_info.sealed_signup_data,
            has_been_refreshed=False,
            signup_nonce=nonce)

    # Create the validator registry payload
    payload = \
        vr_pb.ValidatorRegistryPayload(
            verb='register',
            name='validator-{}'.format(public_key[:8]),
            id=public_key,
            signup_info=vr_pb.SignUpInfo(
                poet_public_key=signup_info.poet_public_key,
                proof_data=signup_info.proof_data,
                anti_sybil_id=signup_info.anti_sybil_id,
                nonce=SignupInfo.block_id_to_nonce(args.block)))
    serialized = payload.SerializeToString()

    # Create the address that will be used to look up this validator
    # registry transaction.  Seems like a potential for refactoring..
    validator_entry_address = \
        VR_NAMESPACE + sha256(public_key.encode()).hexdigest()

    # Create a transaction header and transaction for the validator
    # registry update amd then hand it off to the batch publisher to
    # send out.
    output_addresses = [validator_entry_address, VALIDATOR_MAP_ADDRESS]
    input_addresses = \
        output_addresses + \
        [SettingsView.setting_address('sawtooth.poet.report_public_key_pem'),
         SettingsView.setting_address('sawtooth.poet.'
                                      'valid_enclave_measurements'),
         SettingsView.setting_address('sawtooth.poet.valid_enclave_basenames')]

    header = \
        txn_pb.TransactionHeader(
            signer_public_key=public_key,
            family_name='sawtooth_validator_registry',
            family_version='1.0',
            inputs=input_addresses,
            outputs=output_addresses,
            dependencies=[],
            payload_sha512=sha512(serialized).hexdigest(),
            batcher_public_key=public_key,
            nonce=time.time().hex().encode()).SerializeToString()
    signature = signer.sign(header)

    transaction = \
        txn_pb.Transaction(
            header=header,
            payload=serialized,
            header_signature=signature)

    batch = _create_batch(signer, [transaction])
    batch_list = batch_pb.BatchList(batches=[batch])
    try:
        print('Generating {}'.format(args.output))
        with open(args.output, 'wb') as batch_file:
            batch_file.write(batch_list.SerializeToString())
    except IOError as e:
        raise CliException('Unable to write to batch file: {}'.format(str(e)))
class PoetSettingsView(object):
    """A class to wrap the retrieval of PoET configuration settings from the
    configuration view.  For values that are not in the current state view
    or that are invalid, default values are returned.
    """

    _BLOCK_CLAIM_DELAY_ = 1
    _ENCLAVE_MODULE_NAME_ = \
        'sawtooth_poet_simulator.poet_enclave_simulator.poet_enclave_simulator'
    _INITIAL_WAIT_TIME_ = 3000.0
    _KEY_BLOCK_CLAIM_LIMIT_ = 25
    _MINIMUM_WAIT_TIME_ = 1.0
    # pylint: disable=invalid-name
    _POPULATION_ESTIMATE_SAMPLE_SIZE_ = 50
    _SIGNUP_COMMIT_MAXIMUM_DELAY_ = 0
    _TARGET_WAIT_TIME_ = 20.0
    _ZTEST_MAXIMUM_WIN_DEVIATION_ = 3.075
    _ZTEST_MINIMUM_WIN_COUNT_ = 3

    def __init__(self, state_view):
        """Initialize a PoetSettingsView object.

        Args:
            state_view (StateView): The current state view.

        Returns:
            None
        """

        self._settings_view = SettingsView(state_view)

        self._block_claim_delay = None
        self._enclave_module_name = None
        self._initial_wait_time = None
        self._key_block_claim_limit = None
        self._minimum_wait_time = None
        self._population_estimate_sample_size = None
        self._target_wait_time = None
        self._signup_commit_maximum_delay = None
        self._ztest_maximum_win_deviation = None
        self._ztest_minimum_win_count = None

    def _get_config_setting(self,
                            name,
                            value_type,
                            default_value,
                            validate_function=None):
        """Retrieves a value from the config view, returning the default value
        if does not exist in the current state view or if the value is
        invalid.

        Args:
            name (str): The config setting to return.
            value_type (type): The value type, for example, int, float, etc.,
                of config value.
            default_value (object): The default value to be used if no value
                found or if value in config is invalid, for example, a
                non-integer value for an int config setting.
            validate_function (function): An optional function that can be
                applied to the setting to determine validity.  The function
                should return True if setting is valid, False otherwise.

        Returns:
            The value for the config setting.
        """

        try:
            value = \
                self._settings_view.get_setting(
                    key=name,
                    default_value=default_value,
                    value_type=value_type)

            if validate_function is not None:
                if not validate_function(value):
                    raise \
                        ValueError(
                            'Value ({}) for {} is not valid'.format(
                                value,
                                name))
        except ValueError:
            value = default_value

        return value

    @property
    def block_claim_delay(self):
        """Return the block claim delay if config setting exists and
        is valid, otherwise return the default.

        The block claim delay is the number of blocks after a validator's
        signup information is committed to the validator registry before
        it can claim a block.
        """
        if self._block_claim_delay is None:
            self._block_claim_delay = \
                self._get_config_setting(
                    name='sawtooth.poet.block_claim_delay',
                    value_type=int,
                    default_value=PoetSettingsView._BLOCK_CLAIM_DELAY_,
                    validate_function=lambda value: value >= 0)

        return self._block_claim_delay

    @property
    def enclave_module_name(self):
        """Return the enclave module name if config setting exists and is
        valid, otherwise return the default.

        The enclave module name is the name of the Python module containing the
        implementation of the underlying PoET enclave.
        """
        if self._enclave_module_name is None:
            self._enclave_module_name = \
                self._get_config_setting(
                    name='sawtooth.poet.enclave_module_name',
                    value_type=str,
                    default_value=PoetSettingsView._ENCLAVE_MODULE_NAME_,
                    # function should return true if value is nonempty
                    validate_function=lambda value: value)

        return self._enclave_module_name

    @property
    def initial_wait_time(self):
        """Return the initial wait time if config setting exists and is valid,
        otherwise return the default.

        The initial wait time is used during the bootstrapping of the block-
        chain to compute the local mean for wait timers until there are at
        least population_estimate_sample_size PoET blocks in the blockchain.
        """
        if self._initial_wait_time is None:
            self._initial_wait_time = \
                self._get_config_setting(
                    name='sawtooth.poet.initial_wait_time',
                    value_type=float,
                    default_value=PoetSettingsView._INITIAL_WAIT_TIME_,
                    validate_function=lambda value:
                        math.isfinite(value) and value >= 0)

        return self._initial_wait_time

    @property
    def key_block_claim_limit(self):
        """Return the key block claim limit if config setting exists and
        is valid, otherwise return the default.

        The key block claim limit is the maximum number of blocks that a
        validator may claim with a PoET key pair before it needs to refresh
        its signup information.
        """
        if self._key_block_claim_limit is None:
            self._key_block_claim_limit = \
                self._get_config_setting(
                    name='sawtooth.poet.key_block_claim_limit',
                    value_type=int,
                    default_value=PoetSettingsView._KEY_BLOCK_CLAIM_LIMIT_,
                    validate_function=lambda value: value > 0)

        return self._key_block_claim_limit

    @property
    def minimum_wait_time(self):
        """Return the minimum wait time if config setting exists and is valid,
        otherwise return the default.

        The minimum wait time is used as a lower bound for the minimum amount
        of time a validator must want before attempting to claim a block.
        """
        if self._minimum_wait_time is None:
            self._minimum_wait_time = \
                self._get_config_setting(
                    name='sawtooth.poet.minimum_wait_time',
                    value_type=float,
                    default_value=PoetSettingsView._MINIMUM_WAIT_TIME_,
                    validate_function=lambda value:
                        math.isfinite(value) and value > 0)

        return self._minimum_wait_time

    @property
    def population_estimate_sample_size(self):
        """Return the population estimate sample size if config setting exists
        and is valid, otherwise return the default.

        The population estimate sample size is the number of most-recent blocks
        that will be used when estimating the population size after the block-
        chain has been bootstrapped (i.e., at least
        population_estimate_sample_size blocks have been added to the
        blockchain) and subsequently used to compute the local mean for a new
        wait timer.

        Until population_estimate_sample_size blocks are in the
        blockchain, the local mean computed for a wait timer is based upon the
        ratio of the target and initial wait times.
        """
        if self._population_estimate_sample_size is None:
            self._population_estimate_sample_size = \
                self._get_config_setting(
                    name='sawtooth.poet.population_estimate_sample_size',
                    value_type=int,
                    default_value=PoetSettingsView.
                    _POPULATION_ESTIMATE_SAMPLE_SIZE_,
                    validate_function=lambda value: value > 0)

        return self._population_estimate_sample_size

    @property
    def signup_commit_maximum_delay(self):
        """Return the signup commit maximum delay if config setting exists and
        is valid, otherwise return the default.

        The signup commit maximum delay is the maximum allowed number of blocks
        between the head of the block chain when the signup information was
        created and subsequent validator registry transaction was submitted and
        when said transaction was committed to the blockchain.  For example, if
        the signup commit maximum delay is one and the signup information's
        containing validator registry transaction was created/submitted when
        the blockchain head was block number 100, then the validator registry
        transaction must have been committed either in block 101 (i.e., zero
        blocks between 100 and 101) or block 102 (i.e., one block between 100
        and 102).
        """
        if self._signup_commit_maximum_delay is None:
            self._signup_commit_maximum_delay = \
                self._get_config_setting(
                    name='sawtooth.poet.signup_commit_maximum_delay',
                    value_type=int,
                    default_value=PoetSettingsView.
                    _SIGNUP_COMMIT_MAXIMUM_DELAY_,
                    validate_function=lambda value: value >= 0)

        return self._signup_commit_maximum_delay

    @property
    def target_wait_time(self):
        """Return the target wait time if config setting exists and is valid,
        otherwise return the default.

        The target wait time is the desired average amount of time, across all
        validators in the network, a validator must wait before attempting to
        claim a block.
        """
        if self._target_wait_time is None:
            self._target_wait_time = \
                self._get_config_setting(
                    name='sawtooth.poet.target_wait_time',
                    value_type=float,
                    default_value=PoetSettingsView._TARGET_WAIT_TIME_,
                    validate_function=lambda value:
                        math.isfinite(value) and value > 0)

        return self._target_wait_time

    @property
    def ztest_maximum_win_deviation(self):
        """Return the zTest maximum win deviation if config setting exists and
        is valid, otherwise return the default.

        The zTest maximum win deviation specifies the maximum allowed
        deviation from the expected win frequency for a particular validator
        before the zTest will fail and the claimed block will be rejected.
        The deviation corresponds to a confidence interval (i.e., how
        confident we are that we have truly detected a validator winning at
        a frequency we consider too frequent):

        3.075 ==> 99.9%
        2.575 ==> 99.5%
        2.321 ==> 99%
        1.645 ==> 95%
        """
        if self._ztest_maximum_win_deviation is None:
            self._ztest_maximum_win_deviation = \
                self._get_config_setting(
                    name='sawtooth.poet.ztest_maximum_win_deviation',
                    value_type=float,
                    default_value=PoetSettingsView.
                    _ZTEST_MAXIMUM_WIN_DEVIATION_,
                    validate_function=lambda value:
                        math.isfinite(value) and value > 0)

        return self._ztest_maximum_win_deviation

    @property
    def ztest_minimum_win_count(self):
        """Return the zTest minimum win count if config setting exists and is
        valid, otherwise return the default.

        The zTest minimum win count is the number of blocks a validator
        must have successfully claimed (once there are at least
        population_estimate_sample_size PoET blocks in the blockchain) before
        the zTest will be applied to the validator's attempt to claim further
        blocks.
        """
        if self._ztest_minimum_win_count is None:
            self._ztest_minimum_win_count = \
                self._get_config_setting(
                    name='sawtooth.poet.ztest_minimum_win_count',
                    value_type=int,
                    default_value=PoetSettingsView._ZTEST_MINIMUM_WIN_COUNT_,
                    validate_function=lambda value: value >= 0)

        return self._ztest_minimum_win_count