def serialize_config(self, loader: ProtobufLoader, instance: Instance, config: Any) -> bytes: try: try: # Try to load module (if it's already compiled) first. service_module = ModuleManager.import_service_module( instance.artifact.name, instance.artifact.version, "service") except (ModuleNotFoundError, ImportError): # If it's not compiled, load & compile protobuf. loader.load_service_proto_files(instance.artifact.runtime_id, instance.artifact.name, instance.artifact.version) service_module = ModuleManager.import_service_module( instance.artifact.name, instance.artifact.version, "service") config_class = service_module.Config # `build_encoder_function` will create a recursive binary serializer for the # provided message type. In our case we want to serialize `Config`. config_encoder = build_encoder_function(config_class) result = config_encoder(config) # We're catching all the exceptions to shutdown gracefully (on the caller side) just in case. # pylint: disable=broad-except except Exception as error: artifact_name = instance.artifact.name raise InstanceSpecLoadError( f"Couldn't get a proto description for artifact: {artifact_name}, error: {error}" ) return result
def _get_encoder( structure_name: str, main_module: Optional[str] = None, service_name: Optional[str] = None, service_module: Optional[str] = None, ) -> type: try: if main_module: module = ModuleManager.import_main_module(main_module) elif service_name and service_module: module = ModuleManager.import_service_module( service_name, service_module) else: raise MapProofBuilderError("Module data not provided") return getattr(module, structure_name) except (ModuleNotFoundError, ImportError): error_data = { "main_module": main_module, "service_name": service_name, "service_module": service_module } raise MapProofBuilderError("Incorrect module data", error_data) except AttributeError: error_data = {"service_name": structure_name} raise MapProofBuilderError("Incorrect structure name", error_data)
def test_load_fail_service(self): # Check that import of an incorrect module for the correct service raises an exception: cryptocurrency_service_name = "exonum-cryptocurrency-advanced:0.11.0" with self.assertRaises(ModuleNotFoundError): ModuleManager.import_service_module(cryptocurrency_service_name, "no_module") # Check that module import for an incorrect service raises an exception: with self.assertRaises(ModuleNotFoundError): ModuleManager.import_service_module("no_service", "service")
def test_service_sources_download(self): with self.client.protobuf_loader() as loader: loader.load_main_proto_files() loader.load_service_proto_files(0, "exonum-supervisor", "1.0.0") _service_module = ModuleManager.import_service_module( "exonum-supervisor", "1.0.0", "service")
def test_load_service(self): # Check that the Cryptocurrency service is loaded correctly: cryptocurrency_service_name = "exonum-cryptocurrency-advanced" version = "1.0.0" cryptocurrency_module = ModuleManager.import_service_module( cryptocurrency_service_name, version, "service") cryptocurrency_module.CreateWallet()
def initialize(self) -> None: """Initializes the Supervisor interface, doing the following: - Initializes protobuf loader; - Finds the ID and the name of the exonum supervisor service instance; - Loading the supervisor proto files; - Importing the supervisor's `service` proto module. """ self._loader.initialize() self._loader.load_main_proto_files() services = self._main_client.public_api.available_services().json() for artifact in services["artifacts"]: if artifact["name"].startswith("exonum-supervisor"): self._supervisor_runtime_id = artifact["runtime_id"] self._supervisor_artifact_name = artifact["name"] self._supervisor_artifact_version = artifact["version"] break if not self._supervisor_artifact_name: raise RuntimeError( "Could not find exonum-supervisor in available artifacts." "Please check that exonum node configuration is correct") self._loader.load_service_proto_files( self._supervisor_runtime_id, self._supervisor_artifact_name, self._supervisor_artifact_version) self._service_module = ModuleManager.import_service_module( self._supervisor_artifact_name, self._supervisor_artifact_version, "service")
def setUpClass(cls): # Add a folder with the pre-compiled Protobuf messages to the path (so that it could be imported): sys.path.append(os.path.abspath("tests/proto_dir")) # Gen init data: keys = KeyPair.generate() # Prepare an original message: cryptocurrency_service_name = "exonum-cryptocurrency-advanced" version = "1.0.0" cryptocurrency_module = ModuleManager.import_service_module( cryptocurrency_service_name, version, "service") cryptocurrency_message_generator = MessageGenerator( 1024, cryptocurrency_service_name, version) create_wallet_alice = cryptocurrency_module.CreateWallet() create_wallet_alice.name = "Alice" # Create an original message: create_wallet_alice_tx = cryptocurrency_message_generator.create_message( create_wallet_alice) create_wallet_alice_tx.sign(keys) cls.keys = keys cls.exonum_message = create_wallet_alice_tx cls.cryptocurrency_service_name = cryptocurrency_service_name
def setUpClass(cls): # Add a folder with the pre-compiled Protobuf messages to the path (so that it could be imported): sys.path.append(os.path.abspath("tests/proto_dir")) # Unload any previously loaded `exonum_main` modules from test_exonum_client: loaded_modules = list(sys.modules.keys()) for module in loaded_modules: if module.startswith("exonum_modules"): del sys.modules[module] # Gen init data: keys = KeyPair.generate() # Prepare an original message: cryptocurrency_service_name = "exonum-cryptocurrency-advanced:0.11.0" cryptocurrency_module = ModuleManager.import_service_module(cryptocurrency_service_name, "service") cryptocurrency_message_generator = MessageGenerator(1024, cryptocurrency_service_name) create_wallet_alice = cryptocurrency_module.CreateWallet() create_wallet_alice.name = "Alice" # Create an original message: create_wallet_alice_tx = cryptocurrency_message_generator.create_message(create_wallet_alice) create_wallet_alice_tx.sign(keys) cls.keys = keys cls.exonum_message = create_wallet_alice_tx cls.cryptocurrency_service_name = cryptocurrency_service_name
def test_main_sources_download(self): client = ExonumClient(hostname=EXONUM_IP, public_api_port=EXONUM_PUBLIC_PORT, private_api_port=EXONUM_PRIVATE_PORT) with client.protobuf_loader() as loader: loader.load_main_proto_files() _runtime_mod = ModuleManager.import_main_module("runtime")
def test_map_proof_validate_one_node(self): proof = { "entries": [{ "key": "1dddbac5d8f16ef97b20a6abe854f6356436ce97b71d9d439b17b91f3a144ac6", "value": { "pub_key": { "data": list( bytes.fromhex( "1dddbac5d8f16ef97b20a6abe854f6356436ce97b71d9d439b17b91f3a144ac6" )) }, "name": "Alice1", "balance": 95, "history_len": 6, "history_hash": { "data": list( bytes.fromhex( "1ff3a775f6df930ad63c5f1ce683393c7f080dbd5ca544e40c7488640bf732f8" )) }, }, }], "proof": [{ "path": "0110000001101111100100100101110101110101011111101101011110011101110111111010011110011" "000000101110011100001111110001111111111000000110110001000011111010010110001000001101100011010" "000000001010000101111100110000011111011100111110010101101110000100010110010001", "hash": "deaa44743a85249302a4633d8cdde96526064c56715318fa0712fe4befb1fef3", }], } cryptocurrency_service_name = "exonum-cryptocurrency-advanced:0.11.0" cryptocurrency_module = ModuleManager.import_service_module( cryptocurrency_service_name, "service") cryptocurrency_decoder = build_encoder_function( cryptocurrency_module.Wallet) parsed_proof = MapProof.parse(proof, bytes.fromhex, cryptocurrency_decoder) result = parsed_proof.check() entries = result.all_entries() self.assertEqual(len(entries), 1) self.assertFalse(entries[0].is_missing) self.assertEqual(entries[0].key, proof["entries"][0]["key"]) self.assertEqual(entries[0].value, proof["entries"][0]["value"]) expected_hash = "7adcdfe51855dc073681b7f9274a414d4d9f378e94e02c39e04819c6f9ed27e7" self.assertEqual(result.root_hash().hex(), expected_hash)
def test_service_sources_download(self): client = ExonumClient(hostname=EXONUM_IP, public_api_port=EXONUM_PUBLIC_PORT, private_api_port=EXONUM_PRIVATE_PORT) with client.protobuf_loader() as loader: loader.load_main_proto_files() loader.load_service_proto_files(0, "exonum-supervisor:0.11.0") _service_module = ModuleManager.import_service_module( "exonum-supervisor:0.11.0", "service")
def _build_consensus_change(self, consensus: Any, change: Any) -> None: """Creates a ConfigChange for consensus config.""" assert self._service_module is not None blockchain_module = ModuleManager.import_service_module( self._supervisor_artifact_name, self._supervisor_artifact_version, "exonum.blockchain") types_module = ModuleManager.import_service_module( self._supervisor_artifact_name, self._supervisor_artifact_version, "exonum.crypto.types") new_consensus_config = blockchain_module.Config() for consensus_key, service_key in consensus["validator_keys"]: consensus_key = types_module.PublicKey( data=bytes.fromhex(consensus_key)) service_key = types_module.PublicKey( data=bytes.fromhex(service_key)) validator_keys = blockchain_module.ValidatorKeys() validator_keys.consensus_key.CopyFrom(consensus_key) validator_keys.service_key.CopyFrom(service_key) new_consensus_config.validator_keys.append(validator_keys) new_consensus_config.first_round_timeout = consensus[ "first_round_timeout"] new_consensus_config.status_timeout = consensus["status_timeout"] new_consensus_config.peers_timeout = consensus["peers_timeout"] new_consensus_config.txs_block_limit = consensus["txs_block_limit"] new_consensus_config.max_message_len = consensus["max_message_len"] new_consensus_config.min_propose_timeout = consensus[ "min_propose_timeout"] new_consensus_config.max_propose_timeout = consensus[ "max_propose_timeout"] new_consensus_config.propose_timeout_threshold = consensus[ "propose_timeout_threshold"] change.consensus.CopyFrom(new_consensus_config)
def _get_encoder( structure_name: str, main_module: Optional[str] = None, service_name: Optional[str] = None, service_version: Optional[str] = None, service_module: Optional[str] = None, ) -> type: try: if main_module: module = ModuleManager.import_main_module(main_module) elif service_name and service_module and service_version: module = ModuleManager.import_service_module( service_name, service_version, service_module) else: err = MapProofBuilderError("Module data not provided") logger.warning(str(err)) raise err encoder = getattr(module, structure_name) logger.debug("Successfully got encoder.") return encoder except (ModuleNotFoundError, ImportError): error_data = { "main_module": main_module, "service_name": service_name, "service_module": service_module } err = MapProofBuilderError("Incorrect module data", error_data) logger.warning("%s: %s", str(err), error_data) raise err except AttributeError: error_data = {"service_name": structure_name} err = MapProofBuilderError("Incorrect structure name", error_data) logger.warning("%s: %s", str(err), error_data) raise err
def test_map_proof_validate_empty_proof(self): proof = {"entries": [], "proof": []} cryptocurrency_service_name = "exonum-cryptocurrency-advanced:0.11.0" cryptocurrency_module = ModuleManager.import_service_module( cryptocurrency_service_name, "service") cryptocurrency_decoder = build_encoder_function( cryptocurrency_module.Wallet) parsed_proof = MapProof.parse(proof, bytes.fromhex, cryptocurrency_decoder) result = parsed_proof.check() entries = result.all_entries() self.assertEqual(len(entries), 0) expected_hash = "7324b5c72b51bb5d4c180f1109cfd347b60473882145841c39f3e584576296f9" self.assertEqual(result.root_hash().hex(), expected_hash)
def test_load_main(self): # Check that the main module is loaded correctly: main_module = ModuleManager.import_main_module("runtime") main_module.AnyTx()
def test_main_sources_download(self): with self.client.protobuf_loader() as loader: loader.load_main_proto_files() _blockchain_mod = ModuleManager.import_main_module( "exonum.blockchain")
def test_load_fail_main(self): # Check that an incorrect module import raises an exception: with self.assertRaises(ModuleNotFoundError): _main_module = ModuleManager.import_main_module("no_module")
def import_anchoring_module(name: str): return ModuleManager.import_service_module( ANCHORING_ARTIFACT_NAME, ANCHORING_ARTIFACT_VERSION, name)