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

import binascii
import json
from datetime import datetime
from pathlib import Path
import pytest
from mythril.disassembler.disassembly import Disassembly
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
from mythril.laser.ethereum.svm import LaserEVM
5 years ago
from mythril.laser.ethereum.time_handler import time_handler
from mythril.laser.ethereum.transaction.concolic import execute_message_call
from mythril.laser.smt import Expression, symbol_factory
from mythril.support.support_args import args
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()
args.unconstrained_storage = False
args.pruning_factor = 1
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 isinstance(actual, bytes):
actual = int(binascii.b2a_hex(actual), 16)
elif isinstance(actual, str):
actual = int(actual, 16)
assert actual == expected