def parse_other_functions(o, otherfuncs, _globals, sigs, external_contracts, origcode, runtime_only=False): sub = ['seq', initializer_lll] add_gas = initializer_lll.gas for _def in otherfuncs: sub.append( parse_func(_def, _globals, { **{ 'self': sigs }, **external_contracts }, origcode)) # noqa E999 sub[-1].total_gas += add_gas add_gas += 30 sig = FunctionSignature.from_definition(_def, external_contracts) sig.gas = sub[-1].total_gas sigs[sig.name] = sig if runtime_only: return sub else: o.append(['return', 0, ['lll', sub, 0]]) return o
def parse_func(code, _globals, sigs, origcode, _custom_units, _vars=None): if _vars is None: _vars = {} sig = FunctionSignature.from_definition(code, sigs=sigs, custom_units=_custom_units) # Check for duplicate variables with globals for arg in sig.args: if arg.name in _globals: raise VariableDeclarationException("Variable name duplicated between function arguments and globals: " + arg.name) # Create a context context = Context(vars=_vars, globals=_globals, sigs=sigs, return_type=sig.output_type, is_constant=sig.const, is_payable=sig.payable, origcode=origcode, custom_units=_custom_units) # Copy calldata to memory for fixed-size arguments copy_size = sum([32 if isinstance(arg.typ, ByteArrayType) else get_size_of_type(arg.typ) * 32 for arg in sig.args]) context.next_mem += copy_size if not len(sig.args): copier = 'pass' elif sig.name == '__init__': copier = ['codecopy', MemoryPositions.RESERVED_MEMORY, '~codelen', copy_size] else: copier = ['calldatacopy', MemoryPositions.RESERVED_MEMORY, 4, copy_size] clampers = [copier] # Add asserts for payable and internal if not sig.payable: clampers.append(['assert', ['iszero', 'callvalue']]) if sig.private: clampers.append(['assert', ['eq', 'caller', 'address']]) # Fill in variable positions for arg in sig.args: clampers.append(make_clamper(arg.pos, context.next_mem, arg.typ, sig.name == '__init__')) if isinstance(arg.typ, ByteArrayType): context.vars[arg.name] = VariableRecord(arg.name, context.next_mem, arg.typ, False) context.next_mem += 32 * get_size_of_type(arg.typ) else: context.vars[arg.name] = VariableRecord(arg.name, MemoryPositions.RESERVED_MEMORY + arg.pos, arg.typ, False) # Create "clampers" (input well-formedness checkers) # Return function body if sig.name == '__init__': o = LLLnode.from_list(['seq'] + clampers + [parse_body(code.body, context)], pos=getpos(code)) else: method_id_node = LLLnode.from_list(sig.method_id, pos=getpos(code), annotation='%s' % sig.name) o = LLLnode.from_list(['if', ['eq', ['mload', 0], method_id_node], ['seq'] + clampers + [parse_body(c, context) for c in code.body] + ['stop'] ], typ=None, pos=getpos(code)) # Check for at leasts one return statement if necessary. if context.return_type and context.function_return_count == 0: raise StructureException( "Missing return statement in function '%s' " % sig.name, code ) o.context = context o.total_gas = o.gas + calc_mem_gas(o.context.next_mem) o.func_name = sig.name return o
def mk_full_signature(code): o = [] _contracts, _events, _defs, _globals, _custom_units = get_contracts_and_defs_and_globals(code) for code in _events: sig = EventSignature.from_declaration(code, custom_units=_custom_units) o.append(sig.to_abi_dict()) for code in _defs: sig = FunctionSignature.from_definition(code, sigs=_contracts, custom_units=_custom_units) if not sig.private: o.append(sig.to_abi_dict()) return o
def parse_external_contracts(external_contracts, _contracts): for _contractname in _contracts: _contract_defs = _contracts[_contractname] _defnames = [_def.name for _def in _contract_defs] contract = {} if len(set(_defnames)) < len(_contract_defs): raise VariableDeclarationException("Duplicate function name: %s" % [name for name in _defnames if _defnames.count(name) > 1][0]) for _def in _contract_defs: sig = FunctionSignature.from_definition(_def) contract[sig.name] = sig external_contracts[_contractname] = contract return external_contracts
def parse_other_functions(o, otherfuncs, _globals, sigs, external_contracts, origcode, _custom_units, fallback_function, runtime_only): sub = ['seq', initializer_lll] add_gas = initializer_lll.gas for _def in otherfuncs: sub.append(parse_func(_def, _globals, {**{'self': sigs}, **external_contracts}, origcode, _custom_units)) # noqa E999 sub[-1].total_gas += add_gas add_gas += 30 sig = FunctionSignature.from_definition(_def, external_contracts, custom_units=_custom_units) sig.gas = sub[-1].total_gas sigs[sig.name] = sig # Add fallback function if fallback_function: fallback_func = parse_func(fallback_function[0], _globals, {**{'self': sigs}, **external_contracts}, origcode, _custom_units) sub.append(fallback_func) else: sub.append(LLLnode.from_list(['revert', 0, 0], typ=None, annotation='Default function')) if runtime_only: return sub else: o.append(['return', 0, ['lll', sub, 0]]) return o
def parse_external_contracts(external_contracts, _contracts): for _contractname in _contracts: _contract_defs = _contracts[_contractname] _defnames = [_def.name for _def in _contract_defs] contract = {} if len(set(_defnames)) < len(_contract_defs): raise FunctionDeclarationException("Duplicate function name: %s" % [name for name in _defnames if _defnames.count(name) > 1][0]) for _def in _contract_defs: constant = False # test for valid call type keyword. if len(_def.body) == 1 and \ isinstance(_def.body[0], ast.Expr) and \ isinstance(_def.body[0].value, ast.Name) and \ _def.body[0].value.id in ('modifying', 'constant'): constant = True if _def.body[0].value.id == 'constant' else False else: raise StructureException('constant or modifying call type must be specified', _def) sig = FunctionSignature.from_definition(_def, contract_def=True, constant=constant) contract[sig.name] = sig external_contracts[_contractname] = contract return external_contracts