Exemple #1
0
    def __init__(self,
                 client: ExonumClient,
                 instance_name: str = "crypto",
                 version: str = "0.2.0"):
        self.client = client
        service_name = "exonum-cryptocurrency"
        self.service_version = version
        self.instance_name = instance_name
        self.loader = client.protobuf_loader()
        self.loader.initialize()
        self.loader.load_main_proto_files()
        self.loader.load_service_proto_files(runtime_id=0,
                                             artifact_name="exonum-supervisor",
                                             artifact_version="1.0.0")
        self.loader.load_service_proto_files(
            runtime_id=0,
            artifact_name=service_name,
            artifact_version=self.service_version)

        self.cryptocurrency_module = ModuleManager.import_service_module(
            service_name, self.service_version, "service")
        self.types_module = ModuleManager.import_service_module(
            service_name, self.service_version, "exonum.crypto.types")
        instance_id = client.public_api.get_instance_id_by_name(
            self.instance_name)
        self.msg_generator = MessageGenerator(
            instance_id=instance_id,
            artifact_name=service_name,
            artifact_version=self.service_version)
Exemple #2
0
def transfer(
    client: ExonumClient, message_generator: MessageGenerator, from_keypair: KeyPair, to_key: PublicKey, amount: int
) -> Tuple[int, int]:
    """This example transfers tokens from one wallet to the other one and
    returns the balances of these wallets."""

    cryptocurrency_module = ModuleManager.import_service_module(CRYPTOCURRENCY_ARTIFACT_NAME, "service")
    # Note that since we are using the Cryptocurrency module,
    # we need to load helpers from this module and not from the main module:
    helpers_module = ModuleManager.import_service_module(CRYPTOCURRENCY_ARTIFACT_NAME, "helpers")

    transfer_message = cryptocurrency_module.Transfer()
    transfer_message.to.CopyFrom(helpers_module.PublicKey(data=to_key.value))
    transfer_message.amount = amount
    transfer_message.seed = Seed.get_seed()

    transfer_tx = message_generator.create_message(transfer_message)
    transfer_tx.sign(from_keypair)

    response = client.send_transaction(transfer_tx)
    ensure_status_code(response)
    tx_hash = response.json()["tx_hash"]

    # Wait for new blocks:

    with client.create_subscriber() as subscriber:
        subscriber.wait_for_new_block()
        subscriber.wait_for_new_block()

    ensure_transaction_success(client, tx_hash)

    from_balance = get_balance(client, from_keypair.public_key)
    to_balance = get_balance(client, to_key)

    return from_balance, to_balance
    def __init__(self, client: ExonumClient):
        self.client = client
        cryptocurrency_service_name = "exonum-cryptocurrency-advanced"
        cryptocurrency_service_version = "0.13.0-rc.2"
        self.loader = client.protobuf_loader()
        self.loader.initialize()
        self.loader.load_main_proto_files()
        self.loader.load_service_proto_files(
            runtime_id=0,
            artifact_name="exonum-supervisor",
            artifact_version="0.13.0-rc.2",
        )
        self.loader.load_service_proto_files(
            runtime_id=0,
            artifact_name=cryptocurrency_service_name,
            artifact_version=cryptocurrency_service_version,
        )

        self.cryptocurrency_module = ModuleManager.import_service_module(
            cryptocurrency_service_name, cryptocurrency_service_version,
            "service")
        self.types_module = ModuleManager.import_service_module(
            cryptocurrency_service_name, cryptocurrency_service_version,
            "types")
        instance_id = client.public_api.get_instance_id_by_name("crypto")
        self.msg_generator = MessageGenerator(
            instance_id=instance_id,
            artifact_name=cryptocurrency_service_name,
            artifact_version=cryptocurrency_service_version)
Exemple #4
0
def run() -> None:
    """Example of downloading the Protobuf sources and using the compiled
    module."""
    client = ExonumClient(hostname="127.0.0.1", public_api_port=8080, private_api_port=8081)

    # Create ProtobufLoader via context manager (so that we will not have to
    # initialize/deinitialize it manually):
    with client.protobuf_loader() as loader:
        # Load core proto files:
        loader.load_main_proto_files()
        # Load proto files for the Exonum supervisor service:
        loader.load_service_proto_files(RUST_RUNTIME_ID, "exonum-supervisor:0.12.0")

        # Load the main module (runtime.proto):
        main_module = ModuleManager.import_main_module("runtime")

        # Create a Protobuf message object:
        artifact_id = main_module.ArtifactId()
        artifact_id.runtime_id = RUST_RUNTIME_ID
        artifact_id.name = "some_service:0.1.0"

        # Working with Protobuf objects, you have to follow Protobuf Python API
        # conventions. See Protobuf Python API docs for details:
        instance_spec = main_module.InstanceSpec()
        instance_spec.artifact.CopyFrom(artifact_id)

        # Load the service module (service.proto from the supervisor service):
        service_module = ModuleManager.import_service_module("exonum-supervisor:0.12.0", "service")

        # Workflow is the same as for the main modules:
        _deploy_request = service_module.DeployRequest()
def create_wallet(client: ExonumClient, message_generator: MessageGenerator,
                  name: str) -> KeyPair:
    """Creates a wallet with the given name and returns a KeyPair for it."""
    key_pair = KeyPair.generate()

    # Load the "service.proto" from the Cryptocurrency service:
    cryptocurrency_module = ModuleManager.import_service_module(
        CRYPTOCURRENCY_ARTIFACT_NAME, "service")

    # Create a Protobuf message:
    create_wallet_message = cryptocurrency_module.TxCreateWallet()
    create_wallet_message.name = name

    # Convert the Protobuf message to an Exonum message and sign it:
    create_wallet_tx = message_generator.create_message(create_wallet_message)
    create_wallet_tx.sign(key_pair)

    # Send the transaction to Exonum:
    response = client.send_transaction(create_wallet_tx)
    ensure_status_code(response)
    tx_hash = response.json()["tx_hash"]

    # Wait for new blocks:
    with client.create_subscriber() as subscriber:
        subscriber.wait_for_new_block()
        subscriber.wait_for_new_block()

    ensure_transaction_success(client, tx_hash)

    print(f"Successfully created wallet with name '{name}'")

    return key_pair
Exemple #6
0
def deploy_service(client: ExonumClient, service_name: str,
                   service_version: str) -> None:
    """This function sends a deploy request for the desired service
    and waits until it is deployed."""

    # Create a deploy request message:
    service_module = ModuleManager.import_service_module(
        SUPERVISOR_ARTIFACT_NAME, SUPERVISOR_ARTIFACT_VERSION, "service")

    deploy_request = service_module.DeployRequest()
    deploy_request.artifact.runtime_id = 0  # Rust runtime ID.
    deploy_request.artifact.name = service_name
    deploy_request.artifact.version = service_version
    deploy_request.deadline_height = 1000000  # Some big number (we won't have to wait that long, it's just a deadline).

    # Convert the request from a Protobuf message to bytes:
    request_bytes = deploy_request.SerializeToString()

    # Send the request and wait for Exonum to process it:
    send_request(client, "deploy-artifact", request_bytes)

    # Ensure that the service is added to the available modules:
    available_services = client.public_api.available_services().json()
    if service_name not in map(lambda x: x["name"],
                               available_services["artifacts"]):
        raise RuntimeError(
            f"{service_name} is not listed in available services after deployment"
        )
def start_service(client: ExonumClient, service_name: str,
                  instance_name: str) -> int:
    """This function starts the previously deployed service instance."""

    # Create a start request:
    service_module = ModuleManager.import_service_module(
        "exonum-supervisor:0.12.0", "service")
    start_request = service_module.StartService()
    start_request.artifact.runtime_id = 0  # Rust runtime ID.
    start_request.artifact.name = service_name
    start_request.name = instance_name
    start_request.deadline_height = 1000000  # Some big number.

    # Convert the request from a Protobuf message to bytes:
    request_bytes = start_request.SerializeToString()

    # Send the request and wait for Exonum to process it:
    send_request(client, "start-service", request_bytes)

    # Ensure that the service is added to the running instances list:
    available_services = client.available_services().json()
    if instance_name not in map(lambda x: x["name"],
                                available_services["services"]):
        raise RuntimeError(
            f"{instance_name} is not listed in running instances after starting"
        )

    # Service has started.
    # Return the running instance ID:
    for instance in available_services["services"]:
        if instance["name"] == instance_name:
            return instance["id"]

    raise RuntimeError("Instance ID was not found")
def verify_proof_to_wallet(proof: Dict[Any, Any], expected_hash: Hash) -> None:
    """Verifies MapProof to table."""

    # Keys in the proof to the wallet are encoded as a byte sequence parsed from
    # a hexadecimal string:
    def key_encoder(data: str) -> bytes:
        return bytes.fromhex(data)

    # Values in the proof to the wallet are encoded as a Protobuf binary
    # representation of the `Wallet` structure:
    cryptocurrency_module = ModuleManager.import_service_module(
        CRYPTOCURRENCY_ARTIFACT_NAME, "service")
    value_encoder = build_encoder_function(cryptocurrency_module.Wallet)

    try:
        parsed_proof = MapProof.parse(proof, key_encoder, value_encoder)

        result = parsed_proof.check()

        if result.root_hash() == expected_hash:
            print("MapProof to wallet verified successfully")
        else:
            print("MapProof to wallet verification failed")
    except MalformedMapProofError:
        print("Received malformed proof to the wallet")
Exemple #9
0
    def __init__(self, client: ExonumClient):
        self.client = client
        cryptocurrency_service_name = 'exonum-cryptocurrency-advanced:0.13.0-rc.2'
        self.loader = client.protobuf_loader()
        self.loader.initialize()
        self.loader.load_main_proto_files()
        self.loader.load_service_proto_files(
            runtime_id=0, service_name='exonum-supervisor:0.13.0-rc.2')
        self.loader.load_service_proto_files(
            runtime_id=0, service_name=cryptocurrency_service_name)

        self.cryptocurrency_module = ModuleManager.import_service_module(
            cryptocurrency_service_name, 'service')
        self.types_module = ModuleManager.import_service_module(
            cryptocurrency_service_name, 'types')
        instance_id = client.get_instance_id_by_name("crypto")
        self.msg_generator = MessageGenerator(
            instance_id=instance_id, artifact_name=cryptocurrency_service_name)
Exemple #10
0
def transfer(client: ExonumClient, message_generator: MessageGenerator,
             from_keypair: KeyPair, to_key: PublicKey,
             amount: int) -> Tuple[int, int]:
    """This example transfers tokens from one wallet to the other one and
    returns the balances of these wallets."""

    cryptocurrency_module = ModuleManager.import_service_module(
        CRYPTOCURRENCY_ARTIFACT_NAME, CRYPTOCURRENCY_ARTIFACT_VERSION,
        "service")
    # Note that since we are using the Cryptocurrency module,
    # we need to load types from this module and not from the main module:
    types_module = ModuleManager.import_service_module(
        CRYPTOCURRENCY_ARTIFACT_NAME, CRYPTOCURRENCY_ARTIFACT_VERSION,
        "exonum.crypto.types")

    transfer_message = cryptocurrency_module.Transfer()
    # The address is a hash of a `Caller` protobuf message.
    hash_address = message_generator.pk_to_hash_address(to_key)
    if hash_address is None:
        raise Exception
    transfer_message.to.CopyFrom(types_module.Hash(data=hash_address.value))
    transfer_message.amount = amount
    transfer_message.seed = Seed.get_seed()

    transfer_tx = message_generator.create_message(transfer_message)
    transfer_tx.sign(from_keypair)

    response = client.public_api.send_transaction(transfer_tx)
    ensure_status_code(response)
    tx_hash = response.json()["tx_hash"]

    # Wait for new blocks:

    with client.create_subscriber("blocks") as subscriber:
        subscriber.wait_for_new_event()
        subscriber.wait_for_new_event()

    ensure_transaction_success(client, tx_hash)

    from_balance = get_balance(client, from_keypair.public_key)
    to_balance = get_balance(client, to_key)

    return from_balance, to_balance
def run_example(source: str) -> None:
    # Create client.
    client = ExonumClient(hostname="127.0.0.1", public_api_port=8080, private_api_port=8081)

    # Setup protobuf provider.
    setup_protobuf_provider(client.protobuf_provider, source)

    # Create ProtobufLoader via context manager (so that we will not have to
    # initialize/deinitialize it manually):
    with client.protobuf_loader() as loader:
        # Load core proto files:
        loader.load_main_proto_files()
        # Load proto files for the Exonum supervisor service:
        loader.load_service_proto_files(RUST_RUNTIME_ID, SERVICE_NAME, SERVICE_VERSION)

        # Load the main module (exonum/crypto/type.proto).
        types_module = ModuleManager.import_main_module("exonum.crypto.types")

        # Create a Protobuf message object:
        public_key = types_module.PublicKey()
        public_key.data = bytes(i for i in range(32))

        # Load the service module (service.proto from the cryptocurrency-advanced service).
        # Note that we load "service" module, which is absent in current version
        # of the service, it only exists in Exonum 1.0.
        service_module = ModuleManager.import_service_module(SERVICE_NAME, SERVICE_VERSION, "service")
        # Note that if we want to work with service module, we should use types also from that module.
        # That's required because of the inner python Protobuf implementation check system.
        types_module = ModuleManager.import_service_module(SERVICE_NAME, SERVICE_VERSION, "exonum.crypto.types")

        # Workflow is the same as for the main modules:
        transfer = service_module.Transfer()
        to = types_module.Hash()
        to.data = bytes(i for i in range(32))

        # Working with Protobuf objects, you have to follow Protobuf Python API conventions.
        # See Protobuf Python API docs for details.
        transfer.to.CopyFrom(to)
        transfer.amount = 10
        transfer.seed = 1
Exemple #12
0
def start_service(client: ExonumClient, service_name: str,
                  service_version: str, instance_name: str) -> int:
    """This function starts the previously deployed service instance."""

    # Create a start request:
    service_module = ModuleManager.import_service_module(
        SUPERVISOR_ARTIFACT_NAME, SUPERVISOR_ARTIFACT_VERSION, "service")
    start_request = service_module.StartService()
    start_request.artifact.runtime_id = 0  # Rust runtime ID.
    start_request.artifact.name = service_name
    start_request.artifact.version = service_version
    start_request.name = instance_name

    # Create a config change object:
    config_change = service_module.ConfigChange()
    config_change.start_service.CopyFrom(start_request)

    # Create a config proposal:
    config_proposal = service_module.ConfigPropose()
    config_proposal.changes.append(config_change)

    # Convert the config proposal from a Protobuf message to bytes:
    request_bytes = config_proposal.SerializeToString()

    # Send the request and wait for Exonum to process it:
    send_request(client, "propose-config", request_bytes)

    # Ensure that the service is added to the running instances list:
    available_services = client.public_api.available_services().json()
    if instance_name not in map(lambda x: x["spec"]["name"],
                                available_services["services"]):
        raise RuntimeError(
            f"{instance_name} is not listed in running instances after starting"
        )

    # Service has started.
    # Return the running instance ID:
    for state in available_services["services"]:
        instance = state["spec"]
        if instance["name"] == instance_name:
            return instance["id"]

    raise RuntimeError("Instance ID was not found")