From 52ba355b657f34c11dd405057a76e46ac8fb9bab Mon Sep 17 00:00:00 2001 From: e-ngo Date: Thu, 8 Aug 2019 23:30:52 -0700 Subject: [PATCH] Add logic for CREATE opcode, still need to add unit test for CREATE. Refactored extcodehash unit tests into separate test units. --- mythril/laser/ethereum/gas.py | 5 +-- mythril/laser/ethereum/instructions.py | 42 ++++++++++++++++++++++---- tests/instructions/extcodehash_test.py | 34 ++++++++++++--------- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/mythril/laser/ethereum/gas.py b/mythril/laser/ethereum/gas.py index 7e283d15..4d8de488 100644 --- a/mythril/laser/ethereum/gas.py +++ b/mythril/laser/ethereum/gas.py @@ -180,10 +180,7 @@ OPCODE_GAS = { "LOG3": (4 * 375, 4 * 375 + 8 * 32), "LOG4": (5 * 375, 5 * 375 + 8 * 32), "CREATE": (32000, 32000), - "CREATE2": ( - 32000, - 32000, - ), # TODO: The gas value is dynamic, to be done while implementing create2 + "CREATE2": (32000, 32000), # TODO: Make the gas value is dynamic "CALL": (700, 700 + 9000 + 25000), "NATIVE_COST": calculate_native_gas, "CALLCODE": (700, 700 + 9000 + 25000), diff --git a/mythril/laser/ethereum/instructions.py b/mythril/laser/ethereum/instructions.py index 1c663ded..35e98e0c 100644 --- a/mythril/laser/ethereum/instructions.py +++ b/mythril/laser/ethereum/instructions.py @@ -1605,12 +1605,42 @@ class Instruction: :param global_state: :return: """ - # TODO: implement me - state = global_state.mstate - state.stack.pop(), state.stack.pop(), state.stack.pop() - # Not supported - state.stack.append(0) - return [global_state] + mstate = global_state.mstate + environment = global_state.environment + world_state = global_state.world_state + + call_value, mem_offset, mem_size = ( + mstate.stack.pop(), + mstate.stack.pop(), + mstate.stack.pop(), + ) + + try: + call_data = mstate.memory[ + util.get_concrete_int(mem_offset) : util.get_concrete_int( + mem_offset + mem_size + ) + ] + except TypeError: + log.debug("Create with symbolic length or offset. Not supported") + + caller = environment.sender + gas_price = environment.gasprice + origin = environment.origin + transaction = ContractCreationTransaction( + world_state=world_state, + caller=caller, + call_data=call_data, + gas_price=gas_price, + origin=origin, + call_value=call_value, + ) + + contract_address = transaction.callee_account.address + + mstate.stack.append(contract_address) + + raise TransactionStartSignal(transaction, self.op_code) @StateTransition() def create2_(self, global_state: GlobalState) -> List[GlobalState]: diff --git a/tests/instructions/extcodehash_test.py b/tests/instructions/extcodehash_test.py index e1ea30c1..14f2ad65 100644 --- a/tests/instructions/extcodehash_test.py +++ b/tests/instructions/extcodehash_test.py @@ -11,33 +11,37 @@ from mythril.support.support_utils import get_code_hash from mythril.laser.smt import symbol_factory +# Arrange +world_state = WorldState() +account = world_state.create_account(balance=10, address=101) +account.code = Disassembly("60606040") +world_state.create_account(balance=10, address=1000) +environment = Environment(account, None, None, None, None, None) +og_state = GlobalState(world_state, environment, None, MachineState(gas_limit=8000000)) +og_state.transaction_stack.append( + (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) +) -def test_extcodehash_concrete(): - # Arrange - world_state = WorldState() - account = world_state.create_account(balance=10, address=101) - account.code = Disassembly("60606040") - world_state.create_account(balance=10, address=1000) - environment = Environment(account, None, None, None, None, None) - og_state = GlobalState( - world_state, environment, None, MachineState(gas_limit=8000000) - ) - og_state.transaction_stack.append( - (MessageCallTransaction(world_state=WorldState(), gas_limit=8000000), None) - ) - - instruction = Instruction("extcodehash", dynamic_loader=None) +instruction = Instruction("extcodehash", dynamic_loader=None) + + +def test_extcodehash_no_account(): # If account does not exist, return 0 og_state.mstate.stack = [symbol_factory.BitVecVal(1, 256)] new_state = instruction.evaluate(og_state)[0] assert new_state.mstate.stack[-1] == 0 + +def test_extcodehash_no_code(): + # If account code does not exist, return hash of empty set. og_state.mstate.stack = [symbol_factory.BitVecVal(1000, 256)] new_state = instruction.evaluate(og_state)[0] assert hex(new_state.mstate.stack[-1].value) == get_code_hash("") + +def test_extcodehash_return_hash(): # If account code exists, return hash of the code. og_state.mstate.stack = [symbol_factory.BitVecVal(101, 256)] new_state = instruction.evaluate(og_state)[0]