Repository: ConsenSys/mythril-classic (python)

Issue:
Pass creation bytecode to mythril
Currently laser does model the creation of a contract, when dealing with SolidityContracts.
When using the command line option -c, mythril will still consider this to be runtime bytecode. An option needs to be added to support creation bytecode

### Requirements
 - Add cli option for creation bytecode
 - Adapt current cli "help" strings to this change
 - Change the analyis.symbolic so that the bytecode will be interpreted as creation bytecode

Pull request:
Fix #576: Add a new CLI option to load contract creation bytecode from the command line
Fix #576: Add a new CLI option to load contract creation bytecode from the command line

Patch:
diff --git a/mythril/analysis/symbolic.py b/mythril/analysis/symbolic.py
index 539fbb24..5bd88896 100644
--- a/mythril/analysis/symbolic.py
+++ b/mythril/analysis/symbolic.py
@@ -1,6 +1,6 @@
 from mythril.laser.ethereum import svm
 from mythril.laser.ethereum.state import Account
-from mythril.ether.soliditycontract import SolidityContract
+from mythril.ether.soliditycontract import SolidityContract, ETHContract
 import copy
 import logging
 from .ops import get_variable, SStore, Call, VarType
@@ -64,6 +64,10 @@ class SymExecWrapper:
             self.laser.sym_exec(
                 creation_code=contract.creation_code, contract_name=contract.name
             )
+        elif isinstance(contract, ETHContract) and contract.creation_code:
+            self.laser.sym_exec(
+                creation_code=contract.creation_code, contract_name=contract.name
+            )
         else:
             self.laser.sym_exec(address)
 
diff --git a/mythril/ether/ethcontract.py b/mythril/ether/ethcontract.py
index 8914c882..d63f2938 100644
--- a/mythril/ether/ethcontract.py
+++ b/mythril/ether/ethcontract.py
@@ -6,7 +6,7 @@ import re
 
 class ETHContract(persistent.Persistent):
     def __init__(
-        self, code, creation_code="", name="Unknown", enable_online_lookup=False
+        self, code="", creation_code="", name="Unknown", enable_online_lookup=False
     ):
 
         # Workaround: We currently do not support compile-time linking.
@@ -27,7 +27,6 @@ class ETHContract(persistent.Persistent):
     def as_dict(self):
 
         return {
-            "address": self.address,
             "name": self.name,
             "code": self.code,
             "creation_code": self.creation_code,
diff --git a/mythril/interfaces/cli.py b/mythril/interfaces/cli.py
index 19d73be6..51bae2a2 100644
--- a/mythril/interfaces/cli.py
+++ b/mythril/interfaces/cli.py
@@ -90,6 +90,11 @@ def main():
         action="store_true",
         help="auto-load dependencies from the blockchain",
     )
+    inputs.add_argument(
+        "--bin-runtime",
+        action="store_true",
+        help="Only when -c or -f is used. Consider the input bytecode as binary runtime code, default being the contract creation bytecode.",
+    )
 
     outputs = parser.add_argument_group("output formats")
     outputs.add_argument(
@@ -317,10 +322,10 @@ def main():
 
         if args.code:
             # Load from bytecode
-            address, _ = mythril.load_from_bytecode(args.code)
+            address, _ = mythril.load_from_bytecode(args.code, args.bin_runtime)
         elif args.codefile:
             bytecode = "".join([l.strip() for l in args.codefile if len(l.strip()) > 0])
-            address, _ = mythril.load_from_bytecode(bytecode)
+            address, _ = mythril.load_from_bytecode(bytecode, args.bin_runtime)
         elif args.address:
             # Get bytecode from a contract address
             address, _ = mythril.load_from_address(args.address)
diff --git a/mythril/laser/ethereum/svm.py b/mythril/laser/ethereum/svm.py
index 4882671b..14cf1b2a 100644
--- a/mythril/laser/ethereum/svm.py
+++ b/mythril/laser/ethereum/svm.py
@@ -129,7 +129,7 @@ class LaserEVM:
                 / float(coverage[0])
                 * 100
             )
-            logging.info("Achieved {} coverage for code: {}".format(cov, code))
+            logging.info("Achieved {:.2f}% coverage for code: {}".format(cov, code))
 
     def _get_covered_instructions(self) -> int:
         """ Gets the total number of covered instructions for all accounts in the svm"""
diff --git a/mythril/mythril.py b/mythril/mythril.py
index 6477d3b2..6c20f563 100644
--- a/mythril/mythril.py
+++ b/mythril/mythril.py
@@ -311,13 +311,24 @@ class Mythril(object):
 
         print(self.eth_db.contract_hash_to_address(hash))
 
-    def load_from_bytecode(self, code):
+    def load_from_bytecode(self, code, bin_runtime=False):
         address = util.get_indexed_address(0)
-        self.contracts.append(
-            ETHContract(
-                code, name="MAIN", enable_online_lookup=self.enable_online_lookup
+        if bin_runtime:
+            self.contracts.append(
+                ETHContract(
+                    code=code,
+                    name="MAIN",
+                    enable_online_lookup=self.enable_online_lookup,
+                )
+            )
+        else:
+            self.contracts.append(
+                ETHContract(
+                    creation_code=code,
+                    name="MAIN",
+                    enable_online_lookup=self.enable_online_lookup,
+                )
             )
-        )
         return address, self.contracts[-1]  # return address and contract object
 
     def load_from_address(self, address):


Test patch:
diff --git a/tests/cmd_line_test.py b/tests/cmd_line_test.py
index 394c5d42..9de57a5f 100644
--- a/tests/cmd_line_test.py
+++ b/tests/cmd_line_test.py
@@ -10,7 +10,7 @@ def output_of(command):
 
 class CommandLineToolTestCase(BaseTestCase):
     def test_disassemble_code_correctly(self):
-        command = "python3 {} MYTH -d -c 0x5050".format(MYTH)
+        command = "python3 {} MYTH -d --bin-runtime -c 0x5050".format(MYTH)
         self.assertEqual("0 POP\n1 POP\n", output_of(command))
 
     def test_disassemble_solidity_file_correctly(self):