app.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. from flask import Flask, request, jsonify
  2. from json import JSONEncoder
  3. # Here are Iroha dependencies.
  4. # Python library generally consists of 3 parts:
  5. # Iroha, IrohaCrypto and IrohaGrpc which we need to import:
  6. import os
  7. import binascii
  8. from iroha import IrohaCrypto
  9. from iroha import Iroha, IrohaGrpc
  10. from werkzeug.wrappers import response
  11. # Here is the information about the environment and admin account information:
  12. IROHA_HOST_ADDR = os.getenv('IROHA_HOST_ADDR', '127.0.0.1')
  13. IROHA_PORT = os.getenv('IROHA_PORT', '50051')
  14. ADMIN_ACCOUNT_ID = os.getenv('ADMIN_ACCOUNT_ID', 'admin@test')
  15. ADMIN_PRIVATE_KEY = os.getenv(
  16. 'ADMIN_PRIVATE_KEY', 'f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70')
  17. # Here we will create user keys
  18. user_private_key = IrohaCrypto.private_key()
  19. user_public_key = IrohaCrypto.derive_public_key(user_private_key)
  20. iroha = Iroha(ADMIN_ACCOUNT_ID)
  21. net = IrohaGrpc('{}:{}'.format(IROHA_HOST_ADDR, IROHA_PORT))
  22. class MyEncoder(JSONEncoder):
  23. def default(self, o):
  24. if isinstance(o, bytes):
  25. return str(o, encoding='utf-8')
  26. return o.__dict__
  27. app = Flask(__name__)
  28. app.json_encoder = MyEncoder
  29. class Asset:
  30. assetId = ""
  31. balance = 0
  32. def __init__(self, assetId = "", balance = 0):
  33. self.assetId = assetId
  34. self.balance = balance
  35. class Assets:
  36. assets = []
  37. class StatefulValidationError:
  38. name = ""
  39. description = ""
  40. solution = ""
  41. def __init__(self, name = "", description = "", solution = ""):
  42. self.name = name
  43. self.description = description
  44. self.solution = solution
  45. transferAssetsValidationErrors = [
  46. StatefulValidationError("Could not transfer asset", "Internal error happened", "Try again or contact developers"),
  47. StatefulValidationError("No such permissions", "Command's creator does not have permission to transfer asset from his account", "Grant the necessary permission"),
  48. StatefulValidationError("No such source account", "Cannot find account with such id to transfer money from", "Make sure source account id is correct"),
  49. StatefulValidationError("No such destination account", "Cannot find account with such id to transfer money to", "Make sure destination account id is correct"),
  50. StatefulValidationError("No such asset found", "Cannot find such asset", "Make sure asset name and precision are correct"),
  51. StatefulValidationError("Not enough balance", "Source account's balance is too low to perform the operation", "Add asset to account or choose lower value to subtract"),
  52. StatefulValidationError("Too much asset to transfer", "Resulting asset quantity of destination account would exceed the allowed maximum", "Make sure that the final destination value is less than 2^256 / 10^asset_precision"),
  53. StatefulValidationError("Too long description", "Too long description", "Ensure that description length matches the criteria above (or just shorten it)")
  54. ]
  55. @app.route("/accounts/<string:accountId>/assets/", methods=['GET'])
  56. def get_account_assets(accountId): #TODO: add validation and error handling
  57. query = iroha.query('GetAccountAssets', account_id=accountId)
  58. IrohaCrypto.sign_query(query, ADMIN_PRIVATE_KEY)
  59. iroha_response = net.send_query(query)
  60. data = iroha_response.account_assets_response.account_assets
  61. response = Assets()
  62. response.assets = []
  63. if len(data) < 1:
  64. return '', 204
  65. for asset in data:
  66. response.assets.append(Asset(asset.asset_id, asset.balance))
  67. return jsonify(response)
  68. @app.route("/assets/transfer/", methods=['POST'])
  69. def transfer_assets():
  70. data = request.get_json()
  71. if data["transfers"] and len(data["transfers"]) > 0:
  72. commands = []
  73. for transfer in data["transfers"]:
  74. commands.append(
  75. iroha.command('TransferAsset', src_account_id = transfer["source"], dest_account_id = transfer["destination"],
  76. asset_id = transfer["asset"], description = transfer["description"], amount = str(transfer["amount"]))
  77. )
  78. transaction = iroha.transaction(commands)
  79. hex_hash = binascii.hexlify(IrohaCrypto.hash(transaction))
  80. IrohaCrypto.sign_transaction(transaction, ADMIN_PRIVATE_KEY)
  81. net.send_tx(transaction)
  82. #TODO speed up status reading
  83. transactionStates = []
  84. for status in net.tx_status_stream(transaction):
  85. transactionStates.append(status)
  86. if(status[0] == "STATEFUL_VALIDATION_SUCCESS"):
  87. break
  88. if(status[0] == "STATEFUL_VALIDATION_FAILED"):
  89. return jsonify({
  90. "transactionHash" : hex_hash,
  91. "error" : transferAssetsValidationErrors[status[2] - 1]
  92. }), 400
  93. #TODO send URL to newly created transaction in Content-Location header
  94. return jsonify({
  95. "transactionHash" : hex_hash,
  96. # "transactionStates" : transactionStates
  97. })