mirror of https://github.com/ConsenSys/mythril
Implement static call (#991)
* Implement static call * Refactor static call tests * Reuse call's post for staticcall * Change variable names and add docstring comments * Rename variable name * change the comment * Fix the tests based on the merge * Fix the tests * Remove extra declaration of WriteProtection * Fix static call test * Add the missing condition in callcodepull/1211/head
parent
00dc912f2c
commit
c55af2a5a0
@ -0,0 +1,124 @@ |
||||
import pytest |
||||
from mock import patch |
||||
|
||||
from mythril.disassembler.disassembly import Disassembly |
||||
from mythril.laser.smt import symbol_factory |
||||
from mythril.laser.ethereum.state.environment import Environment |
||||
from mythril.laser.ethereum.state.account import Account |
||||
from mythril.laser.ethereum.state.machine_state import MachineState |
||||
from mythril.laser.ethereum.state.global_state import GlobalState |
||||
from mythril.laser.ethereum.state.world_state import WorldState |
||||
from mythril.laser.ethereum.instructions import Instruction |
||||
from mythril.laser.ethereum.transaction.transaction_models import MessageCallTransaction |
||||
from mythril.laser.ethereum.call import SymbolicCalldata |
||||
from mythril.laser.ethereum.transaction import TransactionStartSignal |
||||
|
||||
from mythril.laser.ethereum.evm_exceptions import WriteProtection |
||||
|
||||
|
||||
def get_global_state(): |
||||
active_account = Account("0x0", code=Disassembly("60606040")) |
||||
environment = Environment( |
||||
active_account, None, SymbolicCalldata("2"), None, None, None |
||||
) |
||||
world_state = WorldState() |
||||
world_state.put_account(active_account) |
||||
state = GlobalState(world_state, environment, None, MachineState(gas_limit=8000000)) |
||||
state.transaction_stack.append( |
||||
(MessageCallTransaction(world_state=world_state, gas_limit=8000000), None) |
||||
) |
||||
return state |
||||
|
||||
|
||||
@patch( |
||||
"mythril.laser.ethereum.instructions.get_call_parameters", |
||||
return_value=( |
||||
"0", |
||||
Account(code=Disassembly(code="0x00"), address="0x19"), |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
0, |
||||
), |
||||
) |
||||
def test_staticcall(f1): |
||||
# Arrange |
||||
state = get_global_state() |
||||
state.mstate.stack = [10, 10, 10, 10, 10, 10, 10, 10, 0] |
||||
instruction = Instruction("staticcall", dynamic_loader=None) |
||||
|
||||
# Act and Assert |
||||
with pytest.raises(TransactionStartSignal) as ts: |
||||
instruction.evaluate(state) |
||||
assert ts.value.transaction.static |
||||
assert ts.value.transaction.initial_global_state().environment.static |
||||
|
||||
|
||||
test_data = ( |
||||
"suicide", |
||||
"create", |
||||
"create2", |
||||
"log0", |
||||
"log1", |
||||
"log2", |
||||
"log3", |
||||
"log4", |
||||
"sstore", |
||||
) |
||||
|
||||
|
||||
@pytest.mark.parametrize("input", test_data) |
||||
def test_staticness(input): |
||||
# Arrange |
||||
state = get_global_state() |
||||
state.environment.static = True |
||||
state.mstate.stack = [] |
||||
instruction = Instruction(input, dynamic_loader=None) |
||||
|
||||
# Act and Assert |
||||
with pytest.raises(WriteProtection): |
||||
instruction.evaluate(state) |
||||
|
||||
|
||||
test_data_call = ((0, True), (100, False)) |
||||
|
||||
|
||||
@pytest.mark.parametrize("input, success", test_data_call) |
||||
@patch("mythril.laser.ethereum.instructions.get_call_parameters") |
||||
def test_staticness_call_concrete(f1, input, success): |
||||
# Arrange |
||||
state = get_global_state() |
||||
state.environment.static = True |
||||
state.mstate.stack = [] |
||||
code = Disassembly(code="616263") |
||||
f1.return_value = ("0", Account(code=code, address="0x19"), 0, input, 0, 0, 0) |
||||
instruction = Instruction("call", dynamic_loader=None) |
||||
|
||||
# Act and Assert |
||||
if success: |
||||
with pytest.raises(TransactionStartSignal) as ts: |
||||
instruction.evaluate(state) |
||||
assert ts.value.transaction.static |
||||
else: |
||||
with pytest.raises(WriteProtection): |
||||
instruction.evaluate(state) |
||||
|
||||
|
||||
@patch("mythril.laser.ethereum.instructions.get_call_parameters") |
||||
def test_staticness_call_symbolic(f1): |
||||
# Arrange |
||||
state = get_global_state() |
||||
state.environment.static = True |
||||
state.mstate.stack = [] |
||||
call_value = symbol_factory.BitVecSym("x", 256) |
||||
code = Disassembly(code="616263") |
||||
f1.return_value = ("0", Account(code=code, address="0x19"), 0, call_value, 0, 0, 0) |
||||
instruction = Instruction("call", dynamic_loader=None) |
||||
|
||||
# Act and Assert |
||||
with pytest.raises(TransactionStartSignal) as ts: |
||||
instruction.evaluate(state) |
||||
|
||||
assert ts.value.transaction.static |
||||
assert ts.value.global_state.mstate.constraints[-1] == (call_value == 0) |
Loading…
Reference in new issue