From cb3ce65dad02c2ad5def8c6e00609b5bfa00fecf Mon Sep 17 00:00:00 2001 From: David Knott Date: Wed, 4 Oct 2017 23:15:54 -0600 Subject: [PATCH] Fix repeated logging with topics --- tests/parser/features/test_logging.py | 31 +++++++++++++++++++++++- viper/parser/parser.py | 34 +++++++++++++-------------- viper/parser/stmt.py | 13 ++++++++-- 3 files changed, 57 insertions(+), 21 deletions(-) diff --git a/tests/parser/features/test_logging.py b/tests/parser/features/test_logging.py index 0bc386b61c..bcdeb163d3 100644 --- a/tests/parser/features/test_logging.py +++ b/tests/parser/features/test_logging.py @@ -70,6 +70,34 @@ def foo(): assert c.translator.decode_event(logs.topics, logs.data) == {'arg1': b'bar', 'arg2': b'home', 'arg3': '0x'+c.address.hex(), '_event_type': b'MyLog'} +def test_logging_the_same_event_multiple_times_with_topics(): + loggy_code = """ +MyLog: __log__({arg1: indexed(num), arg2: indexed(address)}) + +def foo(): + log.MyLog(1, self) + log.MyLog(1, self) + +def bar(): + log.MyLog(1, self) + log.MyLog(1, self) + """ + + c = get_contract(loggy_code) + c.foo() + c.bar() + logs = s.head_state.receipts[-1].logs[-1] + event_id = u.bytes_to_int(u.sha3(bytes('MyLog(int128,address)', 'utf-8'))) + # Event id is always the first topic + assert logs.topics[0] == event_id + # Event id is calculated correctly + assert c.translator.event_data[event_id] + # Event abi is created correctly + assert c.translator.event_data[event_id] == {'types': ['int128','address'], 'name': 'MyLog', 'names': ['arg1','arg2'], 'indexed': [True,True], 'anonymous': False} + # Event is decoded correctly + assert c.translator.decode_event(logs.topics, logs.data) == {'_event_type': b'MyLog', 'arg1': 1, 'arg2': '0x' + c.address.hex()} + + def test_event_logging_cannot_have_more_than_three_topics(): loggy_code = """ MyLog: __log__({arg1: indexed(bytes <= 3), arg2: indexed(bytes <= 4), arg3: indexed(address), arg4: indexed(num)}) @@ -110,7 +138,8 @@ def test_event_loggging_with_fixed_array_data(): def foo(): log.MyLog([1,2], [block.timestamp, block.timestamp+1, block.timestamp+2], [[1,2],[1,2]]) -# """ + log.MyLog([1,2], [block.timestamp, block.timestamp+1, block.timestamp+2], [[1,2],[1,2]]) + """ c = get_contract(loggy_code) c.foo() diff --git a/viper/parser/parser.py b/viper/parser/parser.py index be687e3133..c4a5408bdf 100644 --- a/viper/parser/parser.py +++ b/viper/parser/parser.py @@ -954,23 +954,21 @@ def parse_stmt(stmt, context): return Stmt(stmt, context).lll_node -def pack_logging_topics(event, args, context): - topics = [event.event_id] - stored_topics = ['seq'] +def pack_logging_topics(event_id, args, topics_types, context): + topics = [event_id] topics_count = 1 - for pos, is_indexed in enumerate(event.indexed_list): - if is_indexed: - typ = event.args.pop(pos + 1 - topics_count).typ - arg = args.pop(pos + 1 - topics_count) - topics_count += 1 - if isinstance(arg, ast.Str): - stored_topics.append(parse_value_expr(arg, context)) - topics.append(['mload', stored_topics[-1].to_list()[-1][-1][-1] + 32]) - else: - input = parse_value_expr(arg, context) - input = base_type_conversion(input, input.typ, typ) - topics.append(input) - return topics, stored_topics, event, args + stored_topics = ['seq'] + for pos, typ in enumerate(topics_types): + arg = args[pos] + topics_count += 1 + if isinstance(arg, ast.Str): + stored_topics.append(parse_value_expr(arg, context)) + topics.append(['mload', stored_topics[-1].to_list()[-1][-1][-1] + 32]) + else: + input = parse_value_expr(arg, context) + input = base_type_conversion(input, input.typ, typ) + topics.append(input) + return topics, stored_topics def pack_args_by_32(holder, maxlen, arg, typ, context, placeholder): @@ -998,13 +996,13 @@ def pack_args_by_32(holder, maxlen, arg, typ, context, placeholder): # Pack logging data arguments -def pack_logging_data(signature, args, context): +def pack_logging_data(types, args, context): # Checks to see if there's any data if not args: return ['seq'], 0, 0 holder = ['seq'] maxlen = len(args) * 32 - for i, (arg, typ) in enumerate(zip(args, [arg.typ for arg in signature.args])): + for i, (arg, typ) in enumerate(zip(args, types)): holder, maxlen = pack_args_by_32(holder, maxlen, arg, typ, context, context.new_placeholder(BaseType(32))) return holder, maxlen, holder[1].to_list()[1][0] diff --git a/viper/parser/stmt.py b/viper/parser/stmt.py index 98632ea2f4..99900edde1 100644 --- a/viper/parser/stmt.py +++ b/viper/parser/stmt.py @@ -130,8 +130,17 @@ def call(self): if self.stmt.func.attr not in self.context.sigs['self']: raise VariableDeclarationException("Event not declared yet: %s" % self.stmt.func.attr) event = self.context.sigs['self'][self.stmt.func.attr] - topics, stored_topics, event, data = pack_logging_topics(event, self.stmt.args, self.context) - inargs, inargsize, inarg_start = pack_logging_data(event, data, self.context) + topics_types, topics = [], [] + data_types, data = [], [] + for pos, is_indexed in enumerate(event.indexed_list): + if is_indexed: + topics_types.append(event.args[pos].typ) + topics.append(self.stmt.args[pos]) + else: + data_types.append(event.args[pos].typ) + data.append(self.stmt.args[pos]) + topics, stored_topics = pack_logging_topics(event.event_id, topics, topics_types, self.context) + inargs, inargsize, inarg_start = pack_logging_data(data_types, data, self.context) return LLLnode.from_list(['seq', inargs, stored_topics, ["log" + str(len(topics)), inarg_start, inargsize] + topics], typ=None, pos=getpos(self.stmt)) else: raise StructureException("Unsupported operator: %r" % ast.dump(self.stmt), self.stmt)