Exemplo n.º 1
0
def coerce_to_hex(x):
    if isinstance(x, int):
        return util.hexlify(zpad(rlp.int_to_big_endian(x), 20))
    elif len(x) == 40 or len(x) == 0:
        return x
    else:
        return util.hexlify(zpad(x, 20)[-20:])
Exemplo n.º 2
0
def base58_check_decode(s, version):
    """Decode from base58."""
    # Convert the string to an integer
    n = 0
    for c in s:
        n *= 58
        if c not in b58_digits:
            raise Base58Error('Not a valid Base58 character: ‘{}’'.format(c))
        digit = b58_digits.index(c)
        n += digit

    # Convert the integer to bytes
    h = '%x' % n
    if len(h) % 2:
        h = '0' + h
    res = binascii.unhexlify(h.encode('utf8'))

    # Add padding back.
    pad = 0
    for c in s[:-1]:
        if c == b58_digits[0]:
            pad += 1
        else:
            break
    k = version * pad + res

    addrbyte, data, chk0 = k[0:1], k[1:-4], k[-4:]
    if addrbyte != version:
        raise VersionByteError('incorrect version byte')
    chk1 = util.dhash(addrbyte + data)[:4]
    if chk0 != chk1:
        raise Base58ChecksumError('Checksum mismatch: 0x{} ≠ 0x{}'.format(util.hexlify(chk0), util.hexlify(chk1)))
    return data
Exemplo n.º 3
0
def hexprint(x):
    assert type(x) in (bytes, list)
    if not x:
        return '<None>'
    if x != -1:
        return ('0x' + util.hexlify(bytes(x)))
    else:
        return 'OUT OF GAS'
Exemplo n.º 4
0
def base58_encode(binary):
    """Encode the address in base58."""
    # Convert big‐endian bytes to integer
    n = int('0x0' + util.hexlify(binary), 16)

    # Divide that integer into base58
    res = []
    while n > 0:
        n, r = divmod(n, 58)
        res.append(b58_digits[r])
    res = ''.join(res[::-1])

    return res
Exemplo n.º 5
0
def parse (db, tx, message):
    if not config.TESTNET:  # TODO
        return

    try:
        gasprice, startgas, endowment = struct.unpack(FORMAT, message[:LENGTH])
    except struct.error:
        gasprice, startgas, endowment = 0, 0, 0 # TODO: Is this ideal 

    code = util.hexlify(message[LENGTH:])
    source, destination, data = execute.compose(db, tx['source'], '', gasprice, startgas, endowment, code)
    message = data[4:]

    # Execute transaction upon publication, for actual creation of contract.
    execute.parse(db, tx, message)
Exemplo n.º 6
0
def base58_check_encode(original, version):
    """Check if base58 encoding is valid."""
    b = binascii.unhexlify(bytes(original, 'utf-8'))
    d = version + b

    binary = d + util.dhash(d)[:4]
    res = base58_encode(binary)

    # Encode leading zeros as base58 zeros
    czero = 0
    pad = 0
    for c in d:
        if c == czero:
            pad += 1
        else:
            break

    address = b58_digits[0] * pad + res

    if original != util.hexlify(base58_check_decode(address, version)):
        raise AddressError('encoded address does not decode properly')

    return address
Exemplo n.º 7
0
 def get_tx_info(tx_hex, block_index=None):
     # block_index mandatory for transactions before block 335000
     source, destination, shell_amount, fee, data = blocks.get_tx_info(tx_hex, block_index=block_index)
     return source, destination, shell_amount, fee, util.hexlify(data) if data else ''
Exemplo n.º 8
0
def memprint(data):
    line = util.hexlify(bytes(data))
    line = ' '.join([line[i:i+2] for i in range(0, len(line), 2)])
    return line
 def henc(n):
     return util.hexlify(enc(n))
Exemplo n.º 10
0
def parse (db, tx, message):
    if not config.TESTNET:  # TODO
        return

    status = 'valid'
    output, gas_cost, gas_remained = None, None, None

    try:
        # TODO: Use unpack function.
        # Unpack message.
        curr_format = FORMAT + '{}s'.format(len(message) - LENGTH)
        try:
            contract_id, gasprice, startgas, value, payload = struct.unpack(curr_format, message)
            if gasprice > config.MAX_INT or startgas > config.MAX_INT: # TODO: define max for gasprice and startgas
                raise exceptions.UnpackError()
        except (struct.error) as e:
            raise exceptions.UnpackError()

        gas_remained = startgas

        contract_id = util.hexlify(contract_id)
        if contract_id == '0000000000000000000000000000000000000000':
            contract_id = ''

        # ‘Apply transaction’!
        tx_obj = Transaction(tx, contract_id, gasprice, startgas, value, payload)
        block_obj = blocks.Block(db, tx['block_hash'])
        success, output, gas_remained = processblock.apply_transaction(db, tx_obj, block_obj)
        if not success and output == '':
            status = 'out of gas'
        gas_cost = gasprice * (startgas - gas_remained) # different definition from pyethereum’s

    except exceptions.UnpackError as e:
        contract_id, gasprice, startgas, value, payload = None, None, None, None, None
        status = 'invalid: could not unpack'
        output = None
    except processblock.ContractError as e:
        status = 'invalid: no such contract'
        contract_id = None
        output = None
    except processblock.InsufficientStartGas as e:
        have, need = e.args
        logger.debug('Insufficient start gas: have {} and need {}'.format(have, need))
        status = 'invalid: insufficient start gas'
        output = None
    except processblock.InsufficientBalance as e:
        have, need = e.args
        logger.debug('Insufficient balance: have {} and need {}'.format(have, need))
        status = 'invalid: insufficient balance'
        output = None
    except processblock.OutOfGas as e:
        logger.debug('TX OUT_OF_GAS (startgas: {}, gas_remained: {})'.format(startgas, gas_remained))
        status = 'out of gas'
        output = None
    finally:

        if status == 'valid':
            logger.debug('TX FINISHED (gas_remained: {})'.format(gas_remained))

        # Add parsed transaction to message-type–specific table.
        bindings = {
            'tx_index': tx['tx_index'],
            'tx_hash': tx['tx_hash'],
            'block_index': tx['block_index'],
            'source': tx['source'],
            'contract_id': contract_id,
            'gasprice': gasprice,
            'startgas': startgas,
            'gas_cost': gas_cost,
            'gas_remained': gas_remained,
            'value': value,
            'payload': payload,
            'output': output,
            'status': status
        }
        sql='insert into executions values(:tx_index, :tx_hash, :block_index, :source, :contract_id, :gasprice, :startgas, :gas_cost, :gas_remained, :value, :data, :output, :status)'
        cursor = db.cursor()
        cursor.execute(sql, bindings)
Exemplo n.º 11
0
def apply_transaction(db, tx, block):

    ### Make fees proportional to money supply. ###
    # Set initial values. Calculate price multiplier.
    # Multiply prices by multiplier, then by 100; make global variables.
    prices = {
              'GDEFAULT': 1,
              'GMEMORY': 1,
              'GSTORAGE': 100,
              'GTXDATA': 5,
              'GTXCOST': 500
             }
    if config.TESTNET:
        supply = 2600001 * config.UNIT
    else:
        supply = util.shp_supply(db)
    MULTIPLIER = fractions.Fraction(supply, 2700000 * config.UNIT) * MULTIPLIER_CONSTANT_FACTOR
    for key in prices.keys():
        prices[key] = fractions.Fraction(prices[key]) * MULTIPLIER
        prices[key] = math.floor(prices[key].__round__(2))
        prices[key] = max(prices[key], 1)
        assert prices[key] > 0
        exec('''global {}; {} = prices['{}']'''.format(key, key, key))

    # (3) the gas limit is no smaller than the intrinsic gas,
    # g0, used by the transaction;
    intrinsic_gas_used = GTXDATA * len(tx.data) + GTXCOST
    if tx.startgas < intrinsic_gas_used:
        raise InsufficientStartGas(tx.startgas, intrinsic_gas_used)

    # (4) the sender account balance contains at least the
    # cost, v0, required in up-front payment.
    total_cost = tx.value + tx.gasprice * tx.startgas
    if block.get_balance(tx.sender) < total_cost:
        raise InsufficientBalance(block.get_balance(tx.sender), total_cost)

    pblogger.log('TX NEW', tx=tx.hex_hash(), tx_dict=tx.to_dict())
    # log('TX NEW', tx_dict)
    # start transacting #################
    block.increment_nonce(tx.sender)

    # buy startgas
    success = block.transfer_value(tx, tx.sender, None,
                                   tx.gasprice * tx.startgas)
    assert success

    message_gas = tx.startgas - intrinsic_gas_used
    message = Message(tx.sender, tx.to, tx.value, message_gas, tx.data)


    primary_result = None

    # Postqueue
    block.postqueue_delete()
    block.postqueue_insert(message)
    while block.postqueue_get():
        message = block.postqueue_pop()
        # MESSAGE
        if tx.to and tx.to != CREATE_CONTRACT_ADDRESS:
            result, gas_remained, data = apply_msg_send(db, block, tx, message)
        else:  # CREATE
            result, gas_remained, data = create_contract(db, block, tx, message)
        if not primary_result:
            primary_result = result, gas_remained, data

    result, gas_remained, data = primary_result

    assert gas_remained >= 0

    pblogger.log("TX APPLIED", result=result, gas_remained=gas_remained,
                 data=util.hexlify(bytes(data)))
    # if pblogger.log_block:
    #     pblogger.log('BLOCK', block=block.to_dict(with_state=True, full_transactions=True))


    if not result:  # 0 = OOG failure in both cases
        pblogger.log('TX FAILED', reason='out of gas', startgas=tx.startgas, gas_remained=gas_remained)
        output = OUT_OF_GAS
    else:
        pblogger.log('TX SUCCESS')
        assert gas_remained == int(gas_remained)
        gas_remained = int(gas_remained)
        # sell remaining gas
        block.transfer_value(
            tx, None, tx.sender, tx.gasprice * gas_remained)
        if tx.to:
            # output = ''.join(map(chr, data))
            output = bytes(data)
        else:
            output = result
    # block.commit_state()

    # Kill suicidal contract.
    for s in block.suicides_get():
        block.del_account(s['contract_id'])
    block.suicides_delete()
    # success = output is not OUT_OF_GAS
    # return success, output if success else ''
    if output == OUT_OF_GAS:
        success = False
        output = ''
    else:
        success = True
    return success, output, gas_remained
Exemplo n.º 12
0
def apply_op(db, block, tx, msg, processed_code, compustate):
    # Does not include paying opfee.

    if compustate.pc >= len(processed_code):
        return []
    op, in_args, out_args, mem_grabs, fee, opcode = processed_code[compustate.pc]

    # print('APPLYING OP', op)
    # print('INARGS', in_args)
    # print('COMPUSTATE.STACK', compustate.stack)

    # empty stack error
    if in_args > len(compustate.stack):
        logger.debug('INSUFFICIENT STACK ERROR (op: {}, needed: {}, available: {})'.format(op, in_args,
                     len(compustate.stack)))
        return []

    # out of gas error
    if fee > compustate.gas:
        return out_of_gas_exception('base_gas', fee, compustate, op)

    pblogger.log('STK', stk=list(reversed(compustate.stack)))

    for i in range(0, len(compustate.memory), 16):
        memblk = compustate.memory[i:i+16]
        # logger.debug('MEM {}'.format(memprint(memblk)))

    # logger.debug('\tSTORAGE\n\t\t' + '\n\t\t'.join(['{}: {}'.format(utils.hexprint(storage['key']), utils.hexprint(storage['value'])) for storage in block.get_storage_data(msg.to)]))

    # Log operation
    log_args = dict(pc=str(compustate.pc),
                    op=op,
                    stackargs=compustate.stack[-1:-in_args-1:-1],
    #               stack=list(reversed(compustate.stack)),
                    gas=compustate.gas)
    if op[:4] == 'PUSH':
        ind = compustate.pc + 1
        log_args['value'] = \
            utils.bytearray_to_int([x[-1] for x in processed_code[ind: ind + int(op[4:])]])
    elif op == 'CALLDATACOPY':
        log_args['data'] = binascii.hexlify(msg.data)
    # log('OP', log_args)
    pblogger.log('OP', **log_args)

    # Apply operation
    compustate.gas -= fee
    compustate.pc += 1
    stk = compustate.stack
    mem = compustate.memory
    if op == 'STOP' or op == 'INVALID':
        return []
    elif op == 'ADD':
        stk.append((stk.pop() + stk.pop()) % TT256)
    elif op == 'SUB':
        stk.append((stk.pop() - stk.pop()) % TT256)
    elif op == 'MUL':
        stk.append((stk.pop() * stk.pop()) % TT256)
    elif op == 'DIV':
        s0, s1 = stk.pop(), stk.pop()
        stk.append(0 if s1 == 0 else s0 // s1)
    elif op == 'MOD':
        s0, s1 = stk.pop(), stk.pop()
        stk.append(0 if s1 == 0 else s0 % s1)
    elif op == 'SDIV':
        s0, s1 = to_signed(stk.pop()), to_signed(stk.pop())
        stk.append(0 if s1 == 0 else (s0 // s1) % TT256)
    elif op == 'SMOD':
        s0, s1 = to_signed(stk.pop()), to_signed(stk.pop())
        stk.append(0 if s1 == 0 else (s0 % s1) % TT256)
    elif op == 'EXP':
        stk.append(pow(stk.pop(), stk.pop(), TT256))
    elif op == 'NEG':
        stk.append(-stk.pop() % TT256)
    elif op == 'LT':
        stk.append(1 if stk.pop() < stk.pop() else 0)
    elif op == 'GT':
        stk.append(1 if stk.pop() > stk.pop() else 0)
    elif op == 'SLT':
        s0, s1 = to_signed(stk.pop()), to_signed(stk.pop())
        stk.append(1 if s0 < s1 else 0)
    elif op == 'SGT':
        s0, s1 = to_signed(stk.pop()), to_signed(stk.pop())
        stk.append(1 if s0 > s1 else 0)
    elif op == 'EQ':
        stk.append(1 if stk.pop() == stk.pop() else 0)
    elif op == 'NOT':
        stk.append(0 if stk.pop() else 1)
    elif op == 'AND':
        stk.append(stk.pop() & stk.pop())
    elif op == 'OR':
        stk.append(stk.pop() | stk.pop())
    elif op == 'XOR':
        stk.append(stk.pop() ^ stk.pop())
    elif op == 'BYTE':
        s0, s1 = stk.pop(), stk.pop()
        if s0 >= 32:
            stk.append(0)
        else:
            stk.append((s1 // 256 ** (31 - s0)) % 256)
    elif op == 'ADDMOD':
        s0, s1, s2 = stk.pop(), stk.pop(), stk.pop()
        stk.append((s0 + s1) % s2 if s2 else 0)
    elif op == 'MULMOD':
        s0, s1, s2 = stk.pop(), stk.pop(), stk.pop()
        stk.append((s0 * s1) % s2 if s2 else 0)
    elif op == 'SHA3':
        s0, s1 = stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + s1):
            return OUT_OF_GAS
        data = bytes(mem[s0: s0 + s1])
        stk.append(rlp.big_endian_to_int(utils.sha3(data)))
    elif op == 'ADDRESS':
        stk.append(utils.coerce_to_int(msg.to))
    elif op == 'BALANCE':
        addr = stk.pop()
        addr = utils.coerce_to_hex(addr)
        stk.append(block.get_balance(addr))
    elif op == 'ASSET_BALANCE':
        addr, asset_id = stk.pop(), stk.pop()
        addr = utils.coerce_to_hex(addr)
        asset_name = util.asset_name(asset_id)
        stk.append(block.get_balance(addr, asset=asset_name))
    elif op == 'SEND':
        # TODO: You can’t send SCH to a contract address.
        addr, quantity, asset_id = stk.pop(), stk.pop(), stk.pop()
        asset_name = util.asset_name(asset_id)
        # TODO: Check balance first.
        block.transfer_value(tx, msg.to, addr, quantity, asset=asset_name)
    elif op == 'ORIGIN':
        stk.append(utils.coerce_to_int(tx.sender))
    elif op == 'CALLER':
        stk.append(utils.coerce_to_int(msg.sender))
    elif op == 'CALLVALUE':
        stk.append(msg.value)
    elif op == 'CALLDATALOAD':
        s0 = stk.pop()
        if s0 >= len(msg.data):
            stk.append(0)
        else:
            dat = msg.data[s0: s0 + 32]
            stk.append(rlp.big_endian_to_int(dat + b'\x00' * (32 - len(dat))))
    elif op == 'CALLDATASIZE':
        stk.append(len(msg.data))
    elif op == 'CALLDATACOPY':
        s0, s1, s2 = stk.pop(), stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + s2):
            return OUT_OF_GAS
        for i in range(s2):
            if s1 + i < len(msg.data):
                mem[s0 + i] = ord(msg.data[s1 + i])
            else:
                mem[s0 + i] = 0
    elif op == 'GASPRICE':
        stk.append(tx.gasprice)
    elif op == 'CODECOPY':
        s0, s1, s2 = stk.pop(), stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + s2):
            return OUT_OF_GAS
        for i in range(s2):
            if s1 + i < len(processed_code):
                mem[s0 + i] = processed_code[s1 + i][-1]
            else:
                mem[s0 + i] = 0
    elif op == 'EXTCODESIZE':
        stk.append(len(block.get_code(stk.pop()) or ''))
    elif op == 'EXTCODECOPY':
        addr, s1, s2, s3 = stk.pop(), stk.pop(), stk.pop(), stk.pop()
        extcode = block.get_code(addr) or ''
        if not mem_extend(mem, compustate, op, s1 + s3):
            return OUT_OF_GAS
        for i in range(s3):
            if s2 + i < len(extcode):
                mem[s1 + i] = ord(extcode[s2 + i])
            else:
                mem[s1 + i] = 0
    elif op == 'PREVHASH':
        stk.append(rlp.big_endian_to_int(block.prevhash))
#    elif op == 'COINBASE':
#        stk.append(rlp.big_endian_to_int(binascii.unhexlify(block.coinbase)))
    elif op == 'TIMESTAMP':
        stk.append(block.timestamp)
    elif op == 'NUMBER':
        stk.append(block.number)
    elif op == 'DIFFICULTY':
        stk.append(block.difficulty)
#    elif op == 'GASLIMIT':
#        stk.append(block.gas_limit)
    elif op == 'POP':
        stk.pop()
    elif op == 'MLOAD':
        s0 = stk.pop()
        if not mem_extend(mem, compustate, op, s0 + 32):
            return OUT_OF_GAS
        data = bytes(mem[s0: s0 + 32])
        stk.append(rlp.big_endian_to_int(data))
    elif op == 'MSTORE':
        s0, s1 = stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + 32):
            return OUT_OF_GAS
        v = s1
        for i in range(31, -1, -1):
            mem[s0 + i] = v % 256
            v //= 256
    elif op == 'MSTORE8':
        s0, s1 = stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + 1):
            return OUT_OF_GAS
        mem[s0] = s1 % 256
    elif op == 'SLOAD':
        stk.append(block.get_storage_data(msg.to, stk.pop()))
    elif op == 'SSTORE':
        s0, s1 = stk.pop(), stk.pop()
        pre_occupied = GSTORAGE if block.get_storage_data(msg.to, s0) else 0
        post_occupied = GSTORAGE if s1 else 0
        gascost = GSTORAGE + post_occupied - pre_occupied
        if compustate.gas < gascost:
            out_of_gas_exception('sstore trie expansion', gascost, compustate, op)
        compustate.gas -= gascost
        block.set_storage_data(msg.to, s0, s1)
    elif op == 'JUMP':
        compustate.pc = stk.pop()
    elif op == 'JUMPI':
        s0, s1 = stk.pop(), stk.pop()
        if s1:
            compustate.pc = s0
    elif op == 'PC':
        stk.append(compustate.pc)
    elif op == 'MSIZE':
        stk.append(len(mem))
    elif op == 'GAS':
        stk.append(compustate.gas)  # AFTER subtracting cost 1
    elif op[:4] == 'PUSH':
        pushnum = int(op[4:])
        dat = [x[-1] for x in processed_code[compustate.pc: compustate.pc + pushnum]]
        compustate.pc += pushnum
        stk.append(utils.bytearray_to_int(dat))
    elif op[:3] == 'DUP':
        depth = int(op[3:])
        # DUP POP POP Debug hint
        is_debug = 1
        for i in range(depth):
            if compustate.pc + i < len(processed_code) and \
                    processed_code[compustate.pc + i][0] != 'POP':
                is_debug = 0
                break
        if is_debug:
            stackargs = [stk.pop() for i in range(depth)]
            stk.extend(reversed(stackargs))
            stk.append(stackargs[-1])
        else:
            stk.append(stk[-depth])
    elif op[:4] == 'SWAP':
        depth = int(op[4:])
        temp = stk[-depth-1]
        stk[-depth-1] = stk[-1]
        stk[-1] = temp
    elif op == 'CREATE':
        value, mstart, msz = stk.pop(), stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, mstart + msz):
            return OUT_OF_GAS
        data = bytes(mem[mstart: mstart + msz])
        # log('SUB CONTRACT NEW', {'sender': msg.to, 'value': value, 'data': util.hexlify(data)})
        pblogger.log('SUB CONTRACT NEW', sender=msg.to, value=value, data=util.hexlify(data))
        create_msg = Message(msg.to, '', value, compustate.gas, data)
        address, gas, code = create_contract(db, block, tx, create_msg)
        # log('SUB CONTRACT OUT', {'address': address, 'code': block.get_code(address)})
        addr = utils.coerce_to_int(address)
        pblogger.log('SUB CONTRACT OUT', address=addr, code=code)
        if addr:
            stk.append(addr)
            compustate.gas = gas
        else:
            stk.append(0)
            compustate.gas = 0
    elif op == 'CALL':
        # TODO: Check that this allows for the sending of SHP to Shellparty addresses, as well as contract addresses.
        gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \
            stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop()
        new_memsize = max(meminstart + meminsz, memoutstart + memoutsz)
        if not mem_extend(mem, compustate, op, new_memsize):
            return OUT_OF_GAS
        if compustate.gas < gas:
            return out_of_gas_exception('subcall gas', gas, compustate, op)
        compustate.gas -= gas
        to = utils.encode_int(to)
        to = util.hexlify(((b'\x00' * (32 - len(to))) + to)[12:])
        data = bytes(mem[meminstart: meminstart + meminsz])
        # log('SUB CALL NEW', {'sender': msg.to, 'to': to, 'value': value, 'gas': gas, 'data': util.hexlify(data)})
        pblogger.log('SUB CALL NEW', sender=msg.to, to=to, value=value, gas=gas, data=util.hexlify(data))
        call_msg = Message(msg.to, to, value, gas, data)
        result, gas, data = apply_msg_send(db, block, tx, call_msg)
        # log('SUB CALL OUT', {'result': result, 'data': data, 'length': data, 'expected': memoutsz})
        pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz)
        if result == 0:
            stk.append(0)
        else:
            stk.append(1)
            compustate.gas += gas
            for i in range(min(len(data), memoutsz)):
                mem[memoutstart + i] = data[i]
    elif op == 'RETURN':
        s0, s1 = stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, s0 + s1):
            return OUT_OF_GAS
        return mem[s0: s0 + s1]
    elif op == 'POST':
        gas, to, value, meminstart, meminsz = \
            stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop()
        if not mem_extend(mem, compustate, op, meminstart + meminsz):
            return OUT_OF_GAS
        if compustate.gas < gas:
            return out_of_gas_exception('subcall gas', gas, compustate, op)
        compustate.gas -= gas
        to = utils.encode_int(to)
        to = util.hexlify(((b'\x00' * (32 - len(to))) + to)[12:])
        data = bytes(mem[meminstart: meminstart + meminsz])
        post_dict = {'sender': msg.to, 'to': to, 'value': value, 'gas': gas, 'data': util.hexlify(data)}
        log('POST NEW', post_dict)
        post_msg = Message(msg.to, to, value, gas, data)
        block.postqueue_append(post_msg)
    elif op == 'CALL_STATELESS':
        gas, to, value, meminstart, meminsz, memoutstart, memoutsz = \
            stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop(), stk.pop()
        new_memsize = max(meminstart + meminsz, memoutstart + memoutsz)
        if not mem_extend(mem, compustate, op, new_memsize):
            return OUT_OF_GAS
        if compustate.gas < gas:
            return out_of_gas_exception('subcall gas', gas, compustate, op)
        compustate.gas -= gas
        to = utils.encode_int(to)
        to = util.hexlify(((b'\x00' * (32 - len(to))) + to)[12:])
        data = bytes(mem[meminstart: meminstart + meminsz])
        # logger.debug('SUB CALL NEW (sender: {}, to: {}, value: {}, gas: {}, data: {})'.format(msg.to, to, value, gas, util.hexlify(data)))
        pblogger.log('SUB CALL NEW', sender=msg.to, to=msg.to, value=value, gas=gas, data=util.hexlify(data))
        call_msg = Message(msg.to, msg.to, value, gas, data)
        result, gas, data = apply_msg(db, block, tx, call_msg, block.get_code(to))
        # logger.debug('SUB CALL OUT (result: {}, data: {}, length: {}, expected: {}'.format(result, data, len(data), memoutsz))
        pblogger.log('SUB CALL OUT', result=result, data=data, length=len(data), expected=memoutsz)
        if result == 0:
            stk.append(0)
        else:
            stk.append(1)
            compustate.gas += gas
            for i in range(min(len(data), memoutsz)):
                mem[memoutstart + i] = data[i]
    elif op == 'SUICIDE':
        to = utils.encode_int(stk.pop())
        to = binascii.hexlify(((b'\x00' * (32 - len(to))) + to)[12:])
        block.transfer_value(tx, msg.to, to, block.get_balance(msg.to))
        block.suicides_append(msg.to)
        return []
    for a in stk:
        assert isinstance(a, int)