Esempio n. 1
0
File: evm.py Progetto: norhh/mythril
def trace(code, calldata=""):
    log_handlers = [
        "eth.vm.op",
        "eth.vm.op.stack",
        "eth.vm.op.memory",
        "eth.vm.op.storage",
    ]
    output = StringIO()
    stream_handler = StreamHandler(output)

    for handler in log_handlers:
        log_vm_op = get_logger(handler)
        log_vm_op.setLevel("TRACE")
        log_vm_op.addHandler(stream_handler)

    addr = bytes.fromhex("0123456789ABCDEF0123456789ABCDEF01234567")
    state = State()

    ext = messages.VMExt(state,
                         transactions.Transaction(0, 0, 21000, addr, 0, addr))
    message = vm.Message(addr, addr, 0, 21000, calldata)
    vm.vm_execute(ext, message, util.safe_decode(code))
    stream_handler.flush()
    ret = output.getvalue()
    lines = ret.split("\n")

    state_trace = []
    for line in lines:
        m = re.search(r"pc=b\'(\d+)\'.*op=([A-Z0-9]+)", line)
        if m:
            pc = m.group(1)
            op = m.group(2)
            m = re.match(r".*stack=(\[.*?\])", line)

            if m:
                stackitems = re.findall(r"b\'(\d+)\'", m.group(1))
                stack = "["

                if len(stackitems):
                    for i in range(0, len(stackitems) - 1):
                        stack += hex(int(stackitems[i])) + ", "
                    stack += hex(int(stackitems[-1]))

                stack += "]"
            else:
                stack = "[]"

            if re.match(r"^PUSH.*", op):
                val = re.search(r"pushvalue=(\d+)", line).group(1)
                pushvalue = hex(int(val))
                state_trace.append({
                    "pc": pc,
                    "op": op,
                    "stack": stack,
                    "pushvalue": pushvalue
                })
            else:
                state_trace.append({"pc": pc, "op": op, "stack": stack})

    return state_trace
Esempio n. 2
0
def trace(code, address = "", calldata = ""):

	logHandlers = ['eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage']

	output = StringIO()
	streamHandler = StreamHandler(output)

	for handler in logHandlers:
		log_vm_op = get_logger(handler)
		log_vm_op.setLevel("TRACE")
		log_vm_op.addHandler(streamHandler)

	addr_from = codecs.decode('0123456789ABCDEF0123456789ABCDEF01234567', 'hex_codec')
	addr_to = safe_decode(address)

	state = State()

	ext = messages.VMExt(state, transactions.Transaction(0, 0, 21000, addr_from, 0, addr_to))

	message = vm.Message(addr_from, addr_to, 0, 21000, calldata, code_address=addr_to)

	res, gas, dat = vm.vm_execute(ext, message, code)

	streamHandler.flush()

	# print(output.getvalue())

	ret = output.getvalue()

	return ret
Esempio n. 3
0
def _apply_msg(ext, msg, code):
    trace_msg = log_msg.is_active("trace")
    if trace_msg:
        log_msg.debug(
            "MSG APPLY",
            sender=encode_hex(msg.sender),
            to=encode_hex(msg.to),
            gas=msg.gas,
            value=msg.value,
            data=encode_hex(msg.data.extract_all()),
        )
        if log_state.is_active("trace"):
            log_state.trace(
                "MSG PRE STATE SENDER",
                account=encode_hex(msg.sender),
                bal=ext.get_balance(msg.sender),
                state=ext.log_storage(msg.sender),
            )
            log_state.trace(
                "MSG PRE STATE RECIPIENT",
                account=encode_hex(msg.to),
                bal=ext.get_balance(msg.to),
                state=ext.log_storage(msg.to),
            )
        # log_state.trace('CODE', code=code)
    # Transfer value, instaquit if not enough
    snapshot = ext._block.snapshot()
    if msg.transfers_value:
        if not ext._block.transfer_value(msg.sender, msg.to, msg.value):
            log_msg.debug("MSG TRANSFER FAILED", have=ext.get_balance(msg.to), want=msg.value)
            return 1, msg.gas, []
    # Main loop
    if msg.code_address in specials.specials:
        res, gas, dat = specials.specials[msg.code_address](ext, msg)
    else:
        res, gas, dat = vm.vm_execute(ext, msg, code)
    # gas = int(gas)
    # assert utils.is_numeric(gas)
    if trace_msg:
        log_msg.debug("MSG APPLIED", gas_remained=gas, sender=encode_hex(msg.sender), to=encode_hex(msg.to), data=dat)
        if log_state.is_active("trace"):
            log_state.trace(
                "MSG POST STATE SENDER",
                account=encode_hex(msg.sender),
                bal=ext.get_balance(msg.sender),
                state=ext.log_storage(msg.sender),
            )
            log_state.trace(
                "MSG POST STATE RECIPIENT",
                account=encode_hex(msg.to),
                bal=ext.get_balance(msg.to),
                state=ext.log_storage(msg.to),
            )

    if res == 0:
        log_msg.debug("REVERTING")
        ext._block.revert(snapshot)

    return res, gas, dat
Esempio n. 4
0
def _apply_msg(ext, msg, code):
    trace_msg = log_msg.is_active('trace')
    if trace_msg:
        log_msg.debug("MSG APPLY",
                      sender=encode_hex(msg.sender),
                      to=encode_hex(msg.to),
                      gas=msg.gas,
                      value=msg.value,
                      data=encode_hex(msg.data.extract_all()))
        if log_state.is_active('trace'):
            log_state.trace('MSG PRE STATE SENDER',
                            account=msg.sender,
                            bal=ext.get_balance(msg.sender),
                            state=ext.log_storage(msg.sender))
            log_state.trace('MSG PRE STATE RECIPIENT',
                            account=msg.to,
                            bal=ext.get_balance(msg.to),
                            state=ext.log_storage(msg.to))
        # log_state.trace('CODE', code=code)
    # Transfer value, instaquit if not enough
    snapshot = ext._block.snapshot()
    if not ext._block.transfer_value(msg.sender, msg.to, msg.value):
        log_msg.debug('MSG TRANSFER FAILED',
                      have=ext.get_balance(msg.to),
                      want=msg.value)
        return 1, msg.gas, []
    # Main loop
    if msg.code_address in specials.specials:
        res, gas, dat = specials.specials[msg.code_address](ext, msg)
    else:
        res, gas, dat = vm.vm_execute(ext, msg, code)
    # gas = int(gas)
    # assert utils.is_numeric(gas)
    if trace_msg:
        log_msg.debug('MSG APPLIED',
                      gas_remained=gas,
                      sender=msg.sender,
                      to=msg.to,
                      data=dat)
        if log_state.is_active('trace'):
            log_state.trace('MSG PRE STATE SENDER',
                            account=msg.sender,
                            bal=ext.get_balance(msg.sender),
                            state=ext.log_storage(msg.sender))
            log_state.trace('MSG PRE STATE RECIPIENT',
                            account=msg.to,
                            bal=ext.get_balance(msg.to),
                            state=ext.log_storage(msg.to))

    if res == 0:
        log_msg.debug('REVERTING')
        ext._block.revert(snapshot)

    return res, gas, dat
Esempio n. 5
0
def _apply_msg(ext, msg, code):
    trace_msg = log_msg.is_active('trace')
    if trace_msg:
        log_msg.debug("MSG APPLY",
                      sender=encode_hex(msg.sender),
                      to=encode_hex(msg.to),
                      gas=msg.gas,
                      value=msg.value,
                      codelen=len(code),
                      data=encode_hex(msg.data.extract_all()) if
                      msg.data.size < 2500 else ("data<%d>" % msg.data.size),
                      pre_storage=ext.log_storage(msg.to),
                      static=msg.static,
                      depth=msg.depth)

    # Transfer value, instaquit if not enough
    snapshot = ext.snapshot()
    if msg.transfers_value:
        if not ext.transfer_value(msg.sender, msg.to, msg.value):
            log_msg.debug('MSG TRANSFER FAILED',
                          have=ext.get_balance(msg.to),
                          want=msg.value)
            return 1, msg.gas, []

    # Main loop
    if msg.code_address in ext.specials:
        res, gas, dat = ext.specials[msg.code_address](ext, msg)
    else:
        res, gas, dat = vm.vm_execute(ext, msg, code)

    if trace_msg:
        log_msg.debug('MSG APPLIED',
                      gas_remained=gas,
                      sender=encode_hex(msg.sender),
                      to=encode_hex(msg.to),
                      data=dat if len(dat) < 2500 else ("data<%d>" % len(dat)),
                      post_storage=ext.log_storage(msg.to))

    if res == 0:
        log_msg.debug('REVERTING')
        ext.revert(snapshot)

    return res, gas, dat
Esempio n. 6
0
def _apply_msg(ext, msg, code):
    if log_msg.is_active('trace'):
        log_msg.debug("MSG APPLY", sender=encode_hex(msg.sender), to=encode_hex(msg.to),
                      gas=msg.gas, value=msg.value,
                      data=encode_hex(msg.data.extract_all()))
    if log_state.is_active('trace'):
        log_state.trace('MSG PRE STATE SENDER', account=msg.sender,
                        bal=ext.get_balance(msg.sender),
                        state=ext.log_storage(msg.sender))
        log_state.trace('MSG PRE STATE RECIPIENT', account=msg.to,
                        bal=ext.get_balance(msg.to),
                        state=ext.log_storage(msg.to))
    # Transfer value, instaquit if not enough
    snapshot = ext._block.snapshot()
    o = ext._block.transfer_value(msg.sender, msg.to, msg.value)
    if not o:
        log_msg.debug('MSG TRANSFER FAILED', have=ext.get_balance(msg.to),
                      want=msg.value)
        return 1, msg.gas, []
    # Main loop
    if msg.code_address in specials.specials:
        res, gas, dat = specials.specials[msg.code_address](ext, msg)
    else:
        res, gas, dat = vm.vm_execute(ext, msg, code)
    gas = int(gas)
    assert utils.is_numeric(gas)
    if log_msg.is_active('trace'):
        log_msg.debug('MSG APPLIED', result=o, gas_remained=gas,
                      sender=msg.sender, to=msg.to, data=dat)
    if log_state.is_active('trace'):
        log_state.trace('MSG PRE STATE SENDER', account=msg.sender,
                        bal=ext.get_balance(msg.sender),
                        state=ext.log_storage(msg.sender))
        log_state.trace('MSG PRE STATE RECIPIENT', account=msg.to,
                        bal=ext.get_balance(msg.to),
                        state=ext.log_storage(msg.to))

    if res == 0:
        log_msg.debug('REVERTING')
        ext._block.revert(snapshot)

    return res, gas, dat
Esempio n. 7
0
def generate_code(contracts):
    ext = VmExtBase()
    new_contracts = {}
    for contract in contracts:
        raw_code = bytes.fromhex(contract["code"][2:])
        contructor_output = EthVM.vm_execute(
            ext,
            ConstructorMSG(contract["address"]),
            raw_code
        )
        new_contracts[contract["address"]] = {
            "name": contract["name"],
            "address": contract["address"],
            "abi": contract["abi"],
            "code": '0x' + contructor_output[2].hex(),
            "storage": {}
        }
    for contract in ext.storage:
        storage = {}
        for key in ext.storage[contract]:
            storage[hex(key)] = hex(ext.storage[contract][key])
        new_contracts[contract]["storage"] = storage
    return list(new_contracts.values())
Esempio n. 8
0
def run_vm_test(params, mode, profiler=None):
    pre = params['pre']
    exek = params['exec']
    env = params['env']
    if 'previousHash' not in env:
        env['previousHash'] = encode_hex(db_env.config['GENESIS_PREVHASH'])

    assert set(env.keys()) == set([
        'currentGasLimit', 'currentTimestamp', 'previousHash',
        'currentCoinbase', 'currentDifficulty', 'currentNumber'
    ])
    # setup env
    header = blocks.BlockHeader(
        prevhash=decode_hex(env['previousHash']),
        number=parse_int_or_hex(env['currentNumber']),
        coinbase=decode_hex(env['currentCoinbase']),
        difficulty=parse_int_or_hex(env['currentDifficulty']),
        gas_limit=parse_int_or_hex(env['currentGasLimit']),
        timestamp=parse_int_or_hex(env['currentTimestamp']))
    blk = blocks.Block(header, env=db_env)

    # setup state
    for address, h in list(pre.items()):
        assert len(address) == 40
        address = decode_hex(address)
        assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, parse_int_or_hex(h['nonce']))
        blk.set_balance(address, parse_int_or_hex(h['balance']))
        blk.set_code(address, decode_hex(h['code'][2:]))
        for k, v in h['storage'].items():
            blk.set_storage_data(address,
                                 utils.big_endian_to_int(decode_hex(k[2:])),
                                 utils.big_endian_to_int(decode_hex(v[2:])))

    # execute transactions
    sender = decode_hex(exek['caller'])  # a party that originates a call
    recvaddr = decode_hex(exek['address'])
    nonce = blk._get_acct_item(sender, 'nonce')
    gasprice = parse_int_or_hex(exek['gasPrice'])
    startgas = parse_int_or_hex(exek['gas'])
    value = parse_int_or_hex(exek['value'])
    data = decode_hex(exek['data'][2:])

    # bypass gas check in tx initialization by temporarily increasing startgas
    num_zero_bytes = str_to_bytes(data).count(ascii_chr(0))
    num_non_zero_bytes = len(data) - num_zero_bytes
    intrinsic_gas = (opcodes.GTXCOST + opcodes.GTXDATAZERO * num_zero_bytes +
                     opcodes.GTXDATANONZERO * num_non_zero_bytes)
    startgas += intrinsic_gas
    tx = transactions.Transaction(nonce=nonce,
                                  gasprice=gasprice,
                                  startgas=startgas,
                                  to=recvaddr,
                                  value=value,
                                  data=data)
    tx.startgas -= intrinsic_gas
    tx.sender = sender

    # capture apply_message calls
    apply_message_calls = []
    orig_apply_msg = pb.apply_msg

    ext = pb.VMExt(blk, tx)

    def msg_wrapper(msg):
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(
            dict(gasLimit=to_string(msg.gas),
                 value=to_string(msg.value),
                 destination=encode_hex(msg.to),
                 data=b'0x' + hexdata))
        return 1, msg.gas, b''

    def create_wrapper(msg):
        sender = decode_hex(msg.sender) if \
            len(msg.sender) == 40 else msg.sender
        nonce = utils.encode_int(ext._block.get_nonce(msg.sender))
        addr = utils.sha3(rlp.encode([sender, nonce]))[12:]
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(
            dict(gasLimit=to_string(msg.gas),
                 value=to_string(msg.value),
                 destination=b'',
                 data=b'0x' + hexdata))
        return 1, msg.gas, addr

    ext.msg = msg_wrapper
    ext.create = create_wrapper

    def blkhash(n):
        if n >= ext.block_number or n < ext.block_number - 256:
            return b''
        else:
            return utils.sha3(to_string(n))

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([safe_ord(x) for x in tx.data]))
    code = decode_hex(exek['code'][2:])
    time_pre = time.time()
    if profiler:
        profiler.enable()
    success, gas_remained, output = vm.vm_execute(ext, msg, code)
    if profiler:
        profiler.disable()
    pb.apply_msg = orig_apply_msg
    blk.commit_state()
    for s in blk.suicides:
        blk.del_account(s)
    time_post = time.time()
    """
     generally expected that the test implementer will read env, exec and pre
     then check their results against gas, logs, out, post and callcreates.
     If an exception is expected, then latter sections are absent in the test.
     Since the reverting of the state is not part of the VM tests.
     """

    params2 = copy.deepcopy(params)

    if success:
        params2['callcreates'] = apply_message_calls
        params2['out'] = b'0x' + encode_hex(b''.join(map(ascii_chr, output)))
        params2['gas'] = to_string(gas_remained)
        params2['logs'] = [log.to_dict() for log in blk.logs]
        params2['post'] = blk.to_dict(with_state=True)['state']

    if mode == FILL:
        return params2
    elif mode == VERIFY:
        if not success:
            assert 'post' not in params, 'failed, but expected to succeed'

        params1 = copy.deepcopy(params)
        shouldbe, reallyis = params1.get('post',
                                         None), params2.get('post', None)
        compare_post_states(shouldbe, reallyis)

        def normalize_value(k, p):
            if k in p:
                if k == 'gas':
                    return parse_int_or_hex(p[k])
                elif k == 'callcreates':
                    return list(map(callcreate_standard_form, p[k]))
                else:
                    return utils.to_string(k)
            return None

        for k in ['pre', 'exec', 'env', 'callcreates', 'out', 'gas', 'logs']:
            shouldbe = normalize_value(k, params1)
            reallyis = normalize_value(k, params2)
            if shouldbe != reallyis:
                raise Exception("Mismatch: " + k +
                                ':\n shouldbe %r\n reallyis %r' %
                                (shouldbe, reallyis))
    elif mode == TIME:
        return time_post - time_pre
Esempio n. 9
0
def trace(code, calldata=""):

    logHandlers = [
        'eth.vm.op', 'eth.vm.op.stack', 'eth.vm.op.memory', 'eth.vm.op.storage'
    ]

    output = StringIO()
    streamHandler = StreamHandler(output)

    for handler in logHandlers:
        log_vm_op = get_logger(handler)
        log_vm_op.setLevel("TRACE")
        log_vm_op.addHandler(streamHandler)

    addr = bytes.fromhex('0123456789ABCDEF0123456789ABCDEF01234567')

    state = State()

    ext = messages.VMExt(state,
                         transactions.Transaction(0, 0, 21000, addr, 0, addr))

    message = vm.Message(addr, addr, 0, 21000, calldata)

    res, gas, dat = vm.vm_execute(ext, message, util.safe_decode(code))

    streamHandler.flush()

    ret = output.getvalue()

    lines = ret.split("\n")

    trace = []

    for line in lines:

        m = re.search(r'pc=b\'(\d+)\'.*op=([A-Z0-9]+)', line)

        if m:
            pc = m.group(1)
            op = m.group(2)

            m = re.match(r'.*stack=(\[.*?\])', line)

            if (m):

                stackitems = re.findall(r'b\'(\d+)\'', m.group(1))

                stack = "["

                if (len(stackitems)):

                    for i in range(0, len(stackitems) - 1):
                        stack += hex(int(stackitems[i])) + ", "

                    stack += hex(int(stackitems[-1]))

                stack += "]"

            else:
                stack = "[]"

            if (re.match(r'^PUSH.*', op)):
                val = re.search(r'pushvalue=(\d+)', line).group(1)
                pushvalue = hex(int(val))
                trace.append({
                    'pc': pc,
                    'op': op,
                    'stack': stack,
                    'pushvalue': pushvalue
                })
            else:
                trace.append({'pc': pc, 'op': op, 'stack': stack})

    return trace
Esempio n. 10
0
def run_vm_test(params, mode, profiler=None):
    pre = params['pre']
    exek = params['exec']
    env = params['env']
    if 'previousHash' not in env:
        env['previousHash'] = encode_hex(db_env.config['GENESIS_PREVHASH'])

    assert set(env.keys()) == set(['currentGasLimit', 'currentTimestamp',
                                   'previousHash', 'currentCoinbase',
                                   'currentDifficulty', 'currentNumber'])
    # setup env
    header = blocks.BlockHeader(
        prevhash=decode_hex(env['previousHash']),
        number=parse_int_or_hex(env['currentNumber']),
        coinbase=decode_hex(env['currentCoinbase']),
        difficulty=parse_int_or_hex(env['currentDifficulty']),
        gas_limit=parse_int_or_hex(env['currentGasLimit']),
        timestamp=parse_int_or_hex(env['currentTimestamp']))

    blk = blocks.Block(header, env=db_env)

    # setup state
    for address, h in list(pre.items()):
        assert len(address) == 40
        address = decode_hex(address)
        assert set(h.keys()) == set(['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, parse_int_or_hex(h['nonce']))
        blk.set_balance(address, parse_int_or_hex(h['balance']))
        blk.set_code(address, decode_hex(h['code'][2:]))
        for k, v in h['storage'].items():
            blk.set_storage_data(address,
                                 utils.big_endian_to_int(decode_hex(k[2:])),
                                 utils.big_endian_to_int(decode_hex(v[2:])))

    # execute transactions
    sender = decode_hex(exek['caller'])  # a party that originates a call
    recvaddr = decode_hex(exek['address'])
    nonce = blk._get_acct_item(sender, 'nonce')
    gasprice = parse_int_or_hex(exek['gasPrice'])
    startgas = parse_int_or_hex(exek['gas'])
    value = parse_int_or_hex(exek['value'])
    data = decode_hex(exek['data'][2:])

    # bypass gas check in tx initialization by temporarily increasing startgas
    num_zero_bytes = str_to_bytes(data).count(ascii_chr(0))
    num_non_zero_bytes = len(data) - num_zero_bytes
    intrinsic_gas = (opcodes.GTXCOST + opcodes.GTXDATAZERO * num_zero_bytes +
                     opcodes.GTXDATANONZERO * num_non_zero_bytes)
    startgas += intrinsic_gas
    tx = transactions.Transaction(nonce=nonce, gasprice=gasprice, startgas=startgas,
                                  to=recvaddr, value=value, data=data)
    tx.startgas -= intrinsic_gas
    tx.sender = sender

    # capture apply_message calls
    apply_message_calls = []
    orig_apply_msg = pb.apply_msg

    ext = pb.VMExt(blk, tx)

    def msg_wrapper(msg):
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(dict(gasLimit=to_string(msg.gas),
                                        value=to_string(msg.value),
                                        destination=encode_hex(msg.to),
                                        data=b'0x' + hexdata))
        return 1, msg.gas, b''

    def create_wrapper(msg):
        sender = decode_hex(msg.sender) if \
            len(msg.sender) == 40 else msg.sender
        nonce = utils.encode_int(ext._block.get_nonce(msg.sender))
        addr = utils.sha3(rlp.encode([sender, nonce]))[12:]
        hexdata = encode_hex(msg.data.extract_all())
        apply_message_calls.append(dict(gasLimit=to_string(msg.gas),
                                        value=to_string(msg.value),
                                        destination=b'', data=b'0x' + hexdata))
        return 1, msg.gas, addr

    ext.msg = msg_wrapper
    ext.create = create_wrapper

    def blkhash(n):
        if n >= ext.block_number or n < ext.block_number - 256:
            return b''
        else:
            return utils.sha3(to_string(n))

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([safe_ord(x) for x in tx.data]))
    code = decode_hex(exek['code'][2:])
    time_pre = time.time()
    if profiler:
        profiler.enable()
    success, gas_remained, output = vm.vm_execute(ext, msg, code)
    if profiler:
        profiler.disable()
    pb.apply_msg = orig_apply_msg
    blk.commit_state()
    for s in blk.suicides:
        blk.del_account(s)
    time_post = time.time()

    """
     generally expected that the test implementer will read env, exec and pre
     then check their results against gas, logs, out, post and callcreates.
     If an exception is expected, then latter sections are absent in the test.
     Since the reverting of the state is not part of the VM tests.
     """

    params2 = copy.deepcopy(params)

    if success:
        params2['callcreates'] = apply_message_calls
        params2['out'] = b'0x' + encode_hex(b''.join(map(ascii_chr, output)))
        params2['gas'] = to_string(gas_remained)
        params2['logs'] = [log.to_dict() for log in blk.logs]
        params2['post'] = blk.to_dict(with_state=True)['state']

    if mode == FILL:
        return params2
    elif mode == VERIFY:
        if not success:
            assert 'post' not in params, 'failed, but expected to succeed'

        params1 = copy.deepcopy(params)
        shouldbe, reallyis = params1.get('post', None), params2.get('post', None)
        compare_post_states(shouldbe, reallyis)

        def normalize_value(k, p):
            if k in p:
                if k == 'gas':
                    return parse_int_or_hex(p[k])
                elif k == 'callcreates':
                    return list(map(callcreate_standard_form, p[k]))
                else:
                    return utils.to_string(k)
            return None

        for k in ['pre', 'exec', 'env', 'callcreates',
                  'out', 'gas', 'logs']:
            shouldbe = normalize_value(k, params1)
            reallyis = normalize_value(k, params2)
            if shouldbe != reallyis:
                raise Exception("Mismatch: " + k + ':\n shouldbe %r\n reallyis %r' %
                                (shouldbe, reallyis))
    elif mode == TIME:
        return time_post - time_pre