diff --git a/examples/tls-example.py b/examples/tls-example.py new file mode 100644 index 00000000..d117d95d --- /dev/null +++ b/examples/tls-example.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Copyright Soramitsu Co., Ltd. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 +# + +import os +import binascii +from iroha import IrohaCrypto +from iroha import Iroha, IrohaGrpc +import sys + +if sys.version_info[0] < 3: + raise Exception('Python 3 or a more recent version is required.') + +print(""" + +This example works only through a TLS connection, you must first configure torii_tls_params +https://iroha.readthedocs.io/en/master/configure/torii-tls.html. + +""") + +IROHA_HOST_ADDR = os.getenv('IROHA_HOST_ADDR', 'localhost') +IROHA_TLS_PORT = os.getenv('IROHA_PORT', '55552') +ADMIN_ACCOUNT_ID = os.getenv('ADMIN_ACCOUNT_ID', 'admin@test') +ADMIN_PRIVATE_KEY = os.getenv( + 'ADMIN_PRIVATE_KEY', 'f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70') +iroha = Iroha(ADMIN_ACCOUNT_ID) +cert = "-----BEGIN CERTIFICATE-----" \ + "MIIDiDCCAnACCQDp6UiqpNfRazANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC" \ + "cnUxDjAMBgNVBAgMBWlyb2hhMRIwEAYDVQQHDAlpbm5vcG9saXMxEjAQBgNVBAoM" \ + "CXNvcmFtaXRzdTENMAsGA1UECwwEc29yYTESMBAGA1UEAwwJbG9jYWxob3N0MRsw" \ + "GQYJKoZIhvcNAQkBFgxtYWlsQG1haWwucnUwHhcNMjAxMTE4MDY0NTE5WhcNMjAx" \ + "MjE4MDY0NTE5WjCBhTELMAkGA1UEBhMCcnUxDjAMBgNVBAgMBWlyb2hhMRIwEAYD" \ + "VQQHDAlpbm5vcG9saXMxEjAQBgNVBAoMCXNvcmFtaXRzdTENMAsGA1UECwwEc29y" \ + "YTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxtYWlsQG1haWwu" \ + "cnUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDfpr+Zep0h6LhArU+y" \ + "bInKlTvizt3E+KxtuPgkhDpd3D7PwOnJ0BJhNXPmTcAMfa3Iye6Hg6Dz4tOOKpxX" \ + "2QcYyVjXf0/vvBXf6DsLHHGsq+JHHvDVVTlScPj7Y88dLJukvGZRORYbprTMxxrw" \ + "XV2EXkrsTsLx8zNiXvj0YbO6VtSGQAvdjpOmILwil7HVQnBi4k2wLndl+wDXJD8L" \ + "a89W7lEZPuq454WMRKByGTJOr/xdwAnJdNb0WyIhvTgQiHkZEbpTwaCq5+t/NliR" \ + "ZmFgh2nIFN4FFCiT1uudqNhla42rlU/ElHv4cKcd3EmBVTyLv52ttD7ndMgss4Us" \ + "Znu/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKCyDkLMu6iUMjaggpOfVepA/Fa7" \ + "LETyrf/S2QDb1igGi2Eg5AXquVSoy7pjQvQ7IZvS+wRLWiEoQSYEN8teu7VJcOAY" \ + "f6W7IX0qR8JsqO4TjX4yjZLKPpsqd4twA+voGk9RAejFBYazYMne3phhKjH5vfKD" \ + "m7IiOWPRX6Fg4TDzQHRbzsqlJ0FmTqTXorWybPif1oBcuVHjBHSqXSYULQhAN9cw" \ + "XNB8vpIi7/294k6OH5pZ0+GCPQmR1M3iYH+av12aUb8QtHAxgtxyHui1qeA+hoQw" \ + "InopdaZUbuCd3Y+AvetfGEIo+DlniGbXyeFXFrWRJotITjG7UVc6U/SB6Pg=" \ + "-----END CERTIFICATE-----" +byte_cert = bytes(cert, 'utf-8') +net = IrohaGrpc('{}:{}'.format(IROHA_HOST_ADDR, IROHA_TLS_PORT), secure=None, root_certificates=byte_cert) + + +def trace(func): + """ + A decorator for tracing methods' begin/end execution points + """ + + def tracer(*args, **kwargs): + name = func.__name__ + print('\tEntering "{}"'.format(name)) + result = func(*args, **kwargs) + print('\tLeaving "{}"'.format(name)) + return result + + return tracer + + +@trace +def send_transaction_and_print_status(transaction): + hex_hash = binascii.hexlify(IrohaCrypto.hash(transaction)) + print('Transaction hash = {}, creator = {}'.format( + hex_hash, transaction.payload.reduced_payload.creator_account_id)) + net.send_tx(transaction) + for status in net.tx_status_stream(transaction): + print(status) + + +@trace +def add_coin_to_admin(): + """ + Add 1000.00 units of 'coin#domain' to 'admin@test' + """ + tx = iroha.transaction([ + iroha.command('AddAssetQuantity', + asset_id='coin#domain', amount='1000.00') + ]) + IrohaCrypto.sign_transaction(tx, ADMIN_PRIVATE_KEY) + send_transaction_and_print_status(tx) + + +add_coin_to_admin() diff --git a/iroha/iroha.py b/iroha/iroha.py index 0b0f17ae..12b0c50e 100644 --- a/iroha/iroha.py +++ b/iroha/iroha.py @@ -341,17 +341,27 @@ class IrohaGrpc(object): Possible implementation of gRPC transport to Iroha """ - def __init__(self, address=None, timeout=None, secure=False): + def __init__(self, address=None, timeout=None, secure=False, root_certificates=None, + private_key=None, + certificate_chain=None): """ Create Iroha gRPC client :param address: Iroha Torii address with port, example "127.0.0.1:50051" :param timeout: timeout for network I/O operations in seconds :param secure: enable grpc ssl channel + :param root_certificates: The PEM-encoded root certificates as a byte string, + None for default location chosen by gRPC + :param private_key: The PEM-encoded private key as a byte string, or None if no + private key should be used. + :param certificate_chain: The PEM-encoded certificate chain as a byte string + to use or None if no certificate chain should be used. """ self._address = address if address else '127.0.0.1:50051' if secure: - self._channel = grpc.secure_channel(self._address, grpc.ssl_channel_credentials()) + self._channel = grpc.secure_channel(self._address, + grpc.ssl_channel_credentials(root_certificates, private_key, + certificate_chain)) else: self._channel = grpc.insecure_channel(self._address)