def encode_param_array(self, args, param_entity): if len(args) == 0: raise Exception('Empty arrays not allowed.') first_arg_type = type(args[0]) for arg in args: if type(arg) != first_arg_type: raise Exception('Array arguments are not of same type.') resolved_type = utils.resolve_type(param_entity['type'], self.aliases) elem_type, array_sizes = utils.factorize_array_type_str(resolved_type) if not utils.check_array(args, elem_type, array_sizes): raise Exception('Array check failed for "{}".'.format( param_entity['type'])) res_buff = [] for arg in utils.flatten_array(args, param_entity['name'], resolved_type): res_buff.append( self.encode_param(arg['value'], { 'name': arg['name'], 'type': arg['type'] })) return ''.join(res_buff)
def build_type_classes(desc): # TODO: Type class constructors shold accept primitive types like ints and bytes where applicable. # They also should accept lists. struct_classes = build_struct_classes(desc) alias_classes = dict() aliases = desc['alias'] if 'alias' in desc else [] final_type_resolver = build_type_resolver(aliases) for alias in aliases: alias_name = alias['name'] final_type = final_type_resolver(alias_name) if utils.is_struct_type(final_type): struct_name = utils.get_struct_name_by_type(final_type) def constructor(self, struct_obj): # TODO: Solve recursion problem with calling super constructor. # For now value is set manualy. #super(self.__class__, self).__init__(struct_obj) assert isinstance(struct_obj, dict) self.value = struct_obj self.type_str = alias_name self._type_resolver = final_type_resolver self.bind() alias_class_atribs = dict() alias_class_atribs['__init__'] = constructor alias_classes[alias_name] = type(alias_name, (struct_classes[struct_name],), alias_class_atribs) elif utils.is_array_type(final_type): elem_type_name, _ = utils.factorize_array_type_str(final_type) if elem_type_name in types.BASIC_SCRYPT_TYPES: alias_classes[alias_name] = list() elif utils.is_struct_type(elem_type_name): struct_name = utils.get_struct_name_by_type(elem_type_name) alias_classes[alias_name] = list() else: if final_type in types.BASIC_SCRYPT_TYPES: def constructor(self, struct_obj): # TODO: Solve recursion problem with calling super constructor. # For now value is set manualy. #super(self.__class__, self).__init__(struct_obj) assert isinstance(struct_obj, dict) self.value = struct_obj self.type_str = alias_name self._type_resolver = final_type_resolver self.bind() alias_class_atribs = dict() alias_class_atribs['__init__'] = constructor alias_classes[alias_name] = type(alias_name, (types.BASIC_SCRYPT_TYPES[final_type],), alias_class_atribs) else: raise Exception('Could not resolve alias "{}" for type "{}".'.format(alias_name, alias['type'])) return {**alias_classes, **struct_classes}
def resolver_func(alias): if utils.is_struct_type(alias): alias = utils.get_struct_name_by_type(alias) array_type = '' if utils.is_array_type(alias): elem_type_name, sizes = utils.factorize_array_type_str(alias) if utils.is_struct_type(elem_type_name): alias = utils.get_struct_name_by_type(elem_type_name) else: alias = elem_type_name array_type_buff = [] for size in sizes: array_type_buff.append('[{}]'.format(size)) array_type = ''.join(array_type_buff) if alias in types.BASIC_SCRYPT_TYPES: return '{}{}'.format(alias, array_type) if alias in resolved_types: return '{}{}'.format(resolved_types[alias], array_type) return 'struct {} {{}}{}'.format(alias, array_type)
def resolve_array_type_w_const_int(contract_name, type_str, static_int_consts): # Resolves array declaration string with static constants as sizes. # e.g. 'int[N][2]' -> 'int[5][2]' elem_type_name, array_sizes = utils.factorize_array_type_str(type_str) # Resolve all constants to integers. sizes = [] for size_str in array_sizes: if size_str.isdigit(): sizes.append(int(size_str)) else: if size_str.find('.') > 0: sizes.append(static_int_consts[size_str]) else: sizes.append(static_int_consts['{}.{}'.format( contract_name, size_str)]) return utils.to_literal_array_type(elem_type_name, sizes)
def resolve_abi_param_type(contract_name, type_str, aliases, static_int_consts): if utils.is_array_type(type_str): resolved_type = CompilerWrapper.resolve_array_type_w_const_int( contract_name, type_str, static_int_consts) else: resolved_type = utils.resolve_type(type_str, aliases) if utils.is_struct_type(resolved_type): return utils.get_struct_name_by_type(resolved_type) elif utils.is_array_type(resolved_type): elem_type_name, array_sizes = utils.factorize_array_type_str( resolved_type) if utils.is_struct_type(elem_type_name): elem_type_name = utils.get_struct_name_by_type(resolved_type) return utils.to_literal_array_type(elem_type_name, array_sizes) return resolved_type
def get_ls_code_part(self, contract, hex_script, *args): abi_constructor = self.abi_constructor() c_params = abi_constructor.get('params', []) if len(args) != len(c_params): raise Exception('Wrong number of arguments passed to constructor. ' \ 'Expected {}, but got {}.'.format(len(c_params), len(args))) _c_params = [] _args = [] for idx, param in enumerate(c_params): arg = args[idx] arg = utils.primitives_to_scrypt_types(arg) resolved_type = utils.resolve_type(param['type'], self.aliases) is_param_statefull = param['state'] if utils.is_array_type(resolved_type): elem_type, array_sizes = utils.factorize_array_type_str( resolved_type) if not utils.check_array(arg, elem_type, array_sizes): raise Exception( 'Constructors parameter with index {} should be array of type "{}".' .format(idx, resolved_type)) flattened_arr = utils.flatten_array(arg, param['name'], resolved_type) for obj in flattened_arr: _c_params.append({ 'name': obj['name'], 'type': obj['type'], 'state': is_param_statefull }) _args.append(obj['value']) elif utils.is_struct_type(resolved_type): if arg.final_type != resolved_type: raise Exception('Constructors parameter with index {} should be struct of type "{}". ' \ 'Got struct of type "{}" instead.'.format(idx, param['type'], arg.type_str)) flattened_struct = utils.flatten_struct(arg, param['name']) for obj in flattened_struct: _c_params.append({ 'name': obj['name'], 'type': obj['type'], 'state': is_param_statefull }) _args.append(obj['value']) else: _c_params.append(param) _args.append(arg) if is_param_statefull: # If a statefull variable, set the passed value as a member of the contract object. setattr(contract, param['name'], arg) finalized_hex_script = hex_script for idx, param in enumerate(_c_params): if not '<{}>'.format(param['name']) in hex_script: raise Exception( 'Missing "{}" contract constructor parameter in passed args.' .format(param['name'])) param_regex = re.compile( escape_str_for_regex('<{}>'.format(param['name']))) if param['state']: # State variables need only a placeholder value as they will get replaced during script execution. #finalized_hex_script = re.sub(param_regex, '0100', finalized_hex_script) finalized_hex_script = re.sub( param_regex, self.encode_param(_args[idx], param), finalized_hex_script) else: finalized_hex_script = re.sub( param_regex, self.encode_param(_args[idx], param), finalized_hex_script) finalized_hex_script = re.sub('<__codePart__>', '00', finalized_hex_script) # Replace inline assembly variable placeholders in locking script with the actual arguments. # TODO: Check if each value is instance of ScryptType if contract.inline_asm_vars: for key, val in contract.inline_asm_vars.items(): param_regex = re.compile( escape_str_for_regex('<{}>'.format(key))) finalized_hex_script = re.sub(param_regex, val.hex, finalized_hex_script) return Script.from_hex(finalized_hex_script)
def get_ls_data_part(self, contract, custom_vals_dict=None, first_call=None): abi_constructor = self.abi_constructor() c_params = abi_constructor.get('params', []) state_buff = [] first_call = first_call if first_call is not None else contract.first_call if first_call: state_buff.append('01') else: state_buff.append('00') for param in c_params: if not param['state']: continue param_name = param['name'] resolved_type = utils.resolve_type(param['type'], self.aliases) if custom_vals_dict: val = custom_vals_dict[param_name] else: val = getattr(contract, param_name, None) if not val: raise Exception( 'Statefull variable "{}" has no value.'.format( param_name)) val = utils.primitives_to_scrypt_types(val) # Do type checking. if utils.is_array_type(resolved_type): elem_type, array_sizes = utils.factorize_array_type_str( resolved_type) if not utils.check_array(val, elem_type, array_sizes): raise Exception( 'Statefull variable "{}" should be array of type "{}".' .format(param_name, resolved_type)) elif utils.is_struct_type(resolved_type): if val.final_type != resolved_type: raise Exception('Statefull variable "{}" should be struct of type "{}". ' \ 'Got struct of type "{}" instead.'.format(param_name, param['type'], val.type_str)) else: if val.final_type != resolved_type: raise Exception('Statefull variable "{}" should be of type "{}". ' \ 'Got object of type "{}" instead.'.format(param_name, param['type'], val.type_str)) state_buff.append(serializer.serialize(val).hex()) # State length and state version. state_len = 0 for elem in state_buff: state_len += len(elem) // 2 if state_len > 0: size_bytes = state_len.to_bytes(4, 'little') state_buff.append(size_bytes.hex()) state_buff.append( CONTRACT_STATE_VERSION.to_bytes(1, 'little').hex()) return Script.from_hex(''.join(state_buff))