From 0f458e7541f6118d64089c403d6bbb3fe1e881b2 Mon Sep 17 00:00:00 2001 From: Konrad Weiss Date: Wed, 13 Jun 2018 11:33:30 +0200 Subject: [PATCH] Add the first code to build transaction traces from the storage state at STOP instruction and a combination strategy to build felxibly large trace chain combinations. Starting from the trace of a constructor and using the traces of the external and public functions of a contract. All possible programmstates to a certain depth can be reached. --- mythril/analysis/modules/build_traces.py | 22 ++++++++++ mythril/solidnotary.py | 27 ++++++++++++ mythril/solidnotary/transactiontrace.py | 54 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 mythril/solidnotary/transactiontrace.py diff --git a/mythril/analysis/modules/build_traces.py b/mythril/analysis/modules/build_traces.py index e69de29b..d20dae21 100644 --- a/mythril/analysis/modules/build_traces.py +++ b/mythril/analysis/modules/build_traces.py @@ -0,0 +1,22 @@ +from mythril.analysis.report import Issue +import logging + + +''' + Build execution traces from the statespace +''' + +def print_obj(obj): + print() + print(obj) + # print(dir(obj)) + print() + + +def execute(statespace): + + logging.debug("Executing module: Transaction End") + + traces = [] + + return [] diff --git a/mythril/solidnotary.py b/mythril/solidnotary.py index e69de29b..2207b26f 100644 --- a/mythril/solidnotary.py +++ b/mythril/solidnotary.py @@ -0,0 +1,27 @@ +import logging +from mythril.solidnotary.transactiontrace import TransactionTrace + +class SolidNotary: + + def __init__(self): + # Todo Parse Annotations and store them in an additional structure + # Todo receive a list of files or a file, these are modified for the analysis + pass + + def notarize(self): + # Todo Instantiate an instance of Mythril, analyze and print the result + # Todo Find how they are storing results + pass + + def get_transaction_traces(statespace): + logging.debug("Executing module: Transaction End") + + traces = [] + + for k in statespace.nodes: + node = statespace.nodes[k] + for state in node.states: + instruction = state.get_current_instruction() + if instruction['opcode'] == "STOP": + traces.append(TransactionTrace(state.environment.active_account.storage)) + return traces diff --git a/mythril/solidnotary/transactiontrace.py b/mythril/solidnotary/transactiontrace.py new file mode 100644 index 00000000..cee4b6de --- /dev/null +++ b/mythril/solidnotary/transactiontrace.py @@ -0,0 +1,54 @@ +class TransactionTrace: + + def __init__(self, storage): + self.storage = storage + # Todo Identifiy addional trace information such as blocknumber and more + + """ + Applies the new trace tt on a possibly even changed trace self. + """ + def apply_trace(self, tt): + if tt is None: + return self + # Todo implement application of a trace on a existing trace. + return None + + def apply_traces_parallel(self, traces): + combined_traces = [] + for trace in traces: + combined_traces.append(self.apply_trace(trace)) + return combined_traces + + def apply_exact_trace_levels(self, traces, depth): + # Todo maybe some faster trace build not building one level at a time to e.g. + # Todo reach level 17 but build 2, then 4, then 8 and then 16 then 17 + trace_lvl_n = [self] + for i in range(depth): + trace_lvl_np1 = [] + for trace in trace_lvl_n: + trace_lvl_np1.append(trace.apply_traces_parallel(traces)) + if deep_equals(trace_lvl_np1, trace_lvl_n): # Fixpoint detected, function needs to ignore lists, dicts and objects. + return trace_lvl_n + trace_lvl_n = trace_lvl_np1 + return trace_lvl_n + + def apply_up_to_trace_levels(self, traces, depth): + traces_up_to = [[self]] # elements are trace_levels + for i in range(depth): + trace_lvl_np1 = [] + for trace in traces_up_to[-1]: + trace_lvl_np1.append(trace.apply_traces_parallel(traces)) + for trace_lvl_i in traces_up_to: + # the following might be faster to check when using a content representing hash + if deep_equals(trace_lvl_np1, trace_lvl_i): # cycle in the traces of trace chains detected: levels + # while repeat themselves, function needs to ignore lists, dicts and objects. + return traces_up_to + traces_up_to.append(trace_lvl_np1) + return traces_up_to + + """ + Either do only deep checing here and use the proper trace or storage_slot reduction in the apply function. Or do + both here. + """ + def deep_equals(trace_lvl1, trace_lvl2): + pass