def decode_single(typ, data): base, sub, _ = typ if base == 'address': return encode_hex(data[12:]) elif base == 'hash': return data[32 - int(sub):] elif base == 'string' or base == 'bytes': if len(sub): return data[:int(sub)] else: l = big_endian_to_int(data[0:32]) return data[32:][:l] elif base == 'uint': return big_endian_to_int(data) elif base == 'int': o = big_endian_to_int(data) return (o - 2 ** int(sub)) if o >= 2 ** (int(sub) - 1) else o elif base == 'ufixed': high, low = [int(x) for x in sub.split('x')] return big_endian_to_int(data) * 1.0 // 2 ** low elif base == 'fixed': high, low = [int(x) for x in sub.split('x')] o = big_endian_to_int(data) i = (o - 2 ** (high + low)) if o >= 2 ** (high + low - 1) else o return (i * 1.0 // 2 ** low) elif base == 'bool': return bool(int(encode_hex(data), 16))
def _encode_function(self, signature, param_values): prefix = utils.big_endian_to_int(utils.sha3(signature)[:4]) if signature.find('(') == -1: raise RuntimeError('Invalid function signature. Missing "(" and/or ")"...') if signature.find(')') - signature.find('(') == 1: return utils.encode_int(prefix) types = signature[signature.find('(') + 1: signature.find(')')].split(',') encoded_params = encode_abi(types, param_values) return utils.zpad(utils.encode_int(prefix), 4) + encoded_params
def dec(typ, arg): base, sub, arrlist = typ sz = get_size(typ) # Dynamic-sized strings are encoded as <len(str)> + <str> if base in ('string', 'bytes') and not sub: L = big_endian_to_int(arg[:32]) assert len(arg[32:]) == ceil32(L), "Wrong data size for string/bytes object" return arg[32:][:L] # Dynamic-sized arrays elif sz is None: L = big_endian_to_int(arg[:32]) subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) # If children are dynamic, use the head/tail mechanism. Fortunately, # here the code is simpler since we do not have to worry about # mixed dynamic and static children, as we do in the top-level multi-arg # case if subsize is None: assert len(arg) >= 32 + 32 * L, "Not enough data for head" start_positions = [big_endian_to_int(arg[32 + 32 * i: 64 + 32 * i]) for i in range(L)] + [len(arg)] outs = [arg[start_positions[i]: start_positions[i + 1]] for i in range(L)] return [dec(subtyp, out) for out in outs] # If children are static, then grab the data slice for each one and # sequentially decode them manually else: return [dec(subtyp, arg[32 + subsize * i: 32 + subsize * (i + 1)]) for i in range(L)] # Static-sized arrays: decode piece-by-piece elif len(arrlist): L = arrlist[-1][0] subtyp = base, sub, arrlist[:-1] subsize = get_size(subtyp) return [dec(subtyp, arg[subsize * i:subsize * (i + 1)]) for i in range(L)] else: return decode_single(typ, arg)
def _encode_function(self, signature, param_values): prefix = utils.big_endian_to_int(utils.sha3(signature)[:4]) if signature.find('(') == -1: raise RuntimeError( 'Invalid function signature. Missing "(" and/or ")"...') if signature.find(')') - signature.find('(') == 1: return utils.encode_int(prefix) types = signature[signature.find('(') + 1:signature.find(')')].split(',') encoded_params = encode_abi(types, param_values) return utils.zpad(utils.encode_int(prefix), 4) + encoded_params
def decint(n, signed=False): # pylint: disable=invalid-name,too-many-branches ''' Decode an unsigned/signed integer. ''' if isinstance(n, str): n = utils.to_string(n) if n is True: return 1 if n is False: return 0 if n is None: return 0 if is_numeric(n): if signed: if not -TT255 <= n <= TT255 - 1: raise EncodingError('Number out of range: %r' % n) else: if not 0 <= n <= TT256 - 1: raise EncodingError('Number out of range: %r' % n) return n if is_string(n): if len(n) > 32: raise EncodingError('String too long: %r' % n) if len(n) == 40: int_bigendian = decode_hex(n) else: int_bigendian = n # pylint: disable=redefined-variable-type result = big_endian_to_int(int_bigendian) if signed: if result >= TT255: result -= TT256 if not -TT255 <= result <= TT255 - 1: raise EncodingError('Number out of range: %r' % n) else: if not 0 <= result <= TT256 - 1: raise EncodingError('Number out of range: %r' % n) return result raise EncodingError('Cannot decode integer: %r' % n)
def decode_abi(types, data): # Process types proctypes = [process_type(typ) for typ in types] # Get sizes of everything sizes = [get_size(typ) for typ in proctypes] # Initialize array of outputs outs = [None] * len(types) # Initialize array of start positions start_positions = [None] * len(types) + [len(data)] # If a type is static, grab the data directly, otherwise record # its start position pos = 0 for i, typ in enumerate(types): if sizes[i] is None: start_positions[i] = big_endian_to_int(data[pos:pos + 32]) j = i - 1 while j >= 0 and start_positions[j] is None: start_positions[j] = start_positions[i] j -= 1 pos += 32 else: outs[i] = data[pos:pos + sizes[i]] pos += sizes[i] # We add a start position equal to the length of the entire data # for convenience. j = len(types) - 1 while j >= 0 and start_positions[j] is None: start_positions[j] = start_positions[len(types)] j -= 1 assert pos <= len(data), "Not enough data for head" # Grab the data for tail arguments using the start positions # calculated above for i, typ in enumerate(types): if sizes[i] is None: offset = start_positions[i] next_offset = start_positions[i + 1] outs[i] = data[offset:next_offset] # Recursively decode them all return [dec(proctypes[i], outs[i]) for i in range(len(outs))]
def event_id(name, encode_types): """ Return the event id. Defined as: `keccak(EVENT_NAME+"("+EVENT_ARGS.map(canonical_type_of).join(",")+")")` Where `canonical_type_of` is a function that simply returns the canonical type of a given argument, e.g. for uint indexed foo, it would return uint256). Note the lack of spaces. """ event_types = [ _canonical_type(type_) for type_ in encode_types ] event_signature = '{event_name}({canonical_types})'.format( event_name=name, canonical_types=','.join(event_types), ) return big_endian_to_int(utils.sha3(event_signature))
def method_id(name, encode_types): """ Return the unique method id. The signature is defined as the canonical expression of the basic prototype, i.e. the function name with the parenthesised list of parameter types. Parameter types are split by a single comma - no spaces are used. The method id is defined as the first four bytes (left, high-order in big-endian) of the Keccak (SHA-3) hash of the signature of the function. """ function_types = [ _canonical_type(type_) for type_ in encode_types ] function_signature = '{function_name}({canonical_types})'.format( function_name=name, canonical_types=','.join(function_types), ) function_keccak = utils.sha3(function_signature) first_bytes = function_keccak[:4] return big_endian_to_int(first_bytes)