def fn2spec(fn): spec = dict() if fn['type'] == 'function': for attr in ("name", "constant", "payable"): spec[attr] = fn[attr] spec['title'] = fn['name'] # to be extended by contract author spec['inputs'] = abi_arguments2schema(fn['inputs']) spec['outputs'] = abi_arguments2schema(fn['outputs']) elif fn['type'] == 'fallback': spec = { 'name': '', 'title': '', 'constant': False, 'payable': fn['payable'], 'inputs': abi_arguments2schema([]), 'outputs': abi_arguments2schema([]) } else: assert False assert_conforms2definition(spec, load_schema('internal/front-back.json'), 'ETHFunctionSpec') return spec
def fn2spec(fn): if obj_type(fn['name']) == 'actions': spec = { 'name': fn['name'], 'title': fn['name'], 'constant': False, 'payable': False, 'inputs': abi_arguments2schema(fn['fields']), 'outputs': abi_arguments2schema([]) } elif obj_type(fn['name']) == 'tables': spec = { 'name': fn['name'], 'title': fn['name'], 'constant': True, 'payable': False, 'inputs': abi_arguments2schema(table_indexes(fn['name'])), 'outputs': abi_arguments2schema(fn['fields']) } else: assert False assert_conforms2definition(spec, load_schema('internal/front-back.json'), 'ETHFunctionSpec') return spec
def merge_function_titles2specs(spec_array, titles_info): """ Attach human-friendly titles and descriptions to passed ETHFunctionSpec list. Processed elements: function titles and descriptions, function input arguments titles and descriptions, titles and descriptions of function outputs. :param spec_array: list of ETHFunctionSpec :param titles_info: data according to function_titles_info.json schema :return: modified ETHFunctionSpec """ assert_conforms2schema_part( titles_info, load_schema('public/constructor.json'), 'definitions/ETHFunctionAdditionalDescriptions') def set_title(to_spec, from_info): # todo how to deduplicate with json schema? # deduplicate with eth fields = ('title', 'description', 'sorting_order', 'ui:widget', 'ui:widget_options', 'payable_details', 'ui:options', 'icon') for field in fields: if field in from_info: to_spec[field] = from_info[field] for spec in spec_array: fn_titles = titles_info.get(spec['name']) if not fn_titles: continue set_title(spec, fn_titles) for io in ('inputs', 'outputs'): if not (io in fn_titles and 'items' in spec[io]): continue for (idx, arg_titles) in enumerate(fn_titles[io]): if idx >= len(spec[io]["items"]): break set_title(spec[io]["items"][idx], arg_titles) # assume that it is ask function, since ask is getting record from special table spec_functions = [x['name'] for x in spec_array] for name, info in titles_info.items(): if name not in spec_functions and not titles_info.get('inputs'): spec_fn = { #todo remove copy paste 'name': name, 'title': '', 'constant': True, 'payable': False, 'inputs': abi_arguments2schema([]), 'outputs': abi_arguments2schema([]) } set_title(spec_fn, info) spec_array.append(spec_fn) return spec_array
def abi_arguments2schema(abi_args_array): """ Конвертация массива аргументов функции контракта в json schema, пригодную для отрисовки и валидации в браузере. :param abi_args_array: массив аргументов функции контракта в формате Ethereum ABI :return: json schema в виде структуры """ def abi_type2schema(abi_type, abi_name=None): if 'bool' == abi_type: result = {"type": "boolean", "default": False} elif abi_type in ( 'account_name', 'name', 'asset', 'uint32', 'uint64', 'checksum256'): # todo why name instead of account_name ? result = {"$ref": "#/definitions/" + abi_type} elif 'string' == abi_type: result = {"type": "string"} elif abi_type.endswith('[]'): result = {"type": "array", "items": abi_type2schema(abi_type[:-2])} else: raise NotImplementedError( 'ABI type is not supported: {}'.format(abi_type)) if abi_name is not None: result['title'] = abi_name return result schema = { "type": "array", "minItems": len(abi_args_array), "maxItems": len(abi_args_array), } if len(abi_args_array) > 0: schema["items"] = [ abi_type2schema(arg['type'], arg.get("name")) for arg in abi_args_array ] return add_definitions(schema, load_schema('public/eos-sc.json')) else: return schema
def merge_function_titles2specs(spec_array, titles_info): """ Attach human-friendly titles and descriptions to passed ETHFunctionSpec list. Processed elements: function titles and descriptions, function input arguments titles and descriptions, titles and descriptions of function outputs. :param spec_array: list of ETHFunctionSpec :param titles_info: data according to function_titles_info.json schema :return: modified ETHFunctionSpec """ assert_conforms2schema_part( titles_info, load_schema('public/constructor.json'), 'definitions/ETHFunctionAdditionalDescriptions') def set_title(to_spec, from_info): # todo how to deduplicate with json schema? fields = ('title', 'description', 'sorting_order', 'ui:widget', 'ui:widget_options', 'payable_details', 'ui:options', 'icon') for field in fields: if field in from_info: to_spec[field] = from_info[field] for spec in spec_array: fn_titles = titles_info.get(spec['name']) if not fn_titles: continue set_title(spec, fn_titles) for io in ('inputs', 'outputs'): if not (io in fn_titles and 'items' in spec[io]): continue for (idx, arg_titles) in enumerate(fn_titles[io]): if idx >= len(spec[io]["items"]): break set_title(spec[io]["items"][idx], arg_titles) return spec_array
def _call_constructor_method(self, source, method, args=None): assert (method in self.CONSTRUCTOR_METHODS) data = { "constructor_file": source, "method": method, "args": args if args is not None else [] } try: res = requests.post(settings.SMARTZ_CONSTRUCTOR_CALL_SERVICE_URL, json=data) if res.status_code != requests.codes.ok: return { "result": "error", "error_descr": "Something got wrong/0" } is_call_valid = is_conforms2schema_part( res.json(), load_schema('internal/call_ctor_service/call-service.json'), 'rpc_calls/call_service/output_{}'.format(method)) if not is_call_valid: return { "result": "error", "error_descr": "Something got wrong/1 (Invalid response from method {} of constructor)" .format(method) } return res.json() except Exception as e: self.logger.warning( "Failed to call constructor method {}: {}".format( method, str(e))) return {"result": "error", "error_descr": "Something got wrong/1"}
def _process_ctor_schema(blockchain: str, schema): assert blockchain in dict( BLOCKCHAINS), "Blockchain {} is not supported".format(blockchain) return add_definitions(schema, load_schema('public/{}-sc.json'.format(blockchain)))
def abi_arguments2schema(abi_args_array): """ Конвертация массива аргументов функции контракта в json schema, пригодную для отрисовки и валидации в браузере. :param abi_args_array: массив аргументов функции контракта в формате Ethereum ABI :return: json schema в виде структуры """ def abi_type2schema(abi_type, abi_name=None): if 'bool' == abi_type: result = {"type": "boolean", "default": False} elif abi_type in ( 'address', 'uint', 'uint256', 'uint8', 'uint16', 'uint32', 'uint64', 'uint128', 'bytes1', 'bytes2', 'bytes3', 'bytes4', 'bytes5', 'bytes6', 'bytes7', 'bytes8', 'bytes9', 'bytes10', 'bytes11', 'bytes12', 'bytes13', 'bytes14', 'bytes15', 'bytes16', 'bytes17', 'bytes18', 'bytes19', 'bytes20', 'bytes21', 'bytes22', 'bytes23', 'bytes24', 'bytes25', 'bytes26', 'bytes27', 'bytes28', 'bytes29', 'bytes30', 'bytes31', 'bytes32', 'bytes', ): result = {"$ref": "#/definitions/" + abi_type} elif 'string' == abi_type: result = {"type": "string"} elif abi_type.endswith('[]'): result = {"type": "array", "items": abi_type2schema(abi_type[:-2])} else: raise NotImplementedError( 'ABI type is not supported: {}'.format(abi_type)) if abi_name is not None: result['title'] = abi_name return result schema = { "type": "array", "minItems": len(abi_args_array), "maxItems": len(abi_args_array), } if len(abi_args_array) > 0: schema["items"] = [ abi_type2schema(arg['type'], arg.get("name")) for arg in abi_args_array ] return add_definitions(schema, load_schema('public/ethereum-sc.json')) else: return schema
def _prepare_instance_details(dapp: Dapp) -> Dict: output = dapp_pub_info(dapp) assert_conforms2schema_part(output, load_schema('internal/front-back.json'), 'rpc_calls/get_instance_details/output') return output