From 18e7d3afe56663edd64a4af8f909850d3611d4c7 Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Thu, 30 Apr 2015 09:47:32 +0700 Subject: [PATCH 1/3] encode_abi failed in python3 due to non-bytestrings, sha3 also required utf-8 string to be encoded before hashing --- ethereum/abi.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ethereum/abi.py b/ethereum/abi.py index a3a10cfdb..f5ab4a1f9 100644 --- a/ethereum/abi.py +++ b/ethereum/abi.py @@ -32,6 +32,7 @@ def __init__(self, full_signature): " name. Use %s to call %s with types %r" % (name, sig_item['name'], encode_types)) sig = name + '(' + ','.join(encode_types) + ')' + sig = sig.encode('utf-8') if sig_item['type'] == 'function': prefix = big_endian_to_int(utils.sha3(sig)[:4]) decode_types = [f['type'] for f in sig_item['outputs']] @@ -118,7 +119,7 @@ def decint(n): # Encodes a base type def encode_single(arg, base, sub): - normal_args, len_args, var_args = '', '', '' + normal_args, len_args, var_args = b'', b'', b'' # Unsigned integers: uint if base == 'uint': sub = int(sub) @@ -234,12 +235,12 @@ def encode_any(arg, base, sub, arrlist): if base == 'string' and sub == '': raise Exception('Array of dynamic-sized items not allowed: %r' % arg) - o = '' + o = b'' assert isinstance(arg, list), "Expecting array: %r" % arg for a in arg: _, n, _ = encode_any(a, base, sub, arrlist[:-1]) o += n - return zpad(encode_int(len(arg)), 32), '', o + return zpad(encode_int(len(arg)), 32), b'', o # Fixed-sized arrays else: if base == 'string' and sub == '': @@ -247,18 +248,18 @@ def encode_any(arg, base, sub, arrlist): sz = int(arrlist[-1][1:-1]) assert isinstance(arg, list), "Expecting array: %r" % arg assert sz == len(arg), "Wrong number of elements in array: %r" % arg - o = '' + o = b'' for a in arg: _, n, _ = encode_any(a, base, sub, arrlist[:-1]) o += n - return '', o, '' + return b'', o, b'' # Encodes ABI data given a prefix, a list of types, and a list of arguments def encode_abi(types, args): - len_args = '' - normal_args = '' - var_args = '' + len_args = b'' + normal_args = b'' + var_args = b'' if len(types) != len(args): raise Exception("Wrong number of arguments!") for typ, arg in zip(types, args): From 4d0e73dcfc400373aa5d88d209aa00dca8a14626 Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Thu, 30 Apr 2015 13:38:01 +0700 Subject: [PATCH 2/3] bytes strings everywhere --- ethereum/abi.py | 79 +++++++++++++++++++++++----------------------- ethereum/tester.py | 4 ++- 2 files changed, 42 insertions(+), 41 deletions(-) diff --git a/ethereum/abi.py b/ethereum/abi.py index f5ab4a1f9..beab142c5 100644 --- a/ethereum/abi.py +++ b/ethereum/abi.py @@ -21,8 +21,8 @@ def __init__(self, full_signature): for sig_item in full_signature: encode_types = [f['type'] for f in sig_item['inputs']] name = sig_item['name'] - if '(' in name: - name = name[:name.find('(')] + if b'(' in name: + name = name[:name.find(b'(')] if name in v: i = 2 while name + utils.to_string(i) in v: @@ -31,9 +31,8 @@ def __init__(self, full_signature): sys.stderr.write("Warning: multiple methods with the same " " name. Use %s to call %s with types %r" % (name, sig_item['name'], encode_types)) - sig = name + '(' + ','.join(encode_types) + ')' - sig = sig.encode('utf-8') - if sig_item['type'] == 'function': + sig = name + b'(' + b','.join(encode_types) + b')' + if sig_item['type'] == b'function': prefix = big_endian_to_int(utils.sha3(sig)[:4]) decode_types = [f['type'] for f in sig_item['outputs']] is_unknown_type = len(sig_item['outputs']) and \ @@ -44,7 +43,7 @@ def __init__(self, full_signature): "decode_types": decode_types, "is_unknown_type": is_unknown_type } - elif sig_item['type'] == 'event': + elif sig_item['type'] == b'event': prefix = big_endian_to_int(utils.sha3(sig)) indexed = [f['indexed'] for f in sig_item['inputs']] names = [f['name'] for f in sig_item['inputs']] @@ -121,30 +120,30 @@ def decint(n): def encode_single(arg, base, sub): normal_args, len_args, var_args = b'', b'', b'' # Unsigned integers: uint - if base == 'uint': + if base == b'uint': sub = int(sub) i = decint(arg) assert 0 <= i < 2**sub, "Value out of bounds: %r" % arg normal_args = zpad(encode_int(i), 32) # Signed integers: int - elif base == 'int': + elif base == b'int': sub = int(sub) i = decint(arg) assert -2**(sub - 1) <= i < 2**sub, "Value out of bounds: %r" % arg normal_args = zpad(encode_int(i % 2**sub), 32) # Unsigned reals: urealx - elif base == 'ureal': + elif base == b'ureal': high, low = [int(x) for x in sub.split('x')] assert 0 <= arg < 2**high, "Value out of bounds: %r" % arg normal_args = zpad(encode_int(arg * 2**low), 32) # Signed reals: realx - elif base == 'real': + elif base == b'real': high, low = [int(x) for x in sub.split('x')] assert -2**(high - 1) <= arg < 2**(high - 1), \ "Value out of bounds: %r" % arg normal_args = zpad(encode_int((arg % 2**high) * 2**low), 32) # Strings - elif base == 'string': + elif base == b'string': if not is_string(arg): raise Exception("Expecting string: %r" % arg) # Fixed length: string @@ -157,7 +156,7 @@ def encode_single(arg, base, sub): len_args = zpad(encode_int(len(arg)), 32) var_args = arg # Hashes: hash - elif base == 'hash': + elif base == b'hash': assert int(sub) and int(sub) <= 32 if isinstance(arg, int): normal_args = zpad(encode_int(arg), 32) @@ -168,8 +167,8 @@ def encode_single(arg, base, sub): else: raise Exception("Could not parse hash: %r" % arg) # Addresses: address (== hash160) - elif base == 'address': - assert sub == '' + elif base == b'address': + assert sub == b'' if isinstance(arg, int): normal_args = zpad(encode_int(arg), 32) elif len(arg) == 20: @@ -184,43 +183,43 @@ def encode_single(arg, base, sub): def process_type(typ): # Crazy reg expression to separate out base type component (eg. uint), # size (eg. 256, 128x128, none), array component (eg. [], [45], none) - regexp = '([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)' + regexp = b'([a-z]*)([0-9]*x?[0-9]*)((\[[0-9]*\])*)' base, sub, arr, _ = re.match(regexp, typ).groups() - arrlist = re.findall('\[[0-9]*\]', arr) - assert len(''.join(arrlist)) == len(arr), \ + arrlist = re.findall(b'\[[0-9]*\]', arr) + assert len(b''.join(arrlist)) == len(arr), \ "Unknown characters found in array declaration" # Only outermost array can be var-sized for a in arrlist[:-1]: assert len(a) > 2, "Inner arrays must have fixed size" # Check validity of string type - if base == 'string': - assert re.match('^[0-9]*$', sub), \ + if base == b'string': + assert re.match(b'^[0-9]*$', sub), \ "String type must have no suffix or numerical suffix" assert len(sub) or len(arrlist) == 0, \ "Cannot have an array of var-sized strings" # Check validity of integer type - elif base == 'uint' or base == 'int': - assert re.match('^[0-9]+$', sub), \ + elif base == b'uint' or base == b'int': + assert re.match(b'^[0-9]+$', sub), \ "Integer type must have numerical suffix" assert 8 <= int(sub) <= 256, \ "Integer size out of bounds" assert int(sub) % 8 == 0, \ "Integer size must be multiple of 8" # Check validity of real type - elif base == 'ureal' or base == 'real': - assert re.match('^[0-9]+x[0-9]+$', sub), \ + elif base == b'ureal' or base == b'real': + assert re.match(b'^[0-9]+x[0-9]+$', sub), \ "Real type must have suffix of form x, eg. 128x128" - high, low = [int(x) for x in sub.split('x')] + high, low = [int(x) for x in sub.split(b'x')] assert 8 <= (high + low) <= 256, \ "Real size out of bounds (max 32 bytes)" assert high % 8 == 0 and low % 8 == 0, \ "Real high/low sizes must be multiples of 8" # Check validity of hash type - elif base == 'hash': - assert re.match('^[0-9]+$', sub), \ + elif base == b'hash': + assert re.match(b'^[0-9]+$', sub), \ "Hash type must have numerical suffix" # Check validity of address type - elif base == 'address': + elif base == b'address': assert sub == '', "Address cannot have suffix" return base, sub, arrlist @@ -232,7 +231,7 @@ def encode_any(arg, base, sub, arrlist): return encode_single(arg, base, sub) # Variable-sized arrays if arrlist[-1] == '[]': - if base == 'string' and sub == '': + if base == b'string' and sub == b'': raise Exception('Array of dynamic-sized items not allowed: %r' % arg) o = b'' @@ -243,7 +242,7 @@ def encode_any(arg, base, sub, arrlist): return zpad(encode_int(len(arg)), 32), b'', o # Fixed-sized arrays else: - if base == 'string' and sub == '': + if base == b'string' and sub == b'': raise Exception('Array of dynamic-sized items not allowed') sz = int(arrlist[-1][1:-1]) assert isinstance(arg, list), "Expecting array: %r" % arg @@ -273,11 +272,11 @@ def encode_abi(types, args): def is_varsized(base, sub, arrlist): return (len(arrlist) and arrlist[-1] == '[]') or \ - (base == 'string' and sub == '') + (base == b'string' and sub == b'') def getlen(base, sub, arrlist): - if base == 'string' and not len(sub): + if base == b'string' and not len(sub): sz = 1 else: sz = 32 @@ -288,22 +287,22 @@ def getlen(base, sub, arrlist): def decode_single(data, base, sub): - if base == 'address': + if base == b'address': return encode_hex(data[12:]) - elif base == 'string' or base == 'hash': + elif base == b'string' or base == b'hash': return data[:int(sub)] if len(sub) else data - elif base == 'uint': + elif base == b'uint': return big_endian_to_int(data) - elif base == 'int': + elif base == b'int': o = big_endian_to_int(data) return (o - 2**int(sub)) if o >= 2**(int(sub) - 1) else o - elif base == 'ureal': - high, low = [int(x) for x in sub.split('x')] + elif base == b'ureal': + high, low = [int(x) for x in sub.split(b'x')] return big_endian_to_int(data) * 1.0 / 2**low - elif base == 'real': - high, low = [int(x) for x in sub.split('x')] + elif base == b'real': + high, low = [int(x) for x in sub.split(b'x')] return (big_endian_to_int(data) * 1.0 / 2**low) % 2**high - elif base == 'bool': + elif base == b'bool': return bool(int(data.encode('hex'), 16)) diff --git a/ethereum/tester.py b/ethereum/tester.py index a0fc16eb4..e25c8378d 100644 --- a/ethereum/tester.py +++ b/ethereum/tester.py @@ -122,6 +122,7 @@ def kall_factory(f): def kall(*args, **kwargs): _state.block.log_listeners.append( lambda log: self._translator.listen(log)) + o = _state._send(kwargs.get('sender', k0), self.address, kwargs.get('value', 0), @@ -146,7 +147,7 @@ def kall(*args, **kwargs): return kall for f in self._translator.function_data: - vars(self)[f] = kall_factory(f) + vars(self)[f.decode('utf-8')] = kall_factory(f) return _abi_contract(me, code, sender, endowment, language) @@ -175,6 +176,7 @@ def _send(self, sender, to, value, evmdata='', output=None, " the abi_contract mechanism") tm, g = time.time(), self.block.gas_used sendnonce = self.block.get_nonce(u.privtoaddr(sender)) + tx = t.Transaction(sendnonce, 1, gas_limit, to, value, evmdata) self.last_tx = tx tx.sign(sender) From 0cd29fe7c08f273c7a9f93b290791eb3e41ef1e1 Mon Sep 17 00:00:00 2001 From: Jarrad Hope Date: Fri, 1 May 2015 15:34:27 +0700 Subject: [PATCH 3/3] append_str test --- ethereum/tests/test_contracts.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ethereum/tests/test_contracts.py b/ethereum/tests/test_contracts.py index 760011355..d59f91c44 100644 --- a/ethereum/tests/test_contracts.py +++ b/ethereum/tests/test_contracts.py @@ -1423,6 +1423,17 @@ def test_string_manipulation(): assert c.t1() == [97, 98] +append_string_code = """ +def append_str(a): + return(a + "a") +""" + +def test_append_string(): + s = tester.state() + c = s.abi_contract(append_string_code) + assert c.append_str(b"test") == b"testa" + + more_infinite_storage_object_code = """ data block[2^256](_blockHeader(_prevBlock))