|
|
@@ -1,12 +1,14 @@
|
|
|
-from flask import Flask, json, request, jsonify
|
|
|
+from flask import Flask, request, jsonify
|
|
|
from json import JSONEncoder
|
|
|
|
|
|
# Here are Iroha dependencies.
|
|
|
# Python library generally consists of 3 parts:
|
|
|
# Iroha, IrohaCrypto and IrohaGrpc which we need to import:
|
|
|
import os
|
|
|
+import binascii
|
|
|
from iroha import IrohaCrypto
|
|
|
from iroha import Iroha, IrohaGrpc
|
|
|
+from werkzeug.wrappers import response
|
|
|
|
|
|
# Here is the information about the environment and admin account information:
|
|
|
IROHA_HOST_ADDR = os.getenv('IROHA_HOST_ADDR', '127.0.0.1')
|
|
|
@@ -23,7 +25,9 @@ net = IrohaGrpc('{}:{}'.format(IROHA_HOST_ADDR, IROHA_PORT))
|
|
|
|
|
|
|
|
|
class MyEncoder(JSONEncoder):
|
|
|
- def default(self, o):
|
|
|
+ def default(self, o):
|
|
|
+ if isinstance(o, bytes):
|
|
|
+ return str(o, encoding='utf-8')
|
|
|
return o.__dict__
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
@@ -40,6 +44,27 @@ class Asset:
|
|
|
class Assets:
|
|
|
assets = []
|
|
|
|
|
|
+class StatefulValidationError:
|
|
|
+ name = ""
|
|
|
+ description = ""
|
|
|
+ solution = ""
|
|
|
+
|
|
|
+ def __init__(self, name = "", description = "", solution = ""):
|
|
|
+ self.name = name
|
|
|
+ self.description = description
|
|
|
+ self.solution = solution
|
|
|
+
|
|
|
+transferAssetsValidationErrors = [
|
|
|
+ StatefulValidationError("Could not transfer asset", "Internal error happened", "Try again or contact developers"),
|
|
|
+ StatefulValidationError("No such permissions", "Command's creator does not have permission to transfer asset from his account", "Grant the necessary permission"),
|
|
|
+ StatefulValidationError("No such source account", "Cannot find account with such id to transfer money from", "Make sure source account id is correct"),
|
|
|
+ StatefulValidationError("No such destination account", "Cannot find account with such id to transfer money to", "Make sure destination account id is correct"),
|
|
|
+ StatefulValidationError("No such asset found", "Cannot find such asset", "Make sure asset name and precision are correct"),
|
|
|
+ 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"),
|
|
|
+ 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"),
|
|
|
+ StatefulValidationError("Too long description", "Too long description", "Ensure that description length matches the criteria above (or just shorten it)")
|
|
|
+]
|
|
|
+
|
|
|
@app.get("/accounts/<string:accountId>/assets/")
|
|
|
def get_account_assets(accountId): #TODO: add validation and error handling
|
|
|
|
|
|
@@ -58,4 +83,43 @@ def get_account_assets(accountId): #TODO: add validation and error handling
|
|
|
for asset in data:
|
|
|
response.assets.append(Asset(asset.asset_id, asset.balance))
|
|
|
|
|
|
- return jsonify(response)
|
|
|
+ return jsonify(response)
|
|
|
+
|
|
|
+@app.post("/assets/transfer/")
|
|
|
+def transfer_assets():
|
|
|
+ data = request.get_json()
|
|
|
+
|
|
|
+ if data["transfers"] and len(data["transfers"]) > 1:
|
|
|
+ commands = []
|
|
|
+
|
|
|
+ for transfer in data["transfers"]:
|
|
|
+ commands.append(
|
|
|
+ iroha.command('TransferAsset', src_account_id = transfer["source"], dest_account_id = transfer["destination"],
|
|
|
+ asset_id = transfer["asset"], description = transfer["description"], amount = str(transfer["amount"]))
|
|
|
+ )
|
|
|
+
|
|
|
+ transaction = iroha.transaction(commands)
|
|
|
+ hex_hash = binascii.hexlify(IrohaCrypto.hash(transaction))
|
|
|
+
|
|
|
+ IrohaCrypto.sign_transaction(transaction, ADMIN_PRIVATE_KEY)
|
|
|
+ net.send_tx(transaction)
|
|
|
+
|
|
|
+ #TODO speed up status reading
|
|
|
+ transactionStates = []
|
|
|
+ for status in net.tx_status_stream(transaction):
|
|
|
+ transactionStates.append(status)
|
|
|
+
|
|
|
+ if(status[0] == "STATEFUL_VALIDATION_SUCCESS"):
|
|
|
+ break
|
|
|
+
|
|
|
+ if(status[0] == "STATEFUL_VALIDATION_FAILED"):
|
|
|
+ return jsonify({
|
|
|
+ "transactionHash" : hex_hash,
|
|
|
+ "error" : transferAssetsValidationErrors[status[2] - 1]
|
|
|
+ }), 400
|
|
|
+
|
|
|
+ #TODO send URL to newly created transaction in Content-Location header
|
|
|
+ return jsonify({
|
|
|
+ "transactionHash" : hex_hash,
|
|
|
+ # "transactionStates" : transactionStates
|
|
|
+ })
|