Make changes

state_merge
Nikhil Parasaram 5 years ago
parent ab3af1a31d
commit f1cfb614a3
  1. 27
      mythril/laser/ethereum/plugins/implementations/plugin_annotations.py
  2. 39
      mythril/laser/ethereum/plugins/implementations/state_merge.py
  3. 33
      mythril/laser/ethereum/state/world_state.py

@ -1,4 +1,5 @@
from mythril.laser.ethereum.state.annotation import StateAnnotation from mythril.laser.ethereum.state.annotation import StateAnnotation
from mythril.laser.smt import If
from copy import copy from copy import copy
from typing import Dict, List, Set from typing import Dict, List, Set
@ -48,6 +49,20 @@ class DependencyAnnotation(StateAnnotation):
elif value not in self.storage_written[iteration]: elif value not in self.storage_written[iteration]:
self.storage_written[iteration].append(value) self.storage_written[iteration].append(value)
def check_merge_annotation(self, other):
return self.has_call == other.has_call and self.path == other.path
def merge_annotation(self, other: "DependencyAnnotation"):
self.blocks_seen = self.blocks_seen.union(other.blocks_seen)
for v in other.storage_loaded:
if v not in self.storage_loaded:
self.storage_loaded.append(v)
for key, val in other.storage_written.items():
if key not in self.storage_written:
self.storage_written[key] = val
elif self.storage_written[key] != val:
self.storage_written[key] += val
class WSDependencyAnnotation(StateAnnotation): class WSDependencyAnnotation(StateAnnotation):
"""Dependency Annotation for World state """Dependency Annotation for World state
@ -63,3 +78,15 @@ class WSDependencyAnnotation(StateAnnotation):
result = WSDependencyAnnotation() result = WSDependencyAnnotation()
result.annotations_stack = copy(self.annotations_stack) result.annotations_stack = copy(self.annotations_stack)
return result return result
def check_merge_annotation(self, other):
if len(self.annotations_stack) != len(other.annotations_stack):
return False
for a1, a2 in zip(self.annotations_stack, other.annotations_stack):
if a1.check_merge_annotation(a2) is False:
return False
return True
def merge_annotations(self, other):
for a1, a2 in zip(self.annotations_stack, other.annotations_stack):
a1.merge_annotation(a2)

@ -1,5 +1,5 @@
from copy import copy from copy import copy
from typing import List from typing import Dict, List
from mythril.laser.ethereum.svm import LaserEVM from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.plugins.plugin import LaserPlugin from mythril.laser.ethereum.plugins.plugin import LaserPlugin
from mythril.laser.smt import symbol_factory, simplify, Or from mythril.laser.smt import symbol_factory, simplify, Or
@ -33,22 +33,29 @@ class StateMerge(LaserPlugin):
old_states = copy(open_states) old_states = copy(open_states)
while old_size != len(new_states): while old_size != len(new_states):
old_size = len(new_states) old_size = len(new_states)
i = 0
new_states = [] new_states = []
while i < len(old_states) - 1: merged_dict = {} # type: Dict[int, bool]
if self.check_merge_condition(old_states[i], old_states[i + 1]): for i in range(len(old_states)):
new_states.append( if merged_dict.get(i, False):
self.merge_states(old_states[i], old_states[i + 1])
)
i += 2
continue continue
else: i_is_merged = False
for j in range(i + 1, len(old_states)):
if merged_dict.get(j, False) or not self.check_merge_condition(
old_states[i], old_states[j]
):
j += 1
continue
state = old_states[i]
self.merge_states(state, old_states[j])
merged_dict[j] = True
new_states.append(state)
i_is_merged = True
break
if i_is_merged is False:
new_states.append(old_states[i]) new_states.append(old_states[i])
i += 1
if i == len(old_states) - 1:
new_states.append(old_states[i])
old_states = copy(new_states)
old_states = copy(new_states)
logging.info( logging.info(
"States reduced from {} to {}".format(num_old_states, len(new_states)) "States reduced from {} to {}".format(num_old_states, len(new_states))
) )
@ -67,5 +74,11 @@ class StateMerge(LaserPlugin):
@staticmethod @staticmethod
def merge_states(state1: WorldState, state2: WorldState) -> WorldState: def merge_states(state1: WorldState, state2: WorldState) -> WorldState:
"""
Merge state2 into state1
:param state1: The state to be merged into
:param state2: The state which is merged into state1
:return:
"""
state1.merge_states(state2) state1.merge_states(state2)
return state1 return state1

@ -44,8 +44,6 @@ class WorldState:
:param state: The state to be merged with :param state: The state to be merged with
:return: :return:
""" """
# combine annotations
self._annotations += state._annotations
# Merge constraints # Merge constraints
c1 = self.constraints.compress() c1 = self.constraints.compress()
@ -65,10 +63,35 @@ class WorldState:
else: else:
self._accounts[address].merge_accounts(account, c1, self.balances) self._accounts[address].merge_accounts(account, c1, self.balances)
# Merge annotations
self._merge_annotations(state)
# Merge Node # Merge Node
self.node.merge_nodes(state.node, self.constraints) self.node.merge_nodes(state.node, self.constraints)
def check_merge_condition(self, state): def _check_merge_annotations(self, state: "WorldState"):
"""
:param state:
:return:
"""
if len(state.annotations) != len(self._annotations):
return False
for v1, v2 in zip(state.annotations, self._annotations):
if v1.check_merge_annotation(v2) is False: # type: ignore
return False
return True
def _merge_annotations(self, state: "WorldState"):
"""
:param state:
:return:
"""
for v1, v2 in zip(state.annotations, self._annotations):
v1.merge_annotations(v2) # type: ignore
def check_merge_condition(self, state: "WorldState"):
""" """
Checks whether we can merge this state with "state" or not Checks whether we can merge this state with "state" or not
:param state: The state to check the merge-ability with :param state: The state to check the merge-ability with
@ -76,12 +99,16 @@ class WorldState:
""" """
if self.node and not self.node.check_merge_condition(state.node): if self.node and not self.node.check_merge_condition(state.node):
return False return False
for address, account in state.accounts.items(): for address, account in state.accounts.items():
if ( if (
address in self._accounts address in self._accounts
and self._accounts[address].check_merge_condition(account) is False and self._accounts[address].check_merge_condition(account) is False
): ):
return False return False
if not self._check_merge_annotations(state):
return False
return True return True
@property @property

Loading…
Cancel
Save