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
Beispiel #2
0
    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")
Beispiel #4
0
    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")
Beispiel #5
0
 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()
Beispiel #6
0
    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")
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
    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")
Beispiel #10
0
    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)
Beispiel #11
0
    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")
Beispiel #12
0
    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
Beispiel #14
0
    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()
Beispiel #16
0
    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")
Beispiel #18
0
def import_anchoring_module(name: str):
    return ModuleManager.import_service_module(
        ANCHORING_ARTIFACT_NAME, ANCHORING_ARTIFACT_VERSION, name)