Example #1
0
def run_test_vm(params):
    print params
    pre = params['pre']
    exek = params['exec']
    callcreates = params.get('callcreates', [])
    env = params['env']
    post = params.get('post', {})

    check_testdata(env.keys(), ['currentGasLimit', 'currentTimestamp',
                                'previousHash', 'currentCoinbase',
                                'currentDifficulty', 'currentNumber'])
    # setup env
    blk = blocks.Block(db,
                       prevhash=env['previousHash'].decode('hex'),
                       number=int(env['currentNumber']),
                       coinbase=env['currentCoinbase'],
                       difficulty=int(env['currentDifficulty']),
                       gas_limit=int(env['currentGasLimit']),
                       timestamp=int(env['currentTimestamp']))

    # code FIXME WHAT TO DO WITH THIS CODE???
    # if isinstance(env['code'], str):
    #     continue
    # else:
    # addr = 0 # FIXME
    #     blk.set_code(addr, ''.join(map(chr, env['code'])))

    # setup state
    for address, h in pre.items():
        check_testdata(h.keys(), ['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, int(h['nonce']))
        blk.set_balance(address, int(h['balance']))
        blk.set_code(address, h['code'][2:].decode('hex'))
        for k, v in h['storage'].iteritems():
            blk.set_storage_data(address,
                                 u.big_endian_to_int(k[2:].decode('hex')),
                                 u.big_endian_to_int(v[2:].decode('hex')))

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

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

    ext = pb.VMExt(blk, tx)

    def call_wrapper(msg):
        ext.set_balance(msg.sender, ext.get_balance(msg.sender) - msg.value)
        hexdata = msg.data.extract_all().encode('hex')
        apply_message_calls.append(dict(gasLimit=msg.gas, value=msg.value,
                                        destination=msg.to, data=hexdata))
        return 1, msg.gas, ''

    def sendmsg_wrapper(msg, code):
        ext.set_balance(msg.sender, ext.get_balance(msg.sender) - msg.value)
        hexdata = msg.data.extract_all().encode('hex')
        apply_message_calls.append(dict(gasLimit=msg.gas, value=msg.value,
                                        destination=msg.to, data=hexdata))
        return 1, msg.gas, ''

    def create_wrapper(msg):
        ext.set_balance(msg.sender, ext.get_balance(msg.sender) - msg.value)
        sender = msg.sender.decode('hex') if len(msg.sender) == 40 else msg.sender
        nonce = u.encode_int(ext._block.get_nonce(msg.sender))
        addr = u.sha3(rlp.encode([sender, nonce]))[12:].encode('hex')
        hexdata = msg.data.extract_all().encode('hex')
        apply_message_calls.append(dict(gasLimit=msg.gas, value=msg.value,
                                        destination='', data=hexdata))
        return 1, msg.gas, addr

    ext.sendmsg = sendmsg_wrapper
    ext.call = call_wrapper
    ext.create = create_wrapper

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

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([ord(x) for x in tx.data]))
    success, gas_remained, output = \
        vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))
    pb.apply_msg = orig_apply_msg
    blk.commit_state()

    """
     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.
     """

    if not success:
        assert 'gas' not in params
        assert 'post' not in params
        return

    for k in ['gas', 'logs', 'out', 'post', 'callcreates']:
        assert k in params
    assert len(callcreates) == len(apply_message_calls)

    # check against callcreates
    for i, callcreate in enumerate(callcreates):
        amc = apply_message_calls[i]
        assert callcreate['data'] == '0x' + amc['data']
        assert callcreate['gasLimit'] == str(amc['gasLimit'])
        assert callcreate['value'] == str(amc['value'])
        assert callcreate['destination'] == amc['destination']

    if 'out' in params:
        assert '0x' + ''.join(map(chr, output)).encode('hex') == params['out']
    if 'gas' in params:
        assert str(gas_remained) == params['gas']
    if 'logs' in params:
        """
        The logs sections is a mapping between the blooms and their corresponding logentries.
        Each logentry has the format:
        address: The address of the logentry.
        data: The data of the logentry.
        topics: The topics of the logentry, given as an array of values.
        """
        test_logs = params['logs']
        vm_logs = []
        for log in tx.logs:
            vm_logs.append({
                "bloom": bloom.b64(bloom.bloom_from_list(log.bloomables())).encode('hex'),
                "address": log.address,
                "data": '0x' + log.data.encode('hex'),
                "topics": [u.zpad(u.int_to_big_endian(t), 32).encode('hex') for t in log.topics]
            })

        assert len(vm_logs) == len(test_logs)
        assert vm_logs == test_logs

    # check state
    for address, data in post.items():
        state = blk.account_to_dict(address, for_vmtest=True)
        state.pop('storage_root', None)  # attribute not present in vmtest fixtures
        assert data == state
Example #2
0
def run_test_vm(params):
    pre = params['pre']
    exek = params['exec']
    callcreates = params.get('callcreates', [])
    env = params['env']
    post = params.get('post', {})

    check_testdata(env.keys(), [
        'currentGasLimit', 'currentTimestamp', 'previousHash',
        'currentCoinbase', 'currentDifficulty', 'currentNumber'
    ])
    # setup env
    db = new_db()
    blk = blocks.Block(db,
                       prevhash=env['previousHash'].decode('hex'),
                       number=int(env['currentNumber']),
                       coinbase=env['currentCoinbase'],
                       difficulty=int(env['currentDifficulty']),
                       gas_limit=int(env['currentGasLimit']),
                       timestamp=int(env['currentTimestamp']))

    # code FIXME WHAT TO DO WITH THIS CODE???
    # if isinstance(env['code'], str):
    #     continue
    # else:
    # addr = 0 # FIXME
    #     blk.set_code(addr, ''.join(map(chr, env['code'])))

    # setup state
    for address, h in pre.items():
        check_testdata(h.keys(), ['code', 'nonce', 'balance', 'storage'])
        blk.set_nonce(address, int(h['nonce']))
        blk.set_balance(address, int(h['balance']))
        blk.set_code(address, h['code'][2:].decode('hex'))
        for k, v in h['storage']:
            blk.set_storage_data(address, u.big_endian_to_int(k.decode('hex')),
                                 u.big_endian_to_int(v.decode('hex')))

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

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

    def apply_msg_wrapper(_ext, msg, code, toplevel=False):
        hexdata = msg.data.extract_all().encode('hex')
        apply_message_calls.append(
            dict(gasLimit=msg.gas,
                 value=msg.value,
                 destination=msg.to,
                 data=hexdata))
        if not toplevel:
            pb.apply_msg = orig_apply_msg
        result, gas_rem, data = orig_apply_msg(_ext, msg, code)
        if not toplevel:
            pb.apply_msg = apply_msg_wrapper
        return result, gas_rem, data

    pb.apply_msg = apply_msg_wrapper

    ext = pb.VMExt(blk, tx)
    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([ord(x) for x in tx.data]))
    success, gas_remained, output = \
        vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))
    pb.apply_msg = orig_apply_msg
    blk.commit_state()
    """
     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.
     """

    if not success:
        return

    for k in ['gas', 'logs', 'out', 'post', 'callcreates']:
        assert k in params
    assert len(callcreates) == len(apply_message_calls)

    # check against callcreates
    for i, callcreate in enumerate(callcreates):
        amc = apply_message_calls[i]
        assert callcreate['data'] == '0x' + amc['data']
        assert callcreate['gasLimit'] == str(amc['gasLimit'])
        assert callcreate['value'] == str(amc['value'])
        assert callcreate['destination'] == amc['destination']

    if 'out' in params:
        assert '0x' + ''.join(map(chr, output)).encode('hex') == params['out']
    if 'gas' in params:
        assert str(gas_remained) == params['gas']
    if 'logs' in params:
        """
        The logs sections is a mapping between the blooms and their corresponding logentries.
        Each logentry has the format:
        address: The address of the logentry.
        data: The data of the logentry.
        topics: The topics of the logentry, given as an array of values.
        """
        test_logs = params['logs']
        vm_logs = []
        for log in tx.logs:
            vm_logs.append({
                "bloom":
                bloom.b64(bloom.bloom_from_list(
                    log.bloomables())).encode('hex'),
                "address":
                log.address,
                "data":
                '0x' + log.data.encode('hex'),
                "topics": [
                    u.zpad(u.int_to_big_endian(t), 32).encode('hex')
                    for t in log.topics
                ]
            })

        assert len(vm_logs) == len(test_logs)
        assert vm_logs == test_logs

    # check state
    for address, data in post.items():
        state = blk.account_to_dict(address, for_vmtest=True)
        state.pop('storage_root',
                  None)  # attribute not present in vmtest fixtures
        assert data == state

    db.delete_db()
Example #3
0
def profile_vm_test(params):
    pre = params['pre']
    exek = params['exec']
    env = params['env']

    # setup env
    blk = blocks.Block(db,
                       prevhash=env['previousHash'].decode('hex'),
                       number=int(env['currentNumber']),
                       coinbase=env['currentCoinbase'],
                       difficulty=int(env['currentDifficulty']),
                       gas_limit=int(env['currentGasLimit']),
                       timestamp=int(env['currentTimestamp']))

    # setup state
    for address, h in pre.items():
        blk.set_nonce(address, int(h['nonce']))
        blk.set_balance(address, int(h['balance']))
        blk.set_code(address, h['code'][2:].decode('hex'))
        for k, v in h['storage'].iteritems():
            blk.set_storage_data(address,
                                 u.big_endian_to_int(k[2:].decode('hex')),
                                 u.big_endian_to_int(v[2:].decode('hex')))

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

    ext = pb.VMExt(blk, tx)

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

    ext.block_hash = blkhash

    msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                     vm.CallData([ord(x) for x in tx.data]))
    blk2 = blocks.Block.deserialize(db, blk.serialize())
    t1 = time.time()
    success, gas_remained, output = \
        vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))
    blk.commit_state()
    t2 = time.time()
    recorder = LogRecorder()
    ext = pb.VMExt(blk2, tx)
    ext.block_hash = blkhash
    success, gas_remained, output = \
        vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))
    trace = recorder.pop_records()
    ops = [x['op'] for x in trace if x['event'] == 'vm']
    opdict = {}
    for op in ops:
        opdict[op] = opdict.get(op, 0) + 1
    return {"ops": opdict, "time": t2 - t1}
Example #4
0
def generate_op_tests():
    outs = {}
    for opcode, (name, inargs, outargs, _) in opcodes.opcodes.items():
     _subid = 0
     for push_depths in push_params:
      for jump_num, code_size in codesize_params:
        if name in ['CALL', 'CREATE', 'CALLCODE', 'LOG', 'POP', 'RETURN', 'STOP', 'INVALID', 'JUMP', 'JUMPI', 'CALLDATALOAD', 'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY', 'SHA3', 'MLOAD', 'MSTORE', 'MSTORE8', 'SUICIDE']:
            continue
        if name[:3] in ['DUP', 'SWA', 'LOG']:
            continue
        if name == 'SSTORE':
            jump_num /= 10
        c = '\x5b'
        if name[:4] == 'PUSH':
            if push_depths != push_params[0]:
                continue
            for i in range(code_size):
                v = int(name[4:])
                w = random.randrange(256**v)
                c += chr(0x5f + v) + utils.zpad(utils.encode_int(w), v)
        else:
            for i in range(code_size):
                for _ in range(inargs):
                    v = push_depths[i * len(push_depths) // code_size]
                    w = random.randrange(256**v)
                    c += chr(0x5f + v) + utils.zpad(utils.encode_int(w), v)
                c += chr(opcode)
                for _ in range(outargs):
                    c += chr(0x50)
        # PUSH1 0 MLOAD . DUP1 . PUSH1 1 ADD PUSH1 0 MSTORE . PUSH2 <jumps> GT PUSH1 0 JUMPI
        c += '\x60\x00\x51' + '\x80' + '\x60\x01\x01\x60\x00\x52' + \
            '\x61'+chr(jump_num // 256) + chr(jump_num % 256) + '\x11\x60\x00\x57'
        o = {
            "callcreates": [],
            "env": {
                "currentCoinbase": "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
                "currentDifficulty": "256",
                "currentGasLimit": "1000000000",
                "currentNumber": "257",
                "currentTimestamp": "1",
                "previousHash": "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
            },
            "exec": {
                "address": "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
                "caller": "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
                "code": "0x"+c.encode('hex'),
                "data": "0x",
                "gas": "1000000",
                "gasPrice": "100000000000000",
                "origin": "cd1722f3947def4cf144679da39c4c32bdc35681",
                "value": "1000000000000000000"
            },
            "pre": {
                "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6": {
                    "balance": "1000000000000000000",
                    "code": "0x",
                    "nonce": "0",
                    "storage": {
                    }
                }
            },
            "gas": "1000000",
            "logs": [],
            "out": "0x"
        }
        env = o['env']
        pre = o['pre']
        exek = o['exec']
        blk = blocks.Block(db,
                           prevhash=env['previousHash'].decode('hex'),
                           number=int(env['currentNumber']),
                           coinbase=env['currentCoinbase'],
                           difficulty=int(env['currentDifficulty']),
                           gas_limit=int(env['currentGasLimit']),
                           timestamp=int(env['currentTimestamp']))

        # setup state
        for address, h in pre.items():
            blk.set_nonce(address, int(h['nonce']))
            blk.set_balance(address, int(h['balance']))
            blk.set_code(address, h['code'][2:].decode('hex'))
            for k, v in h['storage'].iteritems():
                blk.set_storage_data(address,
                                     u.big_endian_to_int(k[2:].decode('hex')),
                                     u.big_endian_to_int(v[2:].decode('hex')))

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

        ext = pb.VMExt(blk, tx)

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

        ext.block_hash = blkhash

        msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                         vm.CallData([ord(x) for x in tx.data]))
        success, gas_remained, output = \
            vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))

        o['post'] = blk.to_dict(True)['state']
        outs[name+str(_subid)] = o
        _subid += 1
    return outs
Example #5
0
def generate_op_tests():
    outs = {}
    for opcode, (name, inargs, outargs, _) in opcodes.opcodes.items():
        _subid = 0
        for push_depths in push_params:
            for jump_num, code_size in codesize_params:
                if name in [
                        'CALL', 'CREATE', 'CALLCODE', 'LOG', 'POP', 'RETURN',
                        'STOP', 'INVALID', 'JUMP', 'JUMPI', 'CALLDATALOAD',
                        'CALLDATACOPY', 'CODECOPY', 'EXTCODECOPY', 'SHA3',
                        'MLOAD', 'MSTORE', 'MSTORE8', 'SUICIDE'
                ]:
                    continue
                if name[:3] in ['DUP', 'SWA', 'LOG']:
                    continue
                if name == 'SSTORE':
                    jump_num /= 10
                c = '\x5b'
                if name[:4] == 'PUSH':
                    if push_depths != push_params[0]:
                        continue
                    for i in range(code_size):
                        v = int(name[4:])
                        w = random.randrange(256**v)
                        c += chr(0x5f + v) + utils.zpad(utils.encode_int(w), v)
                else:
                    for i in range(code_size):
                        for _ in range(inargs):
                            v = push_depths[i * len(push_depths) // code_size]
                            w = random.randrange(256**v)
                            c += chr(0x5f + v) + utils.zpad(
                                utils.encode_int(w), v)
                        c += chr(opcode)
                        for _ in range(outargs):
                            c += chr(0x50)
                # PUSH1 0 MLOAD . DUP1 . PUSH1 1 ADD PUSH1 0 MSTORE . PUSH2 <jumps> GT PUSH1 0 JUMPI
                c += '\x60\x00\x51' + '\x80' + '\x60\x01\x01\x60\x00\x52' + \
                    '\x61'+chr(jump_num // 256) + chr(jump_num % 256) + '\x11\x60\x00\x57'
                o = {
                    "callcreates": [],
                    "env": {
                        "currentCoinbase":
                        "2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
                        "currentDifficulty":
                        "256",
                        "currentGasLimit":
                        "1000000000",
                        "currentNumber":
                        "257",
                        "currentTimestamp":
                        "1",
                        "previousHash":
                        "5e20a0453cecd065ea59c37ac63e079ee08998b6045136a8ce6635c7912ec0b6"
                    },
                    "exec": {
                        "address": "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
                        "caller": "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6",
                        "code": "0x" + c.encode('hex'),
                        "data": "0x",
                        "gas": "1000000",
                        "gasPrice": "100000000000000",
                        "origin": "cd1722f3947def4cf144679da39c4c32bdc35681",
                        "value": "1000000000000000000"
                    },
                    "pre": {
                        "0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6": {
                            "balance": "1000000000000000000",
                            "code": "0x",
                            "nonce": "0",
                            "storage": {}
                        }
                    },
                    "gas": "1000000",
                    "logs": [],
                    "out": "0x"
                }
                env = o['env']
                pre = o['pre']
                exek = o['exec']
                blk = blocks.Block(db,
                                   prevhash=env['previousHash'].decode('hex'),
                                   number=int(env['currentNumber']),
                                   coinbase=env['currentCoinbase'],
                                   difficulty=int(env['currentDifficulty']),
                                   gas_limit=int(env['currentGasLimit']),
                                   timestamp=int(env['currentTimestamp']))

                # setup state
                for address, h in pre.items():
                    blk.set_nonce(address, int(h['nonce']))
                    blk.set_balance(address, int(h['balance']))
                    blk.set_code(address, h['code'][2:].decode('hex'))
                    for k, v in h['storage'].iteritems():
                        blk.set_storage_data(
                            address, u.big_endian_to_int(k[2:].decode('hex')),
                            u.big_endian_to_int(v[2:].decode('hex')))

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

                ext = pb.VMExt(blk, tx)

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

                ext.block_hash = blkhash

                msg = vm.Message(tx.sender, tx.to, tx.value, tx.startgas,
                                 vm.CallData([ord(x) for x in tx.data]))
                success, gas_remained, output = \
                    vm.vm_execute(ext, msg, exek['code'][2:].decode('hex'))

                o['post'] = blk.to_dict(True)['state']
                outs[name + str(_subid)] = o
                _subid += 1
    return outs