def setUp(self): context = create_context('secp256k1') crypto_factory = CryptoFactory(context) private_key = context.new_random_private_key() self.signer = crypto_factory.new_signer(private_key) self._identity_view_factory = MockIdentityViewFactory() self.permissions = {} self._identity_cache = IdentityCache( self._identity_view_factory) self.permission_verifier = \ PermissionVerifier( permissions=self.permissions, current_root_func=self._current_root_func, identity_cache=self._identity_cache)
class TestPermissionVerifier(unittest.TestCase): def setUp(self): context = create_context('secp256k1') crypto_factory = CryptoFactory(context) private_key = context.new_random_private_key() self.signer = crypto_factory.new_signer(private_key) self._identity_view_factory = MockIdentityViewFactory() self.permissions = {} self._identity_cache = IdentityCache( self._identity_view_factory) self.permission_verifier = \ PermissionVerifier( permissions=self.permissions, current_root_func=self._current_root_func, identity_cache=self._identity_cache) @property def public_key(self): return self.signer.get_public_key().as_hex() def _current_root_func(self): return "0000000000000000000000" def _create_transactions(self, count): txn_list = [] for _ in range(count): payload = { 'Verb': 'set', 'Name': 'name', 'Value': 1, } intkey_prefix = \ hashlib.sha512('intkey'.encode('utf-8')).hexdigest()[0:6] addr = intkey_prefix + \ hashlib.sha512(payload["Name"].encode('utf-8')).hexdigest() payload_encode = hashlib.sha512(cbor.dumps(payload)).hexdigest() header = TransactionHeader( signer_public_key=self.public_key, family_name='intkey', family_version='1.0', inputs=[addr], outputs=[addr], dependencies=[], payload_sha512=payload_encode) header.batcher_public_key = self.public_key header_bytes = header.SerializeToString() signature = self.signer.sign(header_bytes) transaction = Transaction( header=header_bytes, payload=cbor.dumps(payload), header_signature=signature) txn_list.append(transaction) return txn_list def _create_batches(self, batch_count, txn_count): batch_list = [] for _ in range(batch_count): txn_list = self._create_transactions(txn_count) txn_sig_list = [txn.header_signature for txn in txn_list] batch_header = BatchHeader( signer_public_key=self.signer.get_public_key().as_hex()) batch_header.transaction_ids.extend(txn_sig_list) header_bytes = batch_header.SerializeToString() signature = self.signer.sign(header_bytes) batch = Batch( header=header_bytes, transactions=txn_list, header_signature=signature) batch_list.append(batch) return batch_list def test_permission(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) def test_default_policy_permission(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Batch should be allowed. 2. Set default policy to deny all. Batch should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_role(self): """ Test that role:"transactor" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role("transactor", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_batch_signer(self): """ Test that role: "transactor.batch_signer" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role("transactor.batch_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor.batch_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_transaction_signer(self): """ Test that role: "transactor.transaction_signer" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role("transactor.transaction_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor.transaction_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_transaction_siger_transaction_family(self): """ Test that role: "transactor.transaction_signer.intkey" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role( "transactor.transaction_signer.intkey", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "transactor.transaction_signer.intkey", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_off_chain_permissions(self): """ Test that if permissions are empty all signers are permitted. """ batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) def test_off_chain_transactor(self): """ Test that role:"transactor" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_batch_signer(self): """ Test that role:"transactor.batch_signer" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.batch_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.batch_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_transaction_signer(self): """ Test that role:"transactor.transaction_signer" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.transaction_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.transaction_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_transaction_signer_family(self): """ Test that role:"transactor.transaction_signer.intkey" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.transaction_signer.intkey"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.transaction_signer.intkey"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_network(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) def test_network_default(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Public key should be allowed. 2. Set default policy to deny all. Public key should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) allowed = self.permission_verifier.check_network_role(self.public_key) self.assertFalse(allowed) def test_network_role(self): """ Test that role:"network" is checked properly. 1. Set policy to permit signing key. Public key should be allowed. 2. Set policy to permit some other key. Public key should be rejected. """ self._identity_view_factory.add_policy( "policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role( "network", "policy1") allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy2", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "network", "policy2") allowed = self.permission_verifier.check_network_role(self.public_key) self.assertFalse(allowed) def test_network_consensus(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) def test_network_consensus_default(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Public key should be allowed. 2. Set default policy to deny all. Public key should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertFalse(allowed) def test_network_consensus_role(self): """ Test that role:"network.consensus" is checked properly. 1. Set policy to permit signing key. Public key should be allowed. 2. Set policy to permit some other key. Public key should be rejected. """ self._identity_view_factory.add_policy( "policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role( "network.consensus", "policy1") allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy2", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "network.consensus", "policy2") allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertFalse(allowed)
def __init__(self, bind_network, bind_component, endpoint, peering, seeds_list, peer_list, data_dir, config_dir, identity_signer, scheduler_type, permissions, minimum_peer_connectivity, maximum_peer_connectivity, network_public_key=None, network_private_key=None, roles=None, metrics_registry=None): """Constructs a validator instance. Args: bind_network (str): the network endpoint bind_component (str): the component endpoint endpoint (str): the zmq-style URI of this validator's publically reachable endpoint peering (str): The type of peering approach. Either 'static' or 'dynamic'. In 'static' mode, no attempted topology buildout occurs -- the validator only attempts to initiate peering connections with endpoints specified in the peer_list. In 'dynamic' mode, the validator will first attempt to initiate peering connections with endpoints specified in the peer_list and then attempt to do a topology buildout starting with peer lists obtained from endpoints in the seeds_list. In either mode, the validator will accept incoming peer requests up to max_peers. seeds_list (list of str): a list of addresses to connect to in order to perform the initial topology buildout peer_list (list of str): a list of peer addresses data_dir (str): path to the data directory config_dir (str): path to the config directory identity_signer (str): cryptographic signer the validator uses for signing """ # -- Setup Global State Database and Factory -- # global_state_db_filename = os.path.join( data_dir, 'merkle-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug( 'global state database file is %s', global_state_db_filename) global_state_db = LMDBNoLockDatabase(global_state_db_filename, 'c') state_view_factory = StateViewFactory(global_state_db) # -- Setup Receipt Store -- # receipt_db_filename = os.path.join( data_dir, 'txn_receipts-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug('txn receipt store file is %s', receipt_db_filename) receipt_db = LMDBNoLockDatabase(receipt_db_filename, 'c') receipt_store = TransactionReceiptStore(receipt_db) # -- Setup Block Store -- # block_db_filename = os.path.join( data_dir, 'block-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug('block store file is %s', block_db_filename) block_db = IndexedDatabase( block_db_filename, BlockStore.serialize_block, BlockStore.deserialize_block, flag='c', indexes=BlockStore.create_index_configuration()) block_store = BlockStore(block_db) block_cache = BlockCache( block_store, keep_time=300, purge_frequency=30) # -- Setup Thread Pools -- # component_thread_pool = InstrumentedThreadPoolExecutor( max_workers=10, name='Component', metrics_registry=metrics_registry) network_thread_pool = InstrumentedThreadPoolExecutor( max_workers=10, name='Network', metrics_registry=metrics_registry) client_thread_pool = InstrumentedThreadPoolExecutor( max_workers=5, name='Client', metrics_registry=metrics_registry) sig_pool = InstrumentedThreadPoolExecutor( max_workers=3, name='Signature', metrics_registry=metrics_registry) # -- Setup Dispatchers -- # component_dispatcher = Dispatcher(metrics_registry=metrics_registry) network_dispatcher = Dispatcher(metrics_registry=metrics_registry) # -- Setup Services -- # component_service = Interconnect( bind_component, component_dispatcher, secured=False, heartbeat=False, max_incoming_connections=20, monitor=True, max_future_callback_workers=10, metrics_registry=metrics_registry) zmq_identity = hashlib.sha512( time.time().hex().encode()).hexdigest()[:23] secure = False if network_public_key is not None and network_private_key is not None: secure = True network_service = Interconnect( bind_network, dispatcher=network_dispatcher, zmq_identity=zmq_identity, secured=secure, server_public_key=network_public_key, server_private_key=network_private_key, heartbeat=True, public_endpoint=endpoint, connection_timeout=120, max_incoming_connections=100, max_future_callback_workers=10, authorize=True, signer=identity_signer, roles=roles, metrics_registry=metrics_registry) # -- Setup Transaction Execution Platform -- # context_manager = ContextManager(global_state_db) batch_tracker = BatchTracker(block_store) settings_cache = SettingsCache( SettingsViewFactory(state_view_factory), ) transaction_executor = TransactionExecutor( service=component_service, context_manager=context_manager, settings_view_factory=SettingsViewFactory(state_view_factory), scheduler_type=scheduler_type, invalid_observers=[batch_tracker], metrics_registry=metrics_registry) component_service.set_check_connections( transaction_executor.check_connections) event_broadcaster = EventBroadcaster( component_service, block_store, receipt_store) # -- Setup P2P Networking -- # gossip = Gossip( network_service, settings_cache, lambda: block_store.chain_head, block_store.chain_head_state_root, endpoint=endpoint, peering_mode=peering, initial_seed_endpoints=seeds_list, initial_peer_endpoints=peer_list, minimum_peer_connectivity=minimum_peer_connectivity, maximum_peer_connectivity=maximum_peer_connectivity, topology_check_frequency=1 ) completer = Completer( block_store, gossip, metrics_registry=metrics_registry) block_sender = BroadcastBlockSender(completer, gossip) batch_sender = BroadcastBatchSender(completer, gossip) chain_id_manager = ChainIdManager(data_dir) identity_view_factory = IdentityViewFactory( StateViewFactory(global_state_db)) id_cache = IdentityCache(identity_view_factory) # -- Setup Permissioning -- # permission_verifier = PermissionVerifier( permissions, block_store.chain_head_state_root, id_cache) identity_observer = IdentityObserver( to_update=id_cache.invalidate, forked=id_cache.forked) settings_observer = SettingsObserver( to_update=settings_cache.invalidate, forked=settings_cache.forked) # -- Setup Journal -- # batch_injector_factory = DefaultBatchInjectorFactory( block_store=block_store, state_view_factory=state_view_factory, signer=identity_signer) block_publisher = BlockPublisher( transaction_executor=transaction_executor, block_cache=block_cache, state_view_factory=state_view_factory, settings_cache=settings_cache, block_sender=block_sender, batch_sender=batch_sender, squash_handler=context_manager.get_squash_handler(), chain_head=block_store.chain_head, identity_signer=identity_signer, data_dir=data_dir, config_dir=config_dir, permission_verifier=permission_verifier, check_publish_block_frequency=0.1, batch_observers=[batch_tracker], batch_injector_factory=batch_injector_factory, metrics_registry=metrics_registry) block_validator = BlockValidator( block_cache=block_cache, state_view_factory=state_view_factory, transaction_executor=transaction_executor, squash_handler=context_manager.get_squash_handler(), identity_signer=identity_signer, data_dir=data_dir, config_dir=config_dir, permission_verifier=permission_verifier, metrics_registry=metrics_registry) chain_controller = ChainController( block_cache=block_cache, block_validator=block_validator, state_view_factory=state_view_factory, chain_head_lock=block_publisher.chain_head_lock, on_chain_updated=block_publisher.on_chain_updated, chain_id_manager=chain_id_manager, data_dir=data_dir, config_dir=config_dir, chain_observers=[ event_broadcaster, receipt_store, batch_tracker, identity_observer, settings_observer ], metrics_registry=metrics_registry) genesis_controller = GenesisController( context_manager=context_manager, transaction_executor=transaction_executor, completer=completer, block_store=block_store, state_view_factory=state_view_factory, identity_signer=identity_signer, data_dir=data_dir, config_dir=config_dir, chain_id_manager=chain_id_manager, batch_sender=batch_sender) responder = Responder(completer) completer.set_on_batch_received(block_publisher.queue_batch) completer.set_on_block_received(chain_controller.queue_block) completer.set_chain_has_block(chain_controller.has_block) # -- Register Message Handler -- # network_handlers.add( network_dispatcher, network_service, gossip, completer, responder, network_thread_pool, sig_pool, chain_controller.has_block, block_publisher.has_batch, permission_verifier, block_publisher, metrics_registry) component_handlers.add( component_dispatcher, gossip, context_manager, transaction_executor, completer, block_store, batch_tracker, global_state_db, self.get_chain_head_state_root_hash, receipt_store, event_broadcaster, permission_verifier, component_thread_pool, client_thread_pool, sig_pool, block_publisher, metrics_registry) # -- Store Object References -- # self._component_dispatcher = component_dispatcher self._component_service = component_service self._component_thread_pool = component_thread_pool self._network_dispatcher = network_dispatcher self._network_service = network_service self._network_thread_pool = network_thread_pool self._client_thread_pool = client_thread_pool self._sig_pool = sig_pool self._context_manager = context_manager self._transaction_executor = transaction_executor self._genesis_controller = genesis_controller self._gossip = gossip self._block_publisher = block_publisher self._chain_controller = chain_controller self._block_validator = block_validator
def __init__(self, bind_network, bind_component, endpoint, peering, seeds_list, peer_list, data_dir, config_dir, identity_signing_key, scheduler_type, permissions, network_public_key=None, network_private_key=None, ): """Constructs a validator instance. Args: bind_network (str): the network endpoint bind_component (str): the component endpoint endpoint (str): the zmq-style URI of this validator's publically reachable endpoint peering (str): The type of peering approach. Either 'static' or 'dynamic'. In 'static' mode, no attempted topology buildout occurs -- the validator only attempts to initiate peering connections with endpoints specified in the peer_list. In 'dynamic' mode, the validator will first attempt to initiate peering connections with endpoints specified in the peer_list and then attempt to do a topology buildout starting with peer lists obtained from endpoints in the seeds_list. In either mode, the validator will accept incoming peer requests up to max_peers. seeds_list (list of str): a list of addresses to connect to in order to perform the initial topology buildout peer_list (list of str): a list of peer addresses data_dir (str): path to the data directory config_dir (str): path to the config directory identity_signing_key (str): key validator uses for signing """ db_filename = os.path.join(data_dir, 'merkle-{}.lmdb'.format( bind_network[-2:])) LOGGER.debug('database file is %s', db_filename) merkle_db = LMDBNoLockDatabase(db_filename, 'c') delta_db_filename = os.path.join(data_dir, 'state-deltas-{}.lmdb'.format( bind_network[-2:])) LOGGER.debug('state delta store file is %s', delta_db_filename) state_delta_db = LMDBNoLockDatabase(delta_db_filename, 'c') state_delta_store = StateDeltaStore(state_delta_db) context_manager = ContextManager(merkle_db, state_delta_store) self._context_manager = context_manager state_view_factory = StateViewFactory(merkle_db) block_db_filename = os.path.join(data_dir, 'block-{}.lmdb'.format( bind_network[-2:])) LOGGER.debug('block store file is %s', block_db_filename) block_db = LMDBNoLockDatabase(block_db_filename, 'c') block_store = BlockStore(block_db) batch_tracker = BatchTracker(block_store) block_store.add_update_observer(batch_tracker) # setup network self._dispatcher = Dispatcher() thread_pool = ThreadPoolExecutor(max_workers=10) sig_pool = ThreadPoolExecutor(max_workers=3) self._thread_pool = thread_pool self._sig_pool = sig_pool self._service = Interconnect(bind_component, self._dispatcher, secured=False, heartbeat=False, max_incoming_connections=20, monitor=True, max_future_callback_workers=10) executor = TransactionExecutor( service=self._service, context_manager=context_manager, settings_view_factory=SettingsViewFactory( StateViewFactory(merkle_db)), scheduler_type=scheduler_type, invalid_observers=[batch_tracker]) self._executor = executor self._service.set_check_connections(executor.check_connections) state_delta_processor = StateDeltaProcessor(self._service, state_delta_store, block_store) event_broadcaster = EventBroadcaster(self._service) zmq_identity = hashlib.sha512( time.time().hex().encode()).hexdigest()[:23] network_thread_pool = ThreadPoolExecutor(max_workers=10) self._network_thread_pool = network_thread_pool self._network_dispatcher = Dispatcher() secure = False if network_public_key is not None and network_private_key is not None: secure = True self._network = Interconnect( bind_network, dispatcher=self._network_dispatcher, zmq_identity=zmq_identity, secured=secure, server_public_key=network_public_key, server_private_key=network_private_key, heartbeat=True, public_endpoint=endpoint, connection_timeout=30, max_incoming_connections=100, max_future_callback_workers=10, authorize=True, pub_key=signing.generate_pubkey(identity_signing_key)) self._gossip = Gossip(self._network, endpoint=endpoint, peering_mode=peering, initial_seed_endpoints=seeds_list, initial_peer_endpoints=peer_list, minimum_peer_connectivity=3, maximum_peer_connectivity=10, topology_check_frequency=1) completer = Completer(block_store, self._gossip) block_sender = BroadcastBlockSender(completer, self._gossip) batch_sender = BroadcastBatchSender(completer, self._gossip) chain_id_manager = ChainIdManager(data_dir) identity_view_factory = IdentityViewFactory( StateViewFactory(merkle_db)) permission_verifier = PermissionVerifier( identity_view_factory, permissions, block_store.chain_head_state_root) # Create and configure journal self._journal = Journal( block_store=block_store, state_view_factory=StateViewFactory(merkle_db), block_sender=block_sender, batch_sender=batch_sender, transaction_executor=executor, squash_handler=context_manager.get_squash_handler(), identity_signing_key=identity_signing_key, chain_id_manager=chain_id_manager, data_dir=data_dir, config_dir=config_dir, permission_verifier=permission_verifier, check_publish_block_frequency=0.1, block_cache_purge_frequency=30, block_cache_keep_time=300, batch_observers=[batch_tracker], chain_observers=[state_delta_processor, event_broadcaster], ) self._genesis_controller = GenesisController( context_manager=context_manager, transaction_executor=executor, completer=completer, block_store=block_store, state_view_factory=state_view_factory, identity_key=identity_signing_key, data_dir=data_dir, config_dir=config_dir, chain_id_manager=chain_id_manager, batch_sender=batch_sender ) responder = Responder(completer) completer.set_on_batch_received(self._journal.on_batch_received) completer.set_on_block_received(self._journal.on_block_received) self._dispatcher.add_handler( validator_pb2.Message.TP_STATE_DEL_REQUEST, tp_state_handlers.TpStateDeleteHandler(context_manager), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.TP_STATE_GET_REQUEST, tp_state_handlers.TpStateGetHandler(context_manager), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.TP_STATE_SET_REQUEST, tp_state_handlers.TpStateSetHandler(context_manager), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.TP_REGISTER_REQUEST, processor_handlers.ProcessorRegisterHandler(executor.processors), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.TP_UNREGISTER_REQUEST, processor_handlers.ProcessorUnRegisterHandler(executor.processors), thread_pool) # Set up base network handlers self._network_dispatcher.add_handler( validator_pb2.Message.NETWORK_PING, PingHandler(), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.NETWORK_CONNECT, ConnectHandler(network=self._network), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.NETWORK_DISCONNECT, DisconnectHandler(network=self._network), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.AUTHORIZATION_VIOLATION, AuthorizationViolationHandler(network=self._network), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.AUTHORIZATION_TRUST_REQUEST, AuthorizationTrustRequestHandler( network=self._network, permission_verifier=permission_verifier), network_thread_pool) # Set up gossip handlers self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_GET_PEERS_REQUEST, GetPeersRequestHandler(gossip=self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_GET_PEERS_RESPONSE, GetPeersResponseHandler(gossip=self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_REGISTER, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_REGISTER, PeerRegisterHandler(gossip=self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_UNREGISTER, PeerUnregisterHandler(gossip=self._gossip), network_thread_pool) # GOSSIP_MESSAGE 1) Sends acknowledgement to the sender self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, GossipMessageHandler(), network_thread_pool) # GOSSIP_MESSAGE 2) Verify Network Permissions self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) # GOSSIP_MESSAGE 3) Verifies signature self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, signature_verifier.GossipMessageSignatureVerifier(), sig_pool) # GOSSIP_MESSAGE 4) Verifies batch structure self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, structure_verifier.GossipHandlerStructureVerifier(), network_thread_pool) # GOSSIP_MESSAGE 5) Determines if we should broadcast the # message to our peers. It is important that this occur prior # to the sending of the message to the completer, as this step # relies on whether the gossip message has previously been # seen by the validator to determine whether or not forwarding # should occur self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, GossipBroadcastHandler( gossip=self._gossip, completer=completer), network_thread_pool) # GOSSIP_MESSAGE 6) Send message to completer self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_MESSAGE, CompleterGossipHandler( completer), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_REQUEST, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_REQUEST, BlockResponderHandler(responder, self._gossip), network_thread_pool) # GOSSIP_BLOCK_RESPONSE 1) Sends ack to the sender self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, GossipBlockResponseHandler(), network_thread_pool) # GOSSIP_MESSAGE 2) Verify Network Permissions self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) # GOSSIP_BLOCK_RESPONSE 3) Verifies signature self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, signature_verifier.GossipBlockResponseSignatureVerifier(), sig_pool) # GOSSIP_BLOCK_RESPONSE 4) Check batch structure self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, structure_verifier.GossipBlockResponseStructureVerifier(), network_thread_pool) # GOSSIP_BLOCK_RESPONSE 5) Send message to completer self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, CompleterGossipBlockResponseHandler( completer), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BLOCK_RESPONSE, ResponderBlockResponseHandler(responder, self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_BY_BATCH_ID_REQUEST, BatchByBatchIdResponderHandler(responder, self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_BY_TRANSACTION_ID_REQUEST, BatchByTransactionIdResponderHandler(responder, self._gossip), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, NetworkPermissionHandler( network=self._network, permission_verifier=permission_verifier, gossip=self._gossip ), network_thread_pool) # GOSSIP_BATCH_RESPONSE 1) Sends ack to the sender self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, GossipBatchResponseHandler(), network_thread_pool) # GOSSIP_BATCH_RESPONSE 2) Verifies signature self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, signature_verifier.GossipBatchResponseSignatureVerifier(), sig_pool) # GOSSIP_BATCH_RESPONSE 3) Check batch structure self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, structure_verifier.GossipBatchResponseStructureVerifier(), network_thread_pool) # GOSSIP_BATCH_RESPONSE 4) Send message to completer self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, CompleterGossipBatchResponseHandler( completer), network_thread_pool) self._network_dispatcher.add_handler( validator_pb2.Message.GOSSIP_BATCH_RESPONSE, ResponderBatchResponseHandler(responder, self._gossip), network_thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, BatchListPermissionVerifier( permission_verifier=permission_verifier ), sig_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, signature_verifier.BatchListSignatureVerifier(), sig_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, structure_verifier.BatchListStructureVerifier(), network_thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, CompleterBatchListBroadcastHandler( completer, self._gossip), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_SUBMIT_REQUEST, client_handlers.BatchSubmitFinisher(batch_tracker), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_STATUS_REQUEST, client_handlers.BatchStatusRequest(batch_tracker), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_STATE_LIST_REQUEST, client_handlers.StateListRequest( merkle_db, self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_STATE_GET_REQUEST, client_handlers.StateGetRequest( merkle_db, self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BLOCK_LIST_REQUEST, client_handlers.BlockListRequest(self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BLOCK_GET_REQUEST, client_handlers.BlockGetRequest(self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_LIST_REQUEST, client_handlers.BatchListRequest(self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_BATCH_GET_REQUEST, client_handlers.BatchGetRequest(self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_TRANSACTION_LIST_REQUEST, client_handlers.TransactionListRequest( self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_TRANSACTION_GET_REQUEST, client_handlers.TransactionGetRequest( self._journal.get_block_store()), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_STATE_CURRENT_REQUEST, client_handlers.StateCurrentRequest( self._journal.get_current_root), thread_pool) # State Delta Subscription Handlers self._dispatcher.add_handler( validator_pb2.Message.STATE_DELTA_SUBSCRIBE_REQUEST, StateDeltaSubscriberValidationHandler(state_delta_processor), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.STATE_DELTA_SUBSCRIBE_REQUEST, StateDeltaAddSubscriberHandler(state_delta_processor), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.STATE_DELTA_UNSUBSCRIBE_REQUEST, StateDeltaUnsubscriberHandler(state_delta_processor), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.STATE_DELTA_GET_EVENTS_REQUEST, StateDeltaGetEventsHandler(block_store, state_delta_store), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST, ClientEventsSubscribeValidationHandler(event_broadcaster), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST, ClientEventsSubscribeHandler(event_broadcaster), thread_pool) self._dispatcher.add_handler( validator_pb2.Message.CLIENT_EVENTS_UNSUBSCRIBE_REQUEST, ClientEventsUnsubscribeHandler(event_broadcaster), thread_pool)
class TestPermissionVerifier(unittest.TestCase): def setUp(self): self.private_key = signing.generate_privkey() self.public_key = signing.generate_pubkey(self.private_key) self._identity_view_factory = MockIdentityViewFactory() self.permissions = {} self._identity_cache = IdentityCache( self._identity_view_factory, self._current_root_func) self.permission_verifier = \ PermissionVerifier( permissions=self.permissions, current_root_func=self._current_root_func, identity_cache=self._identity_cache) def _current_root_func(self): return "0000000000000000000000" def _create_transactions(self, count): txn_list = [] for i in range(count): payload = {'Verb': 'set', 'Name': 'name' , 'Value': 1} intkey_prefix = \ hashlib.sha512('intkey'.encode('utf-8')).hexdigest()[0:6] addr = intkey_prefix + \ hashlib.sha512(payload["Name"].encode('utf-8')).hexdigest() payload_encode = hashlib.sha512(cbor.dumps(payload)).hexdigest() header = TransactionHeader( signer_pubkey=self.public_key, family_name='intkey', family_version='1.0', inputs=[addr], outputs=[addr], dependencies=[], payload_encoding="application/cbor", payload_sha512=payload_encode) header.batcher_pubkey = self.public_key header_bytes = header.SerializeToString() signature = signing.sign( header_bytes, self.private_key) transaction = Transaction( header=header_bytes, payload=cbor.dumps(payload), header_signature=signature) txn_list.append(transaction) return txn_list def _create_batches(self, batch_count, txn_count): batch_list = [] for i in range(batch_count): txn_list = self._create_transactions(txn_count) txn_sig_list = [txn.header_signature for txn in txn_list] batch_header = BatchHeader(signer_pubkey=self.public_key) batch_header.transaction_ids.extend(txn_sig_list) header_bytes = batch_header.SerializeToString() signature = signing.sign( header_bytes, self.private_key) batch = Batch(header=header_bytes, transactions=txn_list, header_signature=signature) batch_list.append(batch) return batch_list def test_permission(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) def test_default_policy_permission(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Batch should be allowed. 2. Set default policy to deny all. Batch should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_role(self): """ Test that role:"transactor" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + \ self.public_key]) self._identity_view_factory.add_role("transactor", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_batch_signer(self): """ Test that role: "transactor.batch_signer" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + \ self.public_key]) self._identity_view_factory.add_role("transactor.batch_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor.batch_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_transaction_signer(self): """ Test that role: "transactor.transaction_signer" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + \ self.public_key]) self._identity_view_factory.add_role("transactor.transaction_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role("transactor.transaction_signer", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_transactor_transaction_siger_transaction_family(self): """ Test that role: "transactor.transaction_signer.intkey" is checked properly. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY " + \ self.public_key]) self._identity_view_factory.add_role( "transactor.transaction_signer.intkey", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy1", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "transactor.transaction_signer.intkey", "policy1") batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.is_batch_signer_authorized(batch) self.assertFalse(allowed) def test_off_chain_permissions(self): """ Test that if permissions are empty all signers are permitted. """ batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) def test_off_chain_transactor(self): """ Test that role:"transactor" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_batch_signer(self): """ Test that role:"transactor.batch_signer" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.batch_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.batch_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_transaction_signer(self): """ Test that role:"transactor.transaction_signer" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.transaction_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.transaction_signer"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_off_chain_transactor_transaction_signer_family(self): """ Test that role:"transactor.transaction_signer.intkey" is checked properly if in permissions. 1. Set policy to permit signing key. Batch should be allowed. 2. Set policy to permit some other key. Batch should be rejected. """ policy = make_policy("policy1", ["PERMIT_KEY " + self.public_key]) self.permissions["transactor.transaction_signer.intkey"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertTrue(allowed) policy = make_policy("policy1", ["PERMIT_KEY other"]) self.permissions["transactor.transaction_signer.intkey"] = policy batch = self._create_batches(1, 1)[0] allowed = self.permission_verifier.check_off_chain_batch_roles(batch) self.assertFalse(allowed) def test_network(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) def test_network_default(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Public key should be allowed. 2. Set default policy to deny all. Public key should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) allowed = self.permission_verifier.check_network_role(self.public_key) self.assertFalse(allowed) def test_network_role(self): """ Test that role:"network" is checked properly. 1. Set policy to permit signing key. Public key should be allowed. 2. Set policy to permit some other key. Public key should be rejected. """ self._identity_view_factory.add_policy( "policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role( "network", "policy1") allowed = self.permission_verifier.check_network_role(self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy2", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "network", "policy2") allowed = self.permission_verifier.check_network_role(self.public_key) self.assertFalse(allowed) def test_network_consensus(self): """ Test that if no roles are set and no default policy is set, permit all is used. """ allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) def test_network_consensus_default(self): """ Test that if no roles are set, the default policy is used. 1. Set default policy to permit all. Public key should be allowed. 2. Set default policy to deny all. Public key should be rejected. """ self._identity_view_factory.add_policy("default", ["PERMIT_KEY *"]) allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("default", ["DENY_KEY *"]) allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertFalse(allowed) def test_network_consensus_role(self): """ Test that role:"network.consensus" is checked properly. 1. Set policy to permit signing key. Public key should be allowed. 2. Set policy to permit some other key. Public key should be rejected. """ self._identity_view_factory.add_policy( "policy1", ["PERMIT_KEY " + self.public_key]) self._identity_view_factory.add_role( "network.consensus", "policy1") allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertTrue(allowed) self._identity_cache.forked() self._identity_view_factory.add_policy("policy2", ["PERMIT_KEY other"]) self._identity_view_factory.add_role( "network.consensus", "policy2") allowed = self.permission_verifier.check_network_consensus_role( self.public_key) self.assertFalse(allowed)
def __init__(self, bind_network, bind_component, bind_consensus, endpoint, peering, seeds_list, peer_list, data_dir, config_dir, identity_signer, key_dir, scheduler_type, permissions, minimum_peer_connectivity, maximum_peer_connectivity, state_pruning_block_depth, fork_cache_keep_time, network_public_key=None, network_private_key=None, roles=None, component_thread_pool_workers=10, network_thread_pool_workers=10, signature_thread_pool_workers=3): """Constructs a validator instance. Args: bind_network (str): the network endpoint bind_component (str): the component endpoint endpoint (str): the zmq-style URI of this validator's publically reachable endpoint peering (str): The type of peering approach. Either 'static' or 'dynamic'. In 'static' mode, no attempted topology buildout occurs -- the validator only attempts to initiate peering connections with endpoints specified in the peer_list. In 'dynamic' mode, the validator will first attempt to initiate peering connections with endpoints specified in the peer_list and then attempt to do a topology buildout starting with peer lists obtained from endpoints in the seeds_list. In either mode, the validator will accept incoming peer requests up to max_peers. seeds_list (list of str): a list of addresses to connect to in order to perform the initial topology buildout peer_list (list of str): a list of peer addresses data_dir (str): path to the data directory config_dir (str): path to the config directory identity_signer (Signer): cryptographic signer the validator uses for signing key_dir (str): path to the data directory component_thread_pool_workers (int): number of workers in the component thread pool; defaults to 10. network_thread_pool_workers (int): number of workers in the network thread pool; defaults to 10. signature_thread_pool_workers (int): number of workers in the signature thread pool; defaults to 3. """ # -- Setup Global State Database and Factory -- # global_state_db_filename = os.path.join( data_dir, 'merkle-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug('global state database file is %s', global_state_db_filename) global_state_db = NativeLmdbDatabase( global_state_db_filename, indexes=MerkleDatabase.create_index_configuration()) state_view_factory = StateViewFactory(global_state_db) # -- Setup Receipt Store -- # receipt_db_filename = os.path.join( data_dir, 'txn_receipts-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug('txn receipt store file is %s', receipt_db_filename) receipt_db = LMDBNoLockDatabase(receipt_db_filename, 'c') receipt_store = TransactionReceiptStore(receipt_db) # -- Setup Block Store -- # block_db_filename = os.path.join( data_dir, 'block-{}.lmdb'.format(bind_network[-2:])) LOGGER.debug('block store file is %s', block_db_filename) block_db = NativeLmdbDatabase( block_db_filename, indexes=BlockStore.create_index_configuration()) block_store = BlockStore(block_db) # The cache keep time for the journal's block cache must be greater # than the cache keep time used by the completer. base_keep_time = 1200 block_manager = BlockManager() block_manager.add_commit_store(block_store) block_status_store = BlockValidationResultStore() # -- Setup Thread Pools -- # component_thread_pool = InstrumentedThreadPoolExecutor( max_workers=component_thread_pool_workers, name='Component') network_thread_pool = InstrumentedThreadPoolExecutor( max_workers=network_thread_pool_workers, name='Network') client_thread_pool = InstrumentedThreadPoolExecutor(max_workers=5, name='Client') sig_pool = InstrumentedThreadPoolExecutor( max_workers=signature_thread_pool_workers, name='Signature') # -- Setup Dispatchers -- # component_dispatcher = Dispatcher() network_dispatcher = Dispatcher() # -- Setup Services -- # component_service = Interconnect(bind_component, component_dispatcher, secured=False, reap=False, max_incoming_connections=20, monitor=True, max_future_callback_workers=10) zmq_identity = hashlib.sha512( time.time().hex().encode()).hexdigest()[:23] secure = False if network_public_key is not None and network_private_key is not None: secure = True network_service = Interconnect(bind_network, dispatcher=network_dispatcher, zmq_identity=zmq_identity, secured=secure, server_public_key=network_public_key, server_private_key=network_private_key, reap=True, public_endpoint=endpoint, connection_timeout=120, max_incoming_connections=100, max_future_callback_workers=10, authorize=True, signer=identity_signer, roles=roles) # -- Setup Transaction Execution Platform -- # context_manager = ContextManager(global_state_db) batch_tracker = BatchTracker(block_store.has_batch) settings_cache = SettingsCache( SettingsViewFactory(state_view_factory), ) transaction_executor = TransactionExecutor( service=component_service, context_manager=context_manager, settings_view_factory=SettingsViewFactory(state_view_factory), scheduler_type=scheduler_type, invalid_observers=[batch_tracker]) component_service.set_check_connections( transaction_executor.check_connections) event_broadcaster = EventBroadcaster(component_service, block_store, receipt_store) # -- Consensus Engine -- # consensus_thread_pool = InstrumentedThreadPoolExecutor( max_workers=3, name='Consensus') consensus_dispatcher = Dispatcher() consensus_service = Interconnect(bind_consensus, consensus_dispatcher, secured=False, reap=False, max_incoming_connections=20, max_future_callback_workers=10) consensus_registry = ConsensusRegistry() consensus_notifier = ConsensusNotifier( consensus_service, consensus_registry, identity_signer.get_public_key().as_hex()) consensus_activation_observer = ConsensusActivationObserver( consensus_registry, consensus_notifier, settings_view_factory=SettingsViewFactory(state_view_factory)) # -- Setup P2P Networking -- # gossip = Gossip(network_service, settings_cache, lambda: block_store.chain_head, block_store.chain_head_state_root, consensus_notifier, endpoint=endpoint, peering_mode=peering, initial_seed_endpoints=seeds_list, initial_peer_endpoints=peer_list, minimum_peer_connectivity=minimum_peer_connectivity, maximum_peer_connectivity=maximum_peer_connectivity, topology_check_frequency=1) consensus_notifier.set_gossip(gossip) completer = Completer( block_manager=block_manager, transaction_committed=block_store.has_transaction, get_committed_batch_by_id=block_store.get_batch, get_committed_batch_by_txn_id=( block_store.get_batch_by_transaction), gossip=gossip, cache_keep_time=base_keep_time, cache_purge_frequency=30, requested_keep_time=300) self._completer = completer block_sender = BroadcastBlockSender(completer, gossip) identity_view_factory = IdentityViewFactory( StateViewFactory(global_state_db)) id_cache = IdentityCache(identity_view_factory) # -- Setup Permissioning -- # permission_verifier = PermissionVerifier( permissions, block_store.chain_head_state_root, id_cache) identity_observer = IdentityObserver(to_update=id_cache.invalidate, forked=id_cache.forked) settings_observer = SettingsObserver( to_update=settings_cache.invalidate, forked=settings_cache.forked) # -- Setup Journal -- # journal = Journal( block_store=block_store, block_manager=block_manager, state_database=global_state_db, block_sender=block_sender, block_status_store=block_status_store, consensus_notifier=consensus_notifier, consensus_registry=consensus_registry, state_pruning_block_depth=state_pruning_block_depth, fork_cache_keep_time=fork_cache_keep_time, data_dir=data_dir, batch_observers=[batch_tracker], invalid_transaction_observers=[batch_tracker], observers=[ event_broadcaster, receipt_store, batch_tracker, identity_observer, settings_observer, consensus_activation_observer ], key_dir=key_dir, genesis_observers=[receipt_store], ) completer.set_get_chain_head(lambda: journal.chain_head) responder = Responder(completer) completer.set_on_block_received(journal.queue_block) # -- Register Message Handler -- # network_handlers.add(network_dispatcher, network_service, gossip, completer, responder, network_thread_pool, sig_pool, lambda block_id: block_id in block_manager, journal.has_batch, permission_verifier, consensus_notifier) component_handlers.add(component_dispatcher, gossip, context_manager, transaction_executor, completer, block_store, batch_tracker, global_state_db, self.get_chain_head_state_root_hash, receipt_store, event_broadcaster, permission_verifier, component_thread_pool, client_thread_pool, sig_pool, journal, identity_signer.get_public_key().as_hex()) # -- Store Object References -- # self._component_dispatcher = component_dispatcher self._component_service = component_service self._component_thread_pool = component_thread_pool self._network_dispatcher = network_dispatcher self._network_service = network_service self._network_thread_pool = network_thread_pool consensus_proxy = ConsensusProxy( block_manager=block_manager, journal=journal, gossip=gossip, identity_signer=identity_signer, settings_view_factory=SettingsViewFactory(state_view_factory), state_view_factory=state_view_factory, consensus_registry=consensus_registry, consensus_notifier=consensus_notifier) consensus_handlers.add(consensus_dispatcher, consensus_thread_pool, consensus_proxy, consensus_notifier) self._block_status_store = block_status_store self._consensus_notifier = consensus_notifier self._consensus_dispatcher = consensus_dispatcher self._consensus_service = consensus_service self._consensus_thread_pool = consensus_thread_pool self._consensus_registry = consensus_registry self._client_thread_pool = client_thread_pool self._sig_pool = sig_pool self._context_manager = context_manager self._transaction_executor = transaction_executor self._gossip = gossip self._journal = journal