Security analysis tool for EVM bytecode. Supports smart contracts built for Ethereum, Hedera, Quorum, Vechain, Roostock, Tron and other EVM-compatible blockchains.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mythril/tests/laser/evm_testsuite/evm_test.py

189 lines
6.3 KiB

from mythril.laser.ethereum.svm import LaserEVM
from mythril.laser.ethereum.state.account import Account
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
from mythril.laser.ethereum.state.world_state import WorldState
5 years ago
from mythril.laser.ethereum.time_handler import time_handler
from mythril.laser.ethereum.function_managers import keccak_function_manager
from mythril.disassembler.disassembly import Disassembly
from mythril.laser.ethereum.transaction.concolic import execute_message_call
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
from mythril.laser.smt import Expression, BitVec, symbol_factory
from datetime import datetime
6 years ago
import binascii
import json
import os
from pathlib import Path
import pytest
from z3 import ExprRef, simplify
evm_test_dir = Path(__file__).parent / "VMTests"
6 years ago
test_types = [
"vmArithmeticTest",
"vmBitwiseLogicOperation",
"vmEnvironmentalInfo",
"vmPushDupSwapTest",
"vmTests",
"vmSha3Test",
"vmSystemOperations",
6 years ago
"vmRandomTest",
"vmIOandFlowOperations",
]
tests_with_gas_support = ["gas0", "gas1"]
tests_with_block_number_support = [
"BlockNumberDynamicJumpi0",
"BlockNumberDynamicJumpi1",
6 years ago
"BlockNumberDynamicJump0_jumpdest2",
"DynamicJumpPathologicalTest0",
"BlockNumberDynamicJumpifInsidePushWithJumpDest",
"BlockNumberDynamicJumpiAfterStop",
"BlockNumberDynamicJumpifInsidePushWithoutJumpDest",
"BlockNumberDynamicJump0_jumpdest0",
"BlockNumberDynamicJumpi1_jumpdest",
"BlockNumberDynamicJumpiOutsideBoundary",
"DynamicJumpJD_DependsOnJumps1",
]
6 years ago
tests_with_log_support = ["log1MemExp"]
tests_not_relevent = [
"loop_stacklimit_1020", # We won't be looping till 1020 as we have a max_depth
"loop_stacklimit_1021",
]
tests_to_resolve = ["jumpTo1InstructionafterJump", "sstore_load_2", "jumpi_at_the_end"]
ignored_test_names = (
6 years ago
tests_with_gas_support
+ tests_with_log_support
+ tests_with_block_number_support
+ tests_with_block_number_support
+ tests_not_relevent
+ tests_to_resolve
)
def load_test_data(designations):
"""
:param designations:
:return:
"""
return_data = []
for designation in designations:
for file_reference in (evm_test_dir / designation).iterdir():
with file_reference.open() as file:
top_level = json.load(file)
for test_name, data in top_level.items():
pre_condition = data["pre"]
action = data["exec"]
gas_before = int(action["gas"], 16)
gas_after = data.get("gas")
gas_used = (
gas_before - int(gas_after, 16)
if gas_after is not None
else None
)
post_condition = data.get("post", {})
environment = data.get("env")
return_data.append(
(
test_name,
environment,
pre_condition,
action,
gas_used,
post_condition,
)
)
return return_data
@pytest.mark.parametrize(
"test_name, environment, pre_condition, action, gas_used, post_condition",
load_test_data(test_types),
)
def test_vmtest(
test_name: str,
environment: dict,
pre_condition: dict,
action: dict,
gas_used: int,
post_condition: dict,
) -> None:
6 years ago
# Arrange
if test_name in ignored_test_names:
return
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
world_state = WorldState()
for address, details in pre_condition.items():
account = Account(address, concrete_storage=True)
account.code = Disassembly(details["code"][2:])
account.nonce = int(details["nonce"], 16)
6 years ago
for key, value in details["storage"].items():
6 years ago
key_bitvec = symbol_factory.BitVecVal(int(key, 16), 256)
account.storage[key_bitvec] = symbol_factory.BitVecVal(int(value, 16), 256)
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
world_state.put_account(account)
account.set_balance(int(details["balance"], 16))
5 years ago
time_handler.start_execution(10000)
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
laser_evm = LaserEVM()
laser_evm.open_states = [world_state]
# Act
laser_evm.time = datetime.now()
6 years ago
final_states = execute_message_call(
laser_evm,
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
callee_address=symbol_factory.BitVecVal(int(action["address"], 16), 256),
caller_address=symbol_factory.BitVecVal(int(action["caller"], 16), 256),
origin_address=symbol_factory.BitVecVal(int(action["origin"], 16), 256),
code=action["code"][2:],
gas_limit=int(action["gas"], 16),
data=binascii.a2b_hex(action["data"][2:]),
gas_price=int(action["gasPrice"], 16),
value=int(action["value"], 16),
track_gas=True,
)
# Assert
if gas_used is not None and gas_used < int(environment["currentGasLimit"], 16):
# avoid gas usage larger than block gas limit
# this currently exceeds our estimations
gas_min_max = [
(s.mstate.min_gas_used, s.mstate.max_gas_used) for s in final_states
]
gas_ranges = [g[0] <= gas_used for g in gas_min_max]
assert all(map(lambda g: g[0] <= g[1], gas_min_max))
assert any(gas_ranges)
if post_condition == {}:
# no more work to do if error happens or out of gas
assert len(laser_evm.open_states) == 0
else:
assert len(laser_evm.open_states) == 1
world_state = laser_evm.open_states[0]
for address, details in post_condition.items():
Balance modelling and symbolic sender variables (#1025) * add actor address to symbolic This will allow us to simulate semi-symbolic transaction senders * add value transfer to transaction global state creation * add proper balance tracking to world state and account * use address value vs string * disable actor address variable * use address directly * allow balance functions with int types * use value as getters since bitvecs aren't hashable * implement correct value transfer for suicide * use actor from actor pool * allow use of Or with *arg pattern * use bitvec instead of strings * add dynamic balance implementation to state datamodels * cleanup svm interface * use balance lambda in suicide op implementation * use bitvec instead of string address * update world state and account creation in symbolic * update tests to include overflow results * apply style rules * ignore previous open states for now * update native test to conform to new laser interface * fix incorrect types in the symbolic virtual machine * allow multiple types as input for address in account * fix type hint in symbolic.py * get int out of string in call * fix type in call op implementation * adapt test_transaction to conform to new laser interface * use static address to keep contracts from trying to enter themselves and make address type more dynamic * update evm test to conform to new laser interface * implement suicide to uncreated account * apply style rules * dynamically create colormap This removes the need for a globally maintained accountlist * get value out of address * add accounts getter * change symbolic test call to be valid with respect to the world state and account apis * remove dependency on globally recorded accounts * fix typing issues * fix type annotations in symbolic.py * fix remaining mypy warnings * simplify assertion check * execute lambda to get balance * make variable name plural * add documentation to svm constructor * use list comprehension to make code cleaner * remove comment * change variable name to plural * remove commented code * change variable name to conform to changed interface
6 years ago
account = world_state[symbol_factory.BitVecVal(int(address, 16), 256)]
assert account.nonce == int(details["nonce"], 16)
assert account.code.bytecode == details["code"][2:]
for index, value in details["storage"].items():
expected = int(value, 16)
6 years ago
actual = account.storage[symbol_factory.BitVecVal(int(index, 16), 256)]
if isinstance(actual, Expression):
actual = actual.value
actual = 1 if actual is True else 0 if actual is False else actual
else:
if type(actual) == bytes:
actual = int(binascii.b2a_hex(actual), 16)
elif type(actual) == str:
actual = int(actual, 16)
assert actual == expected