Exemple #1
0
    def test_arithmetic_simplify(self):
        cs = ConstraintSet()
        arr = cs.new_array(name="MEM")
        a = cs.new_bitvec(32, name="VARA")
        b = cs.new_bitvec(32, name="VARB")
        c = a * 2 + b
        self.assertEqual(translate_to_smtlib(c), "(bvadd (bvmul VARA #x00000002) VARB)")
        self.assertEqual(
            translate_to_smtlib((c + 4) - 4),
            "(bvsub (bvadd (bvadd (bvmul VARA #x00000002) VARB) #x00000004) #x00000004)",
        )

        d = c + 4
        s = arithmetic_simplify(d - c)
        self.assertIsInstance(s, Constant)
        self.assertEqual(s.value, 4)
        # size = arithmetic_simplify(size

        cs2 = ConstraintSet()
        exp = cs2.new_bitvec(32)
        exp |= 0
        exp &= 1
        exp |= 0
        self.assertEqual(get_depth(exp), 4)
        self.assertEqual(
            translate_to_smtlib(exp), "(bvor (bvand (bvor BIVEC #x00000000) #x00000001) #x00000000)"
        )
        exp = arithmetic_simplify(exp)
        self.assertTrue(get_depth(exp) < 4)
        self.assertEqual(translate_to_smtlib(exp), "(bvand BIVEC #x00000001)")
Exemple #2
0
    def testBasicArrayStore(self):
        name = "bitarray"
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, name=name)
        # make free 32bit bitvector
        key = cs.new_bitvec(32)

        # assert that the array is 'A' at key position
        array = array.store(key, ord("A"))
        # let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))

        # 1001 position of array can be 'A'
        self.assertTrue(self.solver.can_be_true(cs, array.select(1001) == ord("A")))

        # 1001 position of array can be 'B'
        self.assertTrue(self.solver.can_be_true(cs, array.select(1001) == ord("B")))

        # name is correctly proxied
        self.assertEqual(array.name, name)

        with cs as temp_cs:
            # but if it is 'B' ...
            temp_cs.add(array.select(1001) == ord("B"))
            # then key can not be 1001
            temp_cs.add(key == 1001)
            self.assertFalse(self.solver.check(temp_cs))

        with cs as temp_cs:
            # If 1001 position is 'B' ...
            temp_cs.add(array.select(1001) == ord("B"))
            # then key can be 1002 for ex..
            temp_cs.add(key != 1002)
            self.assertTrue(self.solver.check(temp_cs))
Exemple #3
0
    def testBasicArrayProxySymbIdx2(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array")
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[0] = 1  # Write 1 to first location
        array[key] = 2  # Write 2 to a symbolic (potentially any (potentially 0))location

        solutions = self.solver.get_all_values(cs, array[0])  # get a concrete solution for index
        self.assertItemsEqual(solutions, (1, 2))

        solutions = self.solver.get_all_values(
            cs, array.get(0, 100)
        )  # get a concrete solution for index 0
        self.assertItemsEqual(solutions, (1, 2))

        solutions = self.solver.get_all_values(
            cs, array.get(1, 100)
        )  # get a concrete solution for index 1 (default 100)
        self.assertItemsEqual(solutions, (100, 2))

        self.assertTrue(
            self.solver.can_be_true(cs, array[1] == 12345)
        )  # no default so it can be anything
    def testBasicArraySlice(self):
        hw = bytearray(b"Hello world!")
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, index_max=12)
        array = array.write(0, hw)
        array_slice = array[0:2]
        self.assertTrue(self.solver.must_be_true(cs, array == hw))
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0] == array[0]))
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0:2][1] == array[1]))
        array_slice[0] = ord("A")
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0] == ord("A")))
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0:2][1] == array[1]))
        self.assertTrue(self.solver.must_be_true(cs, array == hw))

        # Testing some slicing combinations
        self.assertRaises(
            IndexError, lambda i: translate_to_smtlib(array_slice[0:1000][i]),
            1002)
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0:1000][0] == ord("A")))
        self.assertTrue(
            self.solver.must_be_true(cs, array_slice[0:1000][1] == array[1]))
        self.assertTrue(
            self.solver.must_be_true(
                cs, array_slice[0:1000][:2][1] == array[:2][1]))
        self.assertTrue(
            self.solver.must_be_true(cs,
                                     array_slice[0:1000][:2][0] == ord("A")))
Exemple #5
0
    def testBasicArray256(self):
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, value_bits=256)
        # make free 32bit bitvector
        key = cs.new_bitvec(32)

        # assert that the array is 111...111 at key position
        cs.add(array[key] == 11111111111111111111111111111111111111111111)
        # let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))

        with cs as temp_cs:
            # 1001 position of array can be 111...111
            temp_cs.add(array[1001] == 11111111111111111111111111111111111111111111)
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # 1001 position of array can also be 222...222
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # but if it is 222...222 ...
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            # then key can not be 1001
            temp_cs.add(key == 1001)
            self.assertFalse(self.solver.check(temp_cs))

        with cs as temp_cs:
            # If 1001 position is 222...222 ...
            temp_cs.add(array[1001] == 22222222222222222222222222222222222222222222)
            # then key can be 1002 for ex..
            temp_cs.add(key == 1002)
            self.assertTrue(self.solver.check(temp_cs))
    def test_visitors(self):
        solver = Z3Solver.instance()
        cs = ConstraintSet()
        arr = cs.new_array(name="MEM")
        a = cs.new_bitvec(32, name="VAR")
        self.assertEqual(get_depth(a), 1)
        cond = Operators.AND(a < 200, a > 100)
        arr[0] = ord("a")
        arr[1] = ord("b")

        self.assertEqual(get_depth(cond), 3)
        self.assertEqual(get_depth(arr[a + 1]), 4)
        self.assertEqual(
            translate_to_smtlib(arr[a + 1]),
            "(select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))",
        )

        arr[3] = arr[a + 1]
        aux = arr[a + Operators.ZEXTEND(arr[a], 32)]

        self.assertEqual(get_depth(aux), 9)
        self.maxDiff = 1500
        self.assertEqual(
            translate_to_smtlib(aux),
            "(select (store (store (store MEM #x00000000 #x61) #x00000001 #x62) #x00000003 (select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))) (bvadd VAR ((_ zero_extend 24) (select (store (store (store MEM #x00000000 #x61) #x00000001 #x62) #x00000003 (select (store (store MEM #x00000000 #x61) #x00000001 #x62) (bvadd VAR #x00000001))) VAR))))",
        )

        values = arr[0:2]
        self.assertEqual(len(values), 2)
        self.assertItemsEqual(solver.get_all_values(cs, values[0]), [ord("a")])
        self.assertItemsEqual(solver.get_all_values(cs, values[1]), [ord("b")])
        arr[1:3] = "cd"

        values = arr[0:3]
        self.assertEqual(len(values), 3)
        self.assertItemsEqual(solver.get_all_values(cs, values[0]), [ord("a")])
        self.assertItemsEqual(solver.get_all_values(cs, values[1]), [ord("c")])
        self.assertItemsEqual(solver.get_all_values(cs, values[2]), [ord("d")])
        self.assertEqual(
            pretty_print(aux, depth=2),
            "ArraySelect\n  ArrayStore\n    ...\n  BitVecAdd\n    ...\n")
        self.assertEqual(pretty_print(Operators.EXTRACT(a, 0, 8), depth=1),
                         "BitVecExtract{0:7}\n  ...\n")
        self.assertEqual(pretty_print(a, depth=2), "VAR\n")

        x = BitVecConstant(32, 100, taint=("important", ))
        y = BitVecConstant(32, 200, taint=("stuff", ))
        z = constant_folder(x + y)
        self.assertItemsEqual(z.taint, ("important", "stuff"))
        self.assertEqual(z.value, 300)

        self.assertRaises(Exception, translate_to_smtlib, 1)

        self.assertEqual(
            translate_to_smtlib(simplify(Operators.ZEXTEND(a, 32))), "VAR")
        self.assertEqual(
            translate_to_smtlib(
                simplify(Operators.EXTRACT(Operators.EXTRACT(a, 0, 8), 0, 8))),
            "((_ extract 7 0) VAR)",
        )
Exemple #7
0
    def testBasicArraySymbIdx(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array")
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[key] = 1  # Write 1 to a single location

        cs.add(array.get(index, default=0) != 0)  # Constrain index so it selects that location

        cs.add(index != key)
        # key and index are the same there is only one slot in 1
        self.assertFalse(self.solver.check(cs))
    def test_serialize_bytes_symbolic(self):
        cs = ConstraintSet()
        buf = cs.new_array(index_max=17)
        ret = ABI.serialize('bytes', buf)

        # does the offset field look right?
        self.assertTrue(solver.must_be_true(cs, ret[0:32] == bytearray(b'\x00'*31 + b'\x20')))

        # does the size field look right?
        self.assertTrue(solver.must_be_true(cs, ret[32:64] == bytearray(b'\x00'*31 + b'\x11')))

        # does the data field look right?
        self.assertTrue(solver.must_be_true(cs, ret[64:64+32] == buf + bytearray(b'\x00'*15)))
Exemple #9
0
    def testBasicArrayProxySymbIdx(self):
        cs = ConstraintSet()
        array = cs.new_array(index_bits=32, value_bits=32, name="array", default=0)
        key = cs.new_bitvec(32, name="key")
        index = cs.new_bitvec(32, name="index")

        array[key] = 1  # Write 1 to a single location
        cs.add(array.get(index) != 0)  # Constrain index so it selects that location
        a_index = self.solver.get_value(cs, index)  # get a concrete solution for index

        cs.add(array.get(a_index) != 0)  # now storage must have something at that location
        cs.add(a_index != index)  # remove it from the solutions
        # It should not be another solution for index
        self.assertFalse(self.solver.check(cs))
Exemple #10
0
    def testBasicPickle(self):
        import pickle
        cs = ConstraintSet()

        #make array of 32->8 bits
        array = cs.new_array(32)
        #make free 32bit bitvector
        key = cs.new_bitvec(32)

        #assert that the array is 'A' at key position
        array = array.store(key, ord('A'))
        #let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))
        cs = pickle.loads(pickle.dumps(cs))
        self.assertTrue(self.solver.check(cs))
    def testBasicArrayConcatSlice(self):
        hw = bytearray(b"Hello world!")
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32, index_max=12)

        array = array.write(0, hw)

        self.assertTrue(self.solver.must_be_true(cs, array == hw))

        self.assertTrue(self.solver.must_be_true(cs, array.read(0, 12) == hw))

        self.assertTrue(
            self.solver.must_be_true(cs,
                                     array.read(6, 6) == hw[6:12]))

        self.assertTrue(
            self.solver.must_be_true(
                cs,
                bytearray(b"Hello ") + array.read(6, 6) == hw))

        self.assertTrue(
            self.solver.must_be_true(
                cs,
                bytearray(b"Hello ") + array.read(6, 5) +
                bytearray(b"!") == hw))

        self.assertTrue(
            self.solver.must_be_true(
                cs,
                array.read(0, 1) + bytearray(b"ello ") + array.read(6, 5) +
                bytearray(b"!") == hw,
            ))

        self.assertTrue(len(array[1:2]) == 1)

        self.assertTrue(len(array[0:12]) == 12)

        results = []
        for c in array[6:11]:
            results.append(c)
        self.assertTrue(len(results) == 5)
Exemple #12
0
    def test_arithmetic_simplify_extract(self):
        cs = ConstraintSet()
        arr = cs.new_array(name='MEM')
        a = cs.new_bitvec(32, name='VARA')
        b = Operators.CONCAT(32, Operators.EXTRACT(a, 24, 8),
                             Operators.EXTRACT(a, 16, 8),
                             Operators.EXTRACT(a, 8, 8),
                             Operators.EXTRACT(a, 0, 8))
        self.assertEqual(
            translate_to_smtlib(b),
            '(concat ((_ extract 31 24) VARA) ((_ extract 23 16) VARA) ((_ extract 15 8) VARA) ((_ extract 7 0) VARA))'
        )
        self.assertEqual(translate_to_smtlib(simplify(b)), 'VARA')

        c = Operators.CONCAT(16, Operators.EXTRACT(a, 16, 8),
                             Operators.EXTRACT(a, 8, 8))
        self.assertEqual(
            translate_to_smtlib(c),
            '(concat ((_ extract 23 16) VARA) ((_ extract 15 8) VARA))')
        self.assertEqual(translate_to_smtlib(simplify(c)),
                         '((_ extract 23 8) VARA)')
Exemple #13
0
    def testBasicArray(self):
        cs = ConstraintSet()
        # make array of 32->8 bits
        array = cs.new_array(32)
        # make free 32bit bitvector
        key = cs.new_bitvec(32)

        # assert that the array is 'A' at key position
        # By default an smtlib can contain any value
        cs.add(array[key] == ord("A"))

        # let's restrict key to be greater than 1000
        cs.add(key.ugt(1000))
        with cs as temp_cs:
            # 1001 position of array can be 'A'
            temp_cs.add(array[1001] == ord("A"))
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # 1001 position of array can also be 'B'
            temp_cs.add(array[1001] == ord("B"))
            self.assertTrue(self.solver.check(temp_cs))

        with cs as temp_cs:
            # but if it is 'B' ...
            temp_cs.add(array[1001] == ord("B"))
            # then key can not be 1001
            temp_cs.add(key == 1001)
            self.assertFalse(self.solver.check(temp_cs))

        with cs as temp_cs:
            # If 1001 position is 'B' ...
            temp_cs.add(array[1001] == ord("B"))
            # then key can be 1000 for ex..
            temp_cs.add(key == 1002)
            self.assertTrue(self.solver.check(temp_cs))
Exemple #14
0
 def test_serialize_bytesM_symbolic(self):
     cs = ConstraintSet()
     buf = cs.new_array(index_max=17)
     ret = ABI.serialize('bytes32', buf)
     self.assertEqual(solver.minmax(cs, ret[0]), (0, 255))
     self.assertEqual(solver.minmax(cs, ret[17]), (0, 0))
Exemple #15
0
    def test_return2(self):
        """
        Testcase taken from https://github.com/ethereum/tests
        File: return2.json
        sha256sum: 25972361a5871003f44467255a656b9e7ba3762a5cfe02b56a0197318d375b9a
        Code:     PUSH1 0x37
                  PUSH1 0x0
                  MSTORE8
                  PUSH1 0x0
                  MLOAD
                  PUSH1 0x0
                  SSTORE
                  PUSH1 0x21
                  PUSH1 0x0
                  RETURN
        """
        def solve(val):
            return self._solve(constraints, val)

        constraints = ConstraintSet()

        blocknumber = constraints.new_bitvec(256, name='blocknumber')
        constraints.add(blocknumber == 0)

        timestamp = constraints.new_bitvec(256, name='timestamp')
        constraints.add(timestamp == 1)

        difficulty = constraints.new_bitvec(256, name='difficulty')
        constraints.add(difficulty == 256)

        coinbase = constraints.new_bitvec(256, name='coinbase')
        constraints.add(
            coinbase == 244687034288125203496486448490407391986876152250)

        gaslimit = constraints.new_bitvec(256, name='gaslimit')
        constraints.add(gaslimit == 10000000)

        world = evm.EVMWorld(constraints,
                             blocknumber=blocknumber,
                             timestamp=timestamp,
                             difficulty=difficulty,
                             coinbase=coinbase,
                             gaslimit=gaslimit)

        acc_addr = 0xcd1722f3947def4cf144679da39c4c32bdc35681
        acc_code = unhexlify('603760005360005160005560216000f3')

        acc_balance = constraints.new_bitvec(
            256, name='balance_0xcd1722f3947def4cf144679da39c4c32bdc35681')
        constraints.add(acc_balance == 23)

        acc_nonce = constraints.new_bitvec(
            256, name='nonce_0xcd1722f3947def4cf144679da39c4c32bdc35681')
        constraints.add(acc_nonce == 0)

        world.create_account(address=acc_addr,
                             balance=acc_balance,
                             code=acc_code,
                             nonce=acc_nonce)

        address = 0xcd1722f3947def4cf144679da39c4c32bdc35681
        caller = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6
        price = constraints.new_bitvec(256, name='price')
        constraints.add(price == 100000000000000)

        value = constraints.new_bitvec(256, name='value')
        constraints.add(value == 23)

        gas = constraints.new_bitvec(256, name='gas')
        constraints.add(gas == 100000)

        data = constraints.new_array(index_max=1)
        constraints.add(data == b'\xaa')

        # open a fake tx, no funds send
        world._open_transaction('CALL',
                                address,
                                price,
                                data,
                                caller,
                                value,
                                gas=gas)

        # This variable might seem redundant in some tests - don't forget it is auto generated
        # and there are cases in which we need it ;)
        result, returndata = self._test_run(world)

        # World sanity checks - those should not change, right?
        self.assertEqual(solve(world.block_number()), 0)
        self.assertEqual(solve(world.block_gaslimit()), 10000000)
        self.assertEqual(solve(world.block_timestamp()), 1)
        self.assertEqual(solve(world.block_difficulty()), 256)
        self.assertEqual(solve(world.block_coinbase()),
                         0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba)

        # Add post checks for account 0xcd1722f3947def4cf144679da39c4c32bdc35681
        # check nonce, balance, code
        self.assertEqual(
            solve(world.get_nonce(0xcd1722f3947def4cf144679da39c4c32bdc35681)),
            0)
        self.assertEqual(
            solve(
                world.get_balance(0xcd1722f3947def4cf144679da39c4c32bdc35681)),
            23)
        self.assertEqual(
            world.get_code(0xcd1722f3947def4cf144679da39c4c32bdc35681),
            unhexlify('603760005360005160005560216000f3'))
        # check storage
        self.assertEqual(
            solve(
                world.get_storage_data(
                    0xcd1722f3947def4cf144679da39c4c32bdc35681, 0x00)),
            0x3700000000000000000000000000000000000000000000000000000000000000)
        # check outs
        self.assertEqual(
            returndata,
            unhexlify(
                '370000000000000000000000000000000000000000000000000000000000000000'
            ))
        # check logs
        logs = [
            Log(unhexlify('{:040x}'.format(l.address)), l.topics,
                solve(l.memlog)) for l in world.logs
        ]
        data = rlp.encode(logs)
        self.assertEqual(
            sha3.keccak_256(data).hexdigest(),
            '1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347')

        # test used gas
        self.assertEqual(solve(world.current_vm.gas), 79970)
Exemple #16
0
    def test_TestNameRegistrator(self):
        """
        Testcase taken from https://github.com/ethereum/tests
        File: TestNameRegistrator.json
        sha256sum: dd000f5977416de19410170b8a7acb5060011594fd97c81f307f015cd5bdd51e
        Code:     PUSH1 0x0
                  CALLDATALOAD
                  SLOAD
                  ISZERO
                  PUSH1 0x9
                  JUMPI
                  STOP
                  JUMPDEST
                  PUSH1 0x20
                  CALLDATALOAD
                  PUSH1 0x0
                  CALLDATALOAD
                  SSTORE
        """
        def solve(val):
            return self._solve(constraints, val)

        constraints = ConstraintSet()

        blocknumber = constraints.new_bitvec(256, name='blocknumber')
        constraints.add(blocknumber == 0)

        timestamp = constraints.new_bitvec(256, name='timestamp')
        constraints.add(timestamp == 1)

        difficulty = constraints.new_bitvec(256, name='difficulty')
        constraints.add(difficulty == 256)

        coinbase = constraints.new_bitvec(256, name='coinbase')
        constraints.add(
            coinbase == 244687034288125203496486448490407391986876152250)

        gaslimit = constraints.new_bitvec(256, name='gaslimit')
        constraints.add(gaslimit == 1000000)

        world = evm.EVMWorld(constraints,
                             blocknumber=blocknumber,
                             timestamp=timestamp,
                             difficulty=difficulty,
                             coinbase=coinbase,
                             gaslimit=gaslimit)

        acc_addr = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6
        acc_code = unhexlify('6000355415600957005b60203560003555')

        acc_balance = constraints.new_bitvec(
            256, name='balance_0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6')
        constraints.add(acc_balance == 100000000000000000000000)

        acc_nonce = constraints.new_bitvec(
            256, name='nonce_0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6')
        constraints.add(acc_nonce == 0)

        world.create_account(address=acc_addr,
                             balance=acc_balance,
                             code=acc_code,
                             nonce=acc_nonce)

        address = 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6
        caller = 0xcd1722f3947def4cf144679da39c4c32bdc35681
        price = constraints.new_bitvec(256, name='price')
        constraints.add(price == 100000000000000)

        value = constraints.new_bitvec(256, name='value')
        constraints.add(value == 1000000000000000000)

        gas = constraints.new_bitvec(256, name='gas')
        constraints.add(gas == 100000)

        data = constraints.new_array(index_max=64)
        constraints.add(
            data ==
            b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfa\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfa'
        )

        # open a fake tx, no funds send
        world._open_transaction('CALL',
                                address,
                                price,
                                data,
                                caller,
                                value,
                                gas=gas)

        # This variable might seem redundant in some tests - don't forget it is auto generated
        # and there are cases in which we need it ;)
        result, returndata = self._test_run(world)

        # World sanity checks - those should not change, right?
        self.assertEqual(solve(world.block_number()), 0)
        self.assertEqual(solve(world.block_gaslimit()), 1000000)
        self.assertEqual(solve(world.block_timestamp()), 1)
        self.assertEqual(solve(world.block_difficulty()), 256)
        self.assertEqual(solve(world.block_coinbase()),
                         0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba)

        # Add post checks for account 0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6
        # check nonce, balance, code
        self.assertEqual(
            solve(world.get_nonce(0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6)),
            0)
        self.assertEqual(
            solve(
                world.get_balance(0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6)),
            100000000000000000000000)
        self.assertEqual(
            world.get_code(0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6),
            unhexlify('6000355415600957005b60203560003555'))
        # check storage
        self.assertEqual(
            solve(
                world.get_storage_data(
                    0xf572e5295c57f15886f9b263e2f6d2d6c7b5ec6,
                    0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa
                )),
            0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa)
        # check outs
        self.assertEqual(returndata, unhexlify(''))
        # check logs
        logs = [
            Log(unhexlify('{:040x}'.format(l.address)), l.topics,
                solve(l.memlog)) for l in world.logs
        ]
        data = rlp.encode(logs)
        self.assertEqual(
            sha3.keccak_256(data).hexdigest(),
            '1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347')

        # test used gas
        self.assertEqual(solve(world.current_vm.gas), 79915)