Support Istanbul fork (#1292)

* Add new opcodes

* Add new precompile

* Add tests

* Refactor the code

* Run only on python 3.6

* Remove support of python3.5 from setup.py text

* Change the TODO comment

* Add a logging message

* Fix py-evm version

Co-authored-by: JoranHonig <JoranHonig@users.noreply.github.com>
pull/1329/head
Nikhil Parasaram 5 years ago committed by GitHub
parent 3be2b4b4aa
commit f3c45c153e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      mythril/laser/ethereum/call.py
  2. 8
      mythril/laser/ethereum/instruction_data.py
  3. 21
      mythril/laser/ethereum/instructions.py
  4. 22
      mythril/laser/ethereum/natives.py
  5. 3
      mythril/laser/ethereum/state/environment.py
  6. 2
      mythril/support/opcodes.py
  7. 1
      requirements.txt
  8. 4
      setup.py
  9. 42
      tests/laser/Precompiles/test_blake2.py
  10. 2
      tox.ini

@ -265,6 +265,7 @@ def native_call(
global_state.mstate.min_gas_used += native_gas_min global_state.mstate.min_gas_used += native_gas_min
global_state.mstate.max_gas_used += native_gas_max global_state.mstate.max_gas_used += native_gas_max
global_state.mstate.mem_extend(mem_out_start, mem_out_sz) global_state.mstate.mem_extend(mem_out_start, mem_out_sz)
try: try:
data = natives.native_contracts(call_address_int, call_data) data = natives.native_contracts(call_address_int, call_data)
except natives.NativeContractException: except natives.NativeContractException:

@ -48,7 +48,7 @@ OPCODES = {
STACK: BIN_OPERATOR_TUPLE, STACK: BIN_OPERATOR_TUPLE,
}, },
"ADDRESS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "ADDRESS": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"BALANCE": {GAS: (400, 400), STACK: UN_OPERATOR_TUPLE}, "BALANCE": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE},
"ORIGIN": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "ORIGIN": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "CALLER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CALLVALUE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "CALLVALUE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
@ -69,7 +69,7 @@ OPCODES = {
GAS: (700, 700 + 3 * 768), # https://ethereum.stackexchange.com/a/47556 GAS: (700, 700 + 3 * 768), # https://ethereum.stackexchange.com/a/47556
STACK: (4, 0), STACK: (4, 0),
}, },
"EXTCODEHASH": {GAS: (400, 400), STACK: UN_OPERATOR_TUPLE}, "EXTCODEHASH": {GAS: (700, 700), STACK: UN_OPERATOR_TUPLE},
"RETURNDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "RETURNDATASIZE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"RETURNDATACOPY": {GAS: (3, 3), STACK: (3, 0)}, "RETURNDATACOPY": {GAS: (3, 3), STACK: (3, 0)},
"BLOCKHASH": {GAS: (20, 20), STACK: UN_OPERATOR_TUPLE}, "BLOCKHASH": {GAS: (20, 20), STACK: UN_OPERATOR_TUPLE},
@ -78,13 +78,15 @@ OPCODES = {
"NUMBER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "NUMBER": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"DIFFICULTY": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "DIFFICULTY": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"GASLIMIT": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE}, "GASLIMIT": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"CHAINID": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"SELFBALANCE": {GAS: (2, 2), STACK: Z_OPERATOR_TUPLE},
"POP": {GAS: (2, 2), STACK: (1, 0)}, "POP": {GAS: (2, 2), STACK: (1, 0)},
# assume 1KB memory r/w cost as upper bound # assume 1KB memory r/w cost as upper bound
"MLOAD": {GAS: (3, 96), STACK: UN_OPERATOR_TUPLE}, "MLOAD": {GAS: (3, 96), STACK: UN_OPERATOR_TUPLE},
"MSTORE": {GAS: (3, 98), STACK: (2, 0)}, "MSTORE": {GAS: (3, 98), STACK: (2, 0)},
"MSTORE8": {GAS: (3, 98), STACK: (2, 0)}, "MSTORE8": {GAS: (3, 98), STACK: (2, 0)},
# assume 64 byte r/w cost as upper bound # assume 64 byte r/w cost as upper bound
"SLOAD": {GAS: (400, 400), STACK: UN_OPERATOR_TUPLE}, "SLOAD": {GAS: (800, 800), STACK: UN_OPERATOR_TUPLE},
"SSTORE": {GAS: (5000, 25000), STACK: (1, 0)}, "SSTORE": {GAS: (5000, 25000), STACK: (1, 0)},
"JUMP": {GAS: (8, 8), STACK: (1, 0)}, "JUMP": {GAS: (8, 8), STACK: (1, 0)},
"JUMPI": {GAS: (10, 10), STACK: (2, 0)}, "JUMPI": {GAS: (10, 10), STACK: (2, 0)},

@ -929,6 +929,27 @@ class Instruction:
state.stack.append(environment.sender) state.stack.append(environment.sender)
return [global_state] return [global_state]
@StateTransition()
def chainid_(self, global_state: GlobalState) -> List[GlobalState]:
"""
:param global_state:
:return:
"""
global_state.mstate.stack.append(global_state.environment.chainid)
return [global_state]
@StateTransition()
def selfbalance_(self, global_state: GlobalState) -> List[GlobalState]:
"""
:param global_state:
:return:
"""
balance = global_state.environment.active_account.balance()
global_state.mstate.stack.append(balance)
return [global_state]
@StateTransition() @StateTransition()
def codesize_(self, global_state: GlobalState) -> List[GlobalState]: def codesize_(self, global_state: GlobalState) -> List[GlobalState]:
""" """

@ -2,13 +2,17 @@
import hashlib import hashlib
import logging import logging
from typing import List, Union import blake2b
from typing import List
from ethereum.utils import ecrecover_to_pub from ethereum.utils import ecrecover_to_pub
from py_ecc.secp256k1 import N as secp256k1n from py_ecc.secp256k1 import N as secp256k1n
import py_ecc.optimized_bn128 as bn128 import py_ecc.optimized_bn128 as bn128
from rlp.utils import ALL_BYTES from rlp.utils import ALL_BYTES
from eth_utils import ValidationError
from eth._utils.blake2.coders import extract_blake2b_parameters
from mythril.laser.ethereum.state.calldata import BaseCalldata, ConcreteCalldata from mythril.laser.ethereum.state.calldata import BaseCalldata, ConcreteCalldata
from mythril.laser.ethereum.util import extract_copy, extract32 from mythril.laser.ethereum.util import extract_copy, extract32
from ethereum.utils import ( from ethereum.utils import (
@ -192,6 +196,20 @@ def ec_pair(data: List[int]) -> List[int]:
return [0] * 31 + [1 if result else 0] return [0] * 31 + [1 if result else 0]
def blake2b_fcompress(data: List[int]) -> List[int]:
"""
blake2b hashing
:param data:
:return:
"""
try:
parameters = extract_blake2b_parameters(bytes(data))
except ValidationError as v:
logging.debug("Invalid blake2b params: {}".format(v))
return []
return list(bytearray(blake2b.compress(*parameters)))
PRECOMPILE_FUNCTIONS = ( PRECOMPILE_FUNCTIONS = (
ecrecover, ecrecover,
sha256, sha256,
@ -201,7 +219,9 @@ PRECOMPILE_FUNCTIONS = (
ec_add, ec_add,
ec_mul, ec_mul,
ec_pair, ec_pair,
blake2b_fcompress,
) )
PRECOMPILE_COUNT = len(PRECOMPILE_FUNCTIONS) PRECOMPILE_COUNT = len(PRECOMPILE_FUNCTIONS)

@ -41,7 +41,10 @@ class Environment:
self.active_function_name = "" self.active_function_name = ""
self.address = active_account.address self.address = active_account.address
# TODO: Add tx_2 > tx_1 then block_no(tx_2) > block_no(tx_1)
self.block_number = symbol_factory.BitVecSym("block_number", 256) self.block_number = symbol_factory.BitVecSym("block_number", 256)
self.chainid = symbol_factory.BitVecSym("chain_id", 256)
# Ib # Ib
self.code = active_account.code if code is None else code self.code = active_account.code if code is None else code

@ -51,6 +51,8 @@ opcodes = {
0x43: ("NUMBER", 0, 1, 2), 0x43: ("NUMBER", 0, 1, 2),
0x44: ("DIFFICULTY", 0, 1, 2), 0x44: ("DIFFICULTY", 0, 1, 2),
0x45: ("GASLIMIT", 0, 1, 2), 0x45: ("GASLIMIT", 0, 1, 2),
0x46: ("CHAINID", 0, 1, 2),
0x47: ("SELFBALANCE", 0, 1, 5),
0x50: ("POP", 1, 0, 2), 0x50: ("POP", 1, 0, 2),
0x51: ("MLOAD", 1, 1, 3), 0x51: ("MLOAD", 1, 1, 3),
0x52: ("MSTORE", 2, 0, 3), 0x52: ("MSTORE", 2, 0, 3),

@ -17,6 +17,7 @@ mock
persistent>=4.2.0 persistent>=4.2.0
plyvel plyvel
py-flags py-flags
py-evm==0.3.0a13
py-solc-x==0.6.0 py-solc-x==0.6.0
py-solc py-solc
pytest>=3.6.0 pytest>=3.6.0

@ -19,7 +19,7 @@ DESCRIPTION = "Security analysis tool for Ethereum smart contracts"
URL = "https://github.com/ConsenSys/mythril" URL = "https://github.com/ConsenSys/mythril"
AUTHOR = "ConsenSys Dilligence" AUTHOR = "ConsenSys Dilligence"
AUTHOR_MAIL = None AUTHOR_MAIL = None
REQUIRES_PYTHON = ">=3.5.0" REQUIRES_PYTHON = ">=3.6.0"
# What packages are required for this module to be executed? # What packages are required for this module to be executed?
@ -52,6 +52,7 @@ REQUIRED = [
"ethereum-input-decoder>=0.2.2", "ethereum-input-decoder>=0.2.2",
"matplotlib", "matplotlib",
"pythx", "pythx",
"py-evm==0.3.0a13",
] ]
TESTS_REQUIRE = ["mypy", "pytest>=3.6.0", "pytest_mock", "pytest-cov"] TESTS_REQUIRE = ["mypy", "pytest>=3.6.0", "pytest_mock", "pytest-cov"]
@ -118,7 +119,6 @@ setup(
"Intended Audience :: Science/Research", "Intended Audience :: Science/Research",
"Topic :: Software Development :: Disassemblers", "Topic :: Software Development :: Disassemblers",
"License :: OSI Approved :: MIT License", "License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.7",
], ],

@ -0,0 +1,42 @@
import pytest
from mythril.laser.ethereum.natives import blake2b_fcompress
# Test cases taken from https://eips.ethereum.org/EIPS/eip-152.
# One of the test case is expected to take a few hrs so I ignored it
@pytest.mark.parametrize(
"input_hex, expected_result",
(
("", ""),
(
"00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", # noqa: E501
"",
),
(
"000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", # noqa: E501
"",
),
(
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", # noqa: E501
"",
),
(
"0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", # noqa: E501
"08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b", # noqa: E501
),
(
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", # noqa: E501
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", # noqa: E501
),
(
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000", # noqa: E501
"75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", # noqa: E501
),
(
"0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", # noqa: E501
"b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", # noqa: E501
),
),
)
def test_blake2(input_hex, expected_result):
input_hex = bytearray.fromhex(input_hex)
assert blake2b_fcompress(input_hex) == list(bytearray.fromhex(expected_result))

@ -1,5 +1,5 @@
[tox] [tox]
envlist = py35, py36 envlist = py36
[testenv] [testenv]
deps = deps =

Loading…
Cancel
Save