|
|
|
@ -28,7 +28,7 @@ class LaserEVM: |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
def __init__(self, accounts, dynamic_loader=None, max_depth=float('inf'), execution_timeout=60, create_timeout=10, |
|
|
|
|
strategy=DepthFirstSearchStrategy): |
|
|
|
|
strategy=DepthFirstSearchStrategy, max_transaction_count=3): |
|
|
|
|
world_state = WorldState() |
|
|
|
|
world_state.accounts = accounts |
|
|
|
|
# this sets the initial world state |
|
|
|
@ -45,6 +45,7 @@ class LaserEVM: |
|
|
|
|
self.work_list = [] |
|
|
|
|
self.strategy = strategy(self.work_list, max_depth) |
|
|
|
|
self.max_depth = max_depth |
|
|
|
|
self.max_transaction_count = max_transaction_count |
|
|
|
|
|
|
|
|
|
self.execution_timeout = execution_timeout |
|
|
|
|
self.create_timeout = create_timeout |
|
|
|
@ -77,19 +78,30 @@ class LaserEVM: |
|
|
|
|
|
|
|
|
|
# Reset code coverage |
|
|
|
|
self.coverage = {} |
|
|
|
|
self.time = datetime.now() |
|
|
|
|
logging.info("Starting message call transaction") |
|
|
|
|
execute_message_call(self, created_account.address) |
|
|
|
|
for i in range(self.max_transaction_count): |
|
|
|
|
initial_coverage = self._get_covered_instructions() |
|
|
|
|
|
|
|
|
|
self.time = datetime.now() |
|
|
|
|
logging.info("Starting message call transaction, iteration: {}".format(i)) |
|
|
|
|
execute_message_call(self, created_account.address) |
|
|
|
|
|
|
|
|
|
end_coverage = self._get_covered_instructions() |
|
|
|
|
if end_coverage == initial_coverage: |
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
logging.info("Finished symbolic execution") |
|
|
|
|
logging.info("%d nodes, %d edges, %d total states", len(self.nodes), len(self.edges), self.total_states) |
|
|
|
|
for code, coverage in self.coverage.items(): |
|
|
|
|
cov = reduce(lambda sum_, val: sum_ + 1 if val else sum_, coverage[1]) / float(coverage[0]) * 100 |
|
|
|
|
logging.info("Achieved {} coverage for code: {}".format(cov, code)) |
|
|
|
|
|
|
|
|
|
def _get_covered_instructions(self) -> int: |
|
|
|
|
""" Gets the total number of covered instructions for all accounts in the svm""" |
|
|
|
|
total_covered_instructions = 0 |
|
|
|
|
for _, cv in self.coverage.items(): |
|
|
|
|
total_covered_instructions += reduce(lambda sum_, val: sum_ + 1 if val else sum_, cv[1]) |
|
|
|
|
return total_covered_instructions |
|
|
|
|
|
|
|
|
|
def exec(self, create=False): |
|
|
|
|
for global_state in self.strategy: |
|
|
|
|
if self.execution_timeout and not create: |
|
|
|
@ -138,30 +150,31 @@ class LaserEVM: |
|
|
|
|
new_global_states = self._end_message_call(return_global_state, global_state, |
|
|
|
|
revert_changes=True, return_data=None) |
|
|
|
|
|
|
|
|
|
except TransactionStartSignal as e: |
|
|
|
|
except TransactionStartSignal as start_signal: |
|
|
|
|
# Setup new global state |
|
|
|
|
new_global_state = e.transaction.initial_global_state() |
|
|
|
|
new_global_state = start_signal.transaction.initial_global_state() |
|
|
|
|
|
|
|
|
|
new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(e.transaction, global_state)] |
|
|
|
|
new_global_state.transaction_stack = copy(global_state.transaction_stack) + [(start_signal.transaction, global_state)] |
|
|
|
|
new_global_state.node = global_state.node |
|
|
|
|
new_global_state.mstate.constraints = global_state.mstate.constraints |
|
|
|
|
|
|
|
|
|
return [new_global_state], op_code |
|
|
|
|
|
|
|
|
|
except TransactionEndSignal as e: |
|
|
|
|
transaction, return_global_state = e.global_state.transaction_stack.pop() |
|
|
|
|
except TransactionEndSignal as end_signal: |
|
|
|
|
transaction, return_global_state = end_signal.global_state.transaction_stack.pop() |
|
|
|
|
|
|
|
|
|
if return_global_state is None: |
|
|
|
|
if not isinstance(transaction, ContractCreationTransaction) or transaction.return_data: |
|
|
|
|
e.global_state.world_state.node = global_state.node |
|
|
|
|
self.open_states.append(e.global_state.world_state) |
|
|
|
|
if (not isinstance(transaction, ContractCreationTransaction) or transaction.return_data) and not end_signal.revert: |
|
|
|
|
end_signal.global_state.world_state.node = global_state.node |
|
|
|
|
self.open_states.append(end_signal.global_state.world_state) |
|
|
|
|
new_global_states = [] |
|
|
|
|
else: |
|
|
|
|
# First execute the post hook for the transaction ending instruction |
|
|
|
|
self._execute_post_hook(op_code, [e.global_state]) |
|
|
|
|
self._execute_post_hook(op_code, [end_signal.global_state]) |
|
|
|
|
|
|
|
|
|
new_global_states = self._end_message_call(return_global_state, global_state, |
|
|
|
|
revert_changes=False, return_data=transaction.return_data) |
|
|
|
|
revert_changes=False or end_signal.revert, |
|
|
|
|
return_data=transaction.return_data) |
|
|
|
|
|
|
|
|
|
self._execute_post_hook(op_code, new_global_states) |
|
|
|
|
|
|
|
|
@ -252,7 +265,7 @@ class LaserEVM: |
|
|
|
|
environment.active_function_name = disassembly.addr_to_func[address] |
|
|
|
|
new_node.flags |= NodeFlags.FUNC_ENTRY |
|
|
|
|
|
|
|
|
|
logging.info( |
|
|
|
|
logging.debug( |
|
|
|
|
"- Entering function " + environment.active_account.contract_name + ":" + new_node.function_name) |
|
|
|
|
elif address == 0: |
|
|
|
|
environment.active_function_name = "fallback" |
|
|
|
|