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)
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)
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
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")
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)
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
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")