Exemplo n.º 1
0
def compose(db, source, timestamp, value, fee_fraction, text):

    # Store the fee fraction as an integer.
    fee_fraction_int = int(fee_fraction * 1e8)

    problems = validate(db, source, timestamp, value, fee_fraction_int, text,
                        util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)

    # always use custom length byte instead of problematic usage of 52p format and make sure to encode('utf-8') for length
    if util.enabled('broadcast_pack_text'):
        data += struct.pack(FORMAT, timestamp, value, fee_fraction_int)
        data += VarIntSerializer.serialize(len(text.encode('utf-8')))
        data += text.encode('utf-8')
    else:
        if len(text) <= 52:
            curr_format = FORMAT + '{}p'.format(len(text) + 1)
        else:
            curr_format = FORMAT + '{}s'.format(len(text))

        data += struct.pack(curr_format, timestamp, value, fee_fraction_int,
                            text.encode('utf-8'))
    return (source, [], data)
Exemplo n.º 2
0
def compose (db, source, asset, give_quantity, escrow_quantity, mainchainrate, status):
    assetid, problems = validate(db, source, asset, give_quantity, escrow_quantity, mainchainrate, status, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, assetid, give_quantity, escrow_quantity, mainchainrate, status)
    return (source, [], data)
Exemplo n.º 3
0
def compose(db, source, asset_dest_quant_list, memo, memo_is_hex):
    cursor = db.cursor()

    out_balances = util.accumulate([(t[0], t[2])
                                    for t in asset_dest_quant_list])
    for (asset, quantity) in out_balances:

        # resolve subassets
        asset = util.resolve_subasset_longname(db, asset)

        if not isinstance(quantity, int):
            raise exceptions.ComposeError(
                'quantities must be an int (in satoshis) for {}'.format(asset))

        balances = list(
            cursor.execute(
                '''SELECT * FROM balances WHERE (address = ? AND asset = ?)''',
                (source, asset)))
        if not balances or balances[0]['quantity'] < quantity:
            raise exceptions.ComposeError(
                'insufficient funds for {}'.format(asset))

    block_index = util.CURRENT_BLOCK_INDEX

    problems = validate(db, source, asset_dest_quant_list, block_index)
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += _encode_mpmaSend(db,
                             asset_dest_quant_list,
                             block_index,
                             memo=memo,
                             memo_is_hex=memo_is_hex)

    return (source, [], data)
Exemplo n.º 4
0
def compose(db, source, give_asset, give_quantity, get_asset, get_quantity,
            expiration, fee_required):
    cursor = db.cursor()

    # resolve subassets
    give_asset = util.resolve_subasset_longname(db, give_asset)
    get_asset = util.resolve_subasset_longname(db, get_asset)

    # Check balance.
    if give_asset != config.BTC:
        balances = list(
            cursor.execute(
                '''SELECT * FROM balances WHERE (address = ? AND asset = ?)''',
                (source, give_asset)))
        if (not balances or balances[0]['quantity'] < give_quantity):
            raise exceptions.ComposeError('insufficient funds')

    problems = validate(db, source, give_asset, give_quantity, get_asset,
                        get_quantity, expiration, fee_required,
                        util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    give_id = util.get_asset_id(db, give_asset, util.CURRENT_BLOCK_INDEX)
    get_id = util.get_asset_id(db, get_asset, util.CURRENT_BLOCK_INDEX)
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, give_id, give_quantity, get_id, get_quantity,
                        expiration, fee_required)
    cursor.close()
    return (source, [], data)
Exemplo n.º 5
0
def pack(db, asset, quantity, tag):
    data = message_type.pack(ID)
    if type(tag) == 'str':
        tag = bytes.fromhex(tag)
    data += struct.pack(FORMAT,
                        util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX),
                        quantity, tag)
    return data
Exemplo n.º 6
0
def compose (db, source, asset, give_quantity, escrow_quantity, mainchainrate, status, open_address=None):
    assetid, problems = validate(db, source, asset, give_quantity, escrow_quantity, mainchainrate, status, open_address, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, assetid, give_quantity, escrow_quantity, mainchainrate, status)
    if status == STATUS_OPEN_EMPTY_ADDRESS and open_address:
        data += address.pack(open_address)
    return (source, [], data)
Exemplo n.º 7
0
def compose(db, source, gasprice, startgas, endowment, code_hex):
    if not config.TESTNET:  # TODO
        return

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, gasprice, startgas, endowment)
    data += binascii.unhexlify(code_hex)

    return (source, [], data)
Exemplo n.º 8
0
def compose(db, source, offer_hash):

    # Check that offer exists.
    _, _, problems = validate(db, source, offer_hash)
    if problems: raise exceptions.ComposeError(problems)

    offer_hash_bytes = binascii.unhexlify(bytes(offer_hash, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, offer_hash_bytes)
    return (source, [], data)
Exemplo n.º 9
0
def compose(db, source, possible_moves, wager, move_random_hash, expiration):

    problems = validate(db, source, possible_moves, wager, move_random_hash, expiration, util.CURRENT_BLOCK_INDEX)

    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, possible_moves, wager, binascii.unhexlify(move_random_hash), expiration)

    return (source, [], data)
Exemplo n.º 10
0
def compose (db, source, offer_hash):

    # Check that offer exists.
    offer, offer_type, problems = validate(db, source, offer_hash)
    if problems: raise exceptions.ComposeError(problems)

    offer_hash_bytes = binascii.unhexlify(bytes(offer_hash, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, offer_hash_bytes)
    return (source, [], data)
Exemplo n.º 11
0
def pack(db, asset, quantity, tag):
    data = message_type.pack(ID)
    if isinstance(tag, str):
        tag = bytes(tag.encode('utf8'))[0:MAX_TAG_LENGTH]
    elif isinstance(tag, bytes):
        tag = tag[0:MAX_TAG_LENGTH]
    else:
        tag = b''

    data += struct.pack(FORMAT, util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX), quantity)
    data += tag
    return data
Exemplo n.º 12
0
def compose(db, source, possible_moves, wager, move_random_hash, expiration):

    problems = validate(db, source, possible_moves, wager, move_random_hash,
                        expiration, util.CURRENT_BLOCK_INDEX)

    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, possible_moves, wager,
                        binascii.unhexlify(move_random_hash), expiration)

    return (source, [], data)
Exemplo n.º 13
0
def compose(db, source, destination, asset, quantity, memo, memo_is_hex):
    cursor = db.cursor()

    # Just send BTC?
    if asset == config.BTC:
        return (source, [(destination, quantity)], None)

    # resolve subassets
    asset = util.resolve_subasset_longname(db, asset)

    #quantity must be in int satoshi (not float, string, etc)
    if not isinstance(quantity, int):
        raise exceptions.ComposeError('quantity must be an int (in satoshi)')

    # Only for outgoing (incoming will overburn).
    balances = list(
        cursor.execute(
            '''SELECT * FROM balances WHERE (address = ? AND asset = ?)''',
            (source, asset)))
    if not balances or balances[0]['quantity'] < quantity:
        raise exceptions.ComposeError('insufficient funds')

    # convert memo to memo_bytes based on memo_is_hex setting
    if memo is None:
        memo_bytes = b''
    elif memo_is_hex:
        memo_bytes = bytes.fromhex(memo)
    else:
        memo = memo.encode('utf-8')
        memo_bytes = struct.pack(">{}s".format(len(memo)), memo)

    block_index = util.CURRENT_BLOCK_INDEX

    problems = validate(db, source, destination, asset, quantity, memo_bytes,
                        block_index)
    if problems: raise exceptions.ComposeError(problems)

    asset_id = util.get_asset_id(db, asset, block_index)

    short_address_bytes = address.pack(destination)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, asset_id, quantity, short_address_bytes)
    data += memo_bytes

    cursor.close()
    # return an empty array as the second argument because we don't need to send BTC dust to the recipient
    return (source, [], data)
Exemplo n.º 14
0
def compose (db, source, quantity_per_unit, asset, dividend_asset):
    # resolve subassets
    asset = util.resolve_subasset_longname(db, asset)
    dividend_asset = util.resolve_subasset_longname(db, dividend_asset)

    dividend_total, outputs, problems, fee = validate(db, source, quantity_per_unit, asset, dividend_asset, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)
    logger.info('Total quantity to be distributed in dividends: {} {}'.format(util.value_out(db, dividend_total, dividend_asset), dividend_asset))

    if dividend_asset == config.BTC:
        return (source, [(output['address'], output['dividend_quantity']) for output in outputs], None)

    asset_id = util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX)
    dividend_asset_id = util.get_asset_id(db, dividend_asset, util.CURRENT_BLOCK_INDEX)
    data = message_type.pack(ID)
    data += struct.pack(FORMAT_2, quantity_per_unit, asset_id, dividend_asset_id)
    return (source, [], data)
Exemplo n.º 15
0
def compose (db, source, feed_address, bet_type, deadline, wager_quantity,
            counterwager_quantity, target_value, leverage, expiration):

    if util.get_balance(db, source, config.XCP) < wager_quantity:
        raise exceptions.ComposeError('insufficient funds')

    problems, leverage = validate(db, source, feed_address, bet_type, deadline, wager_quantity,
                        counterwager_quantity, target_value, leverage, expiration, util.CURRENT_BLOCK_INDEX)
    if util.date_passed(deadline):
        problems.append('deadline passed')
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, bet_type, deadline,
                        wager_quantity, counterwager_quantity, target_value,
                        leverage, expiration)
    return (source, [(feed_address, None)], data)
Exemplo n.º 16
0
def compose (db, source, quantity_per_unit, asset, dividend_asset):
    # resolve subassets
    asset = util.resolve_subasset_longname(db, asset)
    dividend_asset = util.resolve_subasset_longname(db, dividend_asset)

    dividend_total, outputs, problems, fee = validate(db, source, quantity_per_unit, asset, dividend_asset, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)
    logger.info('Total quantity to be distributed in dividends: {} {}'.format(util.value_out(db, dividend_total, dividend_asset), dividend_asset))

    if dividend_asset == config.BTC:
        return (source, [(output['address'], output['dividend_quantity']) for output in outputs], None)

    asset_id = util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX)
    dividend_asset_id = util.get_asset_id(db, dividend_asset, util.CURRENT_BLOCK_INDEX)
    data = message_type.pack(ID)
    data += struct.pack(FORMAT_2, quantity_per_unit, asset_id, dividend_asset_id)
    return (source, [], data)
Exemplo n.º 17
0
def compose (db, source, move, random, rps_match_id):
    tx0_hash, tx1_hash = util.parse_id(rps_match_id)

    txn, rps_match, problems = validate(db, source, move, random, rps_match_id)
    if problems: raise exceptions.ComposeError(problems)

    # Warn if down to the wire.
    time_left = rps_match['match_expire_index'] - util.CURRENT_BLOCK_INDEX
    if time_left < 4:
        logger.warning('Only {} blocks until that rps match expires. The conclusion might not make into the blockchain in time.'.format(time_left))

    tx0_hash_bytes = binascii.unhexlify(bytes(tx0_hash, 'utf-8'))
    tx1_hash_bytes = binascii.unhexlify(bytes(tx1_hash, 'utf-8'))
    random_bytes = binascii.unhexlify(bytes(random, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, move, random_bytes, tx0_hash_bytes, tx1_hash_bytes)
    return (source, [], data)
Exemplo n.º 18
0
def compose (db, source, order_match_id):
    tx0_hash, tx1_hash = util.parse_id(order_match_id)

    destination, btc_quantity, escrowed_asset, escrowed_quantity, order_match, problems = validate(db, source, order_match_id, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    # Warn if down to the wire.
    time_left = order_match['match_expire_index'] - util.CURRENT_BLOCK_INDEX
    if time_left < 4:
        logger.warning('Only {} blocks until that order match expires. The payment might not make into the blockchain in time.'.format(time_left))
    if 10 - time_left < 4:
        logger.warning('Order match has only {} confirmation(s).'.format(10 - time_left))

    tx0_hash_bytes, tx1_hash_bytes = binascii.unhexlify(bytes(tx0_hash, 'utf-8')), binascii.unhexlify(bytes(tx1_hash, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, tx0_hash_bytes, tx1_hash_bytes)
    return (source, [(destination, btc_quantity)], data)
Exemplo n.º 19
0
def compose(db, source, contract_id, gasprice, startgas, value, payload_hex):
    if not config.TESTNET:  # TODO
        return

    payload = binascii.unhexlify(payload_hex)

    if startgas < 0:
        raise processblock.ContractError('negative startgas')
    if gasprice < 0:
        raise processblock.ContractError('negative gasprice')

    # Pack.
    data = message_type.pack(ID)
    curr_format = FORMAT + '{}s'.format(len(payload))
    data += struct.pack(curr_format, binascii.unhexlify(contract_id), gasprice,
                        startgas, value, payload)

    return (source, [], data)
def compose (db, source, destination, asset, quantity, memo, memo_is_hex):
    cursor = db.cursor()

    # Just send BTC?
    if asset == config.BTC:
        return (source, [(destination, quantity)], None)

    # resolve subassets
    asset = util.resolve_subasset_longname(db, asset)

    #quantity must be in int satoshi (not float, string, etc)
    if not isinstance(quantity, int):
        raise exceptions.ComposeError('quantity must be an int (in satoshi)')

    # Only for outgoing (incoming will overburn).
    balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, asset)))
    if not balances or balances[0]['quantity'] < quantity:
        raise exceptions.ComposeError('insufficient funds')

    # convert memo to memo_bytes based on memo_is_hex setting
    if memo is None:
        memo_bytes = b''
    elif memo_is_hex:
        memo_bytes = bytes.fromhex(memo)
    else:
        memo = memo.encode('utf-8')
        memo_bytes = struct.pack(">{}s".format(len(memo)), memo)

    block_index = util.CURRENT_BLOCK_INDEX

    problems = validate(db, source, destination, asset, quantity, memo_bytes, block_index)
    if problems: raise exceptions.ComposeError(problems)

    asset_id = util.get_asset_id(db, asset, block_index)

    short_address_bytes = address.pack(destination)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, asset_id, quantity, short_address_bytes)
    data += memo_bytes

    cursor.close()
    # return an empty array as the second argument because we don't need to send BTC dust to the recipient
    return (source, [], data)
Exemplo n.º 21
0
def compose(db, source, feed_address, bet_type, deadline, wager_quantity,
            counterwager_quantity, target_value, leverage, expiration):

    if util.get_balance(db, source, config.XCP) < wager_quantity:
        raise exceptions.ComposeError('insufficient funds')

    problems, leverage = validate(db, source, feed_address, bet_type, deadline,
                                  wager_quantity, counterwager_quantity,
                                  target_value, leverage, expiration,
                                  util.CURRENT_BLOCK_INDEX)
    if util.date_passed(deadline):
        problems.append('deadline passed')
    if problems: raise exceptions.ComposeError(problems)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, bet_type, deadline, wager_quantity,
                        counterwager_quantity, target_value, leverage,
                        expiration)
    return (source, [(feed_address, None)], data)
Exemplo n.º 22
0
def compose (db, source, destination, flags, memo):
    if memo is None:
        memo = b''
    elif flags & FLAG_BINARY_MEMO:
        memo = bytes.fromhex(memo)
    else:
        memo = memo.encode('utf-8')
        memo = struct.pack(">{}s".format(len(memo)), memo)

    block_index = util.CURRENT_BLOCK_INDEX
    problems = validate(db, source, destination, flags, memo, block_index)
    if problems: raise exceptions.ComposeError(problems)

    short_address_bytes = address.pack(destination)

    data = message_type.pack(ID)
    data += struct.pack(FORMAT, short_address_bytes, flags)
    data += memo

    return (source, [], data)
Exemplo n.º 23
0
def compose(db, source, move, random, rps_match_id):
    tx0_hash, tx1_hash = util.parse_id(rps_match_id)

    txn, rps_match, problems = validate(db, source, move, random, rps_match_id)
    if problems: raise exceptions.ComposeError(problems)

    # Warn if down to the wire.
    time_left = rps_match['match_expire_index'] - util.CURRENT_BLOCK_INDEX
    if time_left < 4:
        logger.warning(
            'Only {} blocks until that rps match expires. The conclusion might not make into the blockchain in time.'
            .format(time_left))

    tx0_hash_bytes = binascii.unhexlify(bytes(tx0_hash, 'utf-8'))
    tx1_hash_bytes = binascii.unhexlify(bytes(tx1_hash, 'utf-8'))
    random_bytes = binascii.unhexlify(bytes(random, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, move, random_bytes, tx0_hash_bytes,
                        tx1_hash_bytes)
    return (source, [], data)
Exemplo n.º 24
0
def compose(db, source, order_match_id):
    tx0_hash, tx1_hash = util.parse_id(order_match_id)

    destination, btc_quantity, _, _, order_match, problems = validate(
        db, source, order_match_id, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    # Warn if down to the wire.
    time_left = order_match['match_expire_index'] - util.CURRENT_BLOCK_INDEX
    if time_left < 4:
        logger.warning(
            'Only {} blocks until that order match expires. The payment might not make into the blockchain in time.'
            .format(time_left))
    if 10 - time_left < 4:
        logger.warning(
            'Order match has only {} confirmation(s).'.format(10 - time_left))

    tx0_hash_bytes, tx1_hash_bytes = binascii.unhexlify(
        bytes(tx0_hash, 'utf-8')), binascii.unhexlify(bytes(tx1_hash, 'utf-8'))
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, tx0_hash_bytes, tx1_hash_bytes)
    return (source, [(destination, btc_quantity)], data)
Exemplo n.º 25
0
def compose (db, source, give_asset, give_quantity, get_asset, get_quantity, expiration, fee_required):
    cursor = db.cursor()

    # resolve subassets
    give_asset = util.resolve_subasset_longname(db, give_asset)
    get_asset = util.resolve_subasset_longname(db, get_asset)

    # Check balance.
    if give_asset != config.BTC:
        balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, give_asset)))
        if (not balances or balances[0]['quantity'] < give_quantity):
            raise exceptions.ComposeError('insufficient funds')

    problems = validate(db, source, give_asset, give_quantity, get_asset, get_quantity, expiration, fee_required, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    give_id = util.get_asset_id(db, give_asset, util.CURRENT_BLOCK_INDEX)
    get_id = util.get_asset_id(db, get_asset, util.CURRENT_BLOCK_INDEX)
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, give_id, give_quantity, get_id, get_quantity,
                        expiration, fee_required)
    cursor.close()
    return (source, [], data)
Exemplo n.º 26
0
def compose(db, source, transfer_destination, asset, quantity, divisible,
            description):

    # Callability is deprecated, so for re‐issuances set relevant parameters
    # to old values; for first issuances, make uncallable.
    cursor = db.cursor()
    cursor.execute(
        '''SELECT * FROM issuances \
                      WHERE (status = ? AND asset = ?)
                      ORDER BY tx_index ASC''', ('valid', asset))
    issuances = cursor.fetchall()
    if issuances:
        last_issuance = issuances[-1]
        callable_ = last_issuance['callable']
        call_date = last_issuance['call_date']
        call_price = last_issuance['call_price']
    else:
        callable_ = False
        call_date = 0
        call_price = 0.0
    cursor.close()

    # check subasset
    subasset_parent = None
    subasset_longname = None
    if util.enabled('subassets'):  # Protocol change.
        subasset_parent, subasset_longname = util.parse_subasset_from_asset_name(
            asset)
        if subasset_longname is not None:
            # try to find an existing subasset
            sa_cursor = db.cursor()
            sa_cursor.execute(
                '''SELECT * FROM assets \
                              WHERE (asset_longname = ?)''',
                (subasset_longname, ))
            assets = sa_cursor.fetchall()
            sa_cursor.close()
            if len(assets) > 0:
                # this is a reissuance
                asset = assets[0]['asset_name']
            else:
                # this is a new issuance
                #   generate a random numeric asset id which will map to this subasset
                asset = util.generate_random_asset()

    call_date, call_price, problems, fee, description, divisible, reissuance, reissued_asset_longname = validate(
        db, source, transfer_destination, asset, quantity, divisible,
        callable_, call_date, call_price, description, subasset_parent,
        subasset_longname, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    asset_id = util.generate_asset_id(asset, util.CURRENT_BLOCK_INDEX)
    if subasset_longname is None or reissuance:
        # Type 20 standard issuance FORMAT_2 >QQ??If
        #   used for standard issuances and all reissuances
        data = message_type.pack(ID)
        if len(description) <= 42:
            curr_format = FORMAT_2 + '{}p'.format(len(description) + 1)
        else:
            curr_format = FORMAT_2 + '{}s'.format(len(description))
        data += struct.pack(curr_format, asset_id, quantity,
                            1 if divisible else 0, 1 if callable_ else 0,
                            call_date or 0, call_price or 0.0,
                            description.encode('utf-8'))
    else:
        # Type 21 subasset issuance SUBASSET_FORMAT >QQ?B
        #   Used only for initial subasset issuance
        # compacts a subasset name to save space
        compacted_subasset_longname = util.compact_subasset_longname(
            subasset_longname)
        compacted_subasset_length = len(compacted_subasset_longname)
        data = message_type.pack(SUBASSET_ID)
        curr_format = SUBASSET_FORMAT + '{}s'.format(
            compacted_subasset_length) + '{}s'.format(len(description))
        data += struct.pack(curr_format, asset_id, quantity,
                            1 if divisible else 0, compacted_subasset_length,
                            compacted_subasset_longname,
                            description.encode('utf-8'))

    if transfer_destination:
        destination_outputs = [(transfer_destination, None)]
    else:
        destination_outputs = []
    return (source, destination_outputs, data)
Exemplo n.º 27
0
def compose (db, source, transfer_destination, asset, quantity, divisible, description):

    # Callability is deprecated, so for re‐issuances set relevant parameters
    # to old values; for first issuances, make uncallable.
    cursor = db.cursor()
    cursor.execute('''SELECT * FROM issuances \
                      WHERE (status = ? AND asset = ?)
                      ORDER BY tx_index ASC''', ('valid', asset))
    issuances = cursor.fetchall()
    if issuances:
        last_issuance = issuances[-1]
        callable_ = last_issuance['callable']
        call_date = last_issuance['call_date']
        call_price = last_issuance['call_price']
    else:
        callable_ = False
        call_date = 0
        call_price = 0.0
    cursor.close()

    # check subasset
    subasset_parent = None
    subasset_longname = None
    if util.enabled('subassets'): # Protocol change.
        subasset_parent, subasset_longname = util.parse_subasset_from_asset_name(asset)
        if subasset_longname is not None:
            # try to find an existing subasset
            sa_cursor = db.cursor()
            sa_cursor.execute('''SELECT * FROM assets \
                              WHERE (asset_longname = ?)''', (subasset_longname,))
            assets = sa_cursor.fetchall()
            sa_cursor.close()
            if len(assets) > 0:
                # this is a reissuance
                asset = assets[0]['asset_name']
            else:
                # this is a new issuance
                #   generate a random numeric asset id which will map to this subasset
                asset = util.generate_random_asset()

    call_date, call_price, problems, fee, description, divisible, reissuance, reissued_asset_longname = validate(db, source, transfer_destination, asset, quantity, divisible, callable_, call_date, call_price, description, subasset_parent, subasset_longname, util.CURRENT_BLOCK_INDEX)
    if problems: raise exceptions.ComposeError(problems)

    asset_id = util.generate_asset_id(asset, util.CURRENT_BLOCK_INDEX)
    if subasset_longname is None or reissuance:
        # Type 20 standard issuance FORMAT_2 >QQ??If
        #   used for standard issuances and all reissuances
        data = message_type.pack(ID)
        if len(description) <= 42:
            curr_format = FORMAT_2 + '{}p'.format(len(description) + 1)
        else:
            curr_format = FORMAT_2 + '{}s'.format(len(description))
        data += struct.pack(curr_format, asset_id, quantity, 1 if divisible else 0, 1 if callable_ else 0,
            call_date or 0, call_price or 0.0, description.encode('utf-8'))
    else:
        # Type 21 subasset issuance SUBASSET_FORMAT >QQ?B
        #   Used only for initial subasset issuance
        # compacts a subasset name to save space
        compacted_subasset_longname = util.compact_subasset_longname(subasset_longname)
        compacted_subasset_length = len(compacted_subasset_longname)
        data = message_type.pack(SUBASSET_ID)
        curr_format = SUBASSET_FORMAT + '{}s'.format(compacted_subasset_length) + '{}s'.format(len(description))
        data += struct.pack(curr_format, asset_id, quantity, 1 if divisible else 0, compacted_subasset_length, compacted_subasset_longname, description.encode('utf-8'))

    if transfer_destination:
        destination_outputs = [(transfer_destination, None)]
    else:
        destination_outputs = []
    return (source, destination_outputs, data)
Exemplo n.º 28
0
def pack(db, asset, quantity, tag):
    data = message_type.pack(ID)
    if type(tag) == 'str':
        tag = bytes.fromhex(tag)
    data += struct.pack(FORMAT, util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX), quantity, tag)
    return data
Exemplo n.º 29
0
def pack(db, asset, quantity, tag):
    data = message_type.pack(ID)
    data += struct.pack(FORMAT,
                        util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX),
                        quantity, tag)
    return data
Exemplo n.º 30
0
def pack(asset, quantity):
    data = message_type.pack(ID)
    data += struct.pack(FORMAT, util.asset_id(asset), quantity)
    return data