Пример #1
0
def unpack(db, message, block_index):
    try:
        memo_bytes_length = len(message) - LENGTH
        if memo_bytes_length < 0:
            raise exceptions.UnpackError('invalid message length')
        if memo_bytes_length > MAX_MEMO_LENGTH:
            raise exceptions.UnpackError('memo too long')

        struct_format = FORMAT + ('{}s'.format(memo_bytes_length))
        short_address_bytes, flags, memo_bytes = struct.unpack(struct_format, message)
        if len(memo_bytes) == 0:
            memo_bytes = None
        elif not(flags & FLAG_BINARY_MEMO):
            memo_bytes = memo_bytes.decode('utf-8')

        # unpack address
        full_address = address.unpack(short_address_bytes)
    except (struct.error) as e:
        logger.warning("sweep send unpack error: {}".format(e))
        raise exceptions.UnpackError('could not unpack')

    unpacked = {
      'destination': full_address,
      'flags': flags,
      'memo': memo_bytes,
    }
    return unpacked
Пример #2
0
def _decode_decodeLUT(data):
    (numAddresses, ) = struct.unpack('>H', data[0:2])
    if numAddresses == 0:
        raise exceptions.DecodeError('address list can\'t be empty')
    p = 2
    addressList = []
    bytesPerAddress = 21

    for i in range(0, numAddresses):
        addr_raw = data[p:p + bytesPerAddress]

        addressList.append(address.unpack(addr_raw))
        p += bytesPerAddress

    lutNbits = math.ceil(math.log2(numAddresses))

    return addressList, lutNbits, data[p:]
Пример #3
0
def unpack(db, message, block_index):
    try:
        # account for memo bytes
        memo_bytes_length = len(message) - LENGTH
        if memo_bytes_length < 0:
            raise exceptions.UnpackError('invalid message length')
        if memo_bytes_length > MAX_MEMO_LENGTH:
            raise exceptions.UnpackError('memo too long')

        struct_format = FORMAT + ('{}s'.format(memo_bytes_length))
        asset_id, quantity, short_address_bytes, memo_bytes = struct.unpack(
            struct_format, message)
        if len(memo_bytes) == 0:
            memo_bytes = None

        # unpack address
        full_address = address.unpack(short_address_bytes)

        # asset id to name
        asset = util.generate_asset_name(asset_id, block_index)
        if asset == config.BTC:
            raise exceptions.AssetNameError('{} not allowed'.format(
                config.BTC))

    except (struct.error) as e:
        logger.warning("enhanced send unpack error: {}".format(e))
        raise exceptions.UnpackError('could not unpack')

    except (exceptions.AssetNameError, exceptions.AssetIDError) as e:
        logger.warning("enhanced send invalid asset id: {}".format(e))
        raise exceptions.UnpackError('asset id invalid')

    unpacked = {
        'asset': asset,
        'quantity': quantity,
        'address': full_address,
        'memo': memo_bytes,
    }
    return unpacked
def unpack(db, message, block_index):
    try:
        # account for memo bytes
        memo_bytes_length = len(message) - LENGTH
        if memo_bytes_length < 0:
            raise exceptions.UnpackError('invalid message length')
        if memo_bytes_length > MAX_MEMO_LENGTH:
            raise exceptions.UnpackError('memo too long')

        struct_format = FORMAT + ('{}s'.format(memo_bytes_length))
        asset_id, quantity, short_address_bytes, memo_bytes = struct.unpack(struct_format, message)
        if len(memo_bytes) == 0:
            memo_bytes = None

        # unpack address
        full_address = address.unpack(short_address_bytes)

        # asset id to name
        asset = util.generate_asset_name(asset_id, block_index)
        if asset == config.BTC:
            raise exceptions.AssetNameError('{} not allowed'.format(config.BTC))

    except (struct.error) as e:
        logger.warning("enhanced send unpack error: {}".format(e))
        raise exceptions.UnpackError('could not unpack')

    except (exceptions.AssetNameError, exceptions.AssetIDError) as e:
        logger.warning("enhanced send invalid asset id: {}".format(e))
        raise exceptions.UnpackError('asset id invalid')

    unpacked = {
      'asset': asset,
      'quantity': quantity,
      'address': full_address,
      'memo': memo_bytes,
    }
    return unpacked
Пример #5
0
def parse(db, tx, message):
    cursor = db.cursor()

    # Unpack message.
    try:
        action_address = tx['source']
        assetid, give_quantity, escrow_quantity, mainchainrate, dispenser_status = struct.unpack(
            FORMAT, message[0:LENGTH])
        if dispenser_status == STATUS_OPEN_EMPTY_ADDRESS:
            action_address = address.unpack(message[LENGTH:LENGTH + 21])
        asset = util.generate_asset_name(assetid, util.CURRENT_BLOCK_INDEX)
        status = 'valid'
    except (exceptions.UnpackError, struct.error) as e:
        assetid, give_quantity, mainchainrate, asset = None, None, None, None
        status = 'invalid: could not unpack'

    if status == 'valid':
        if dispenser_status == STATUS_OPEN or dispenser_status == STATUS_OPEN_EMPTY_ADDRESS:
            cursor.execute(
                'SELECT * FROM dispensers WHERE source=:source AND asset=:asset AND status=:status',
                {
                    'source': action_address,
                    'asset': asset,
                    'status': STATUS_OPEN
                })
            existing = cursor.fetchall()

            if len(existing) == 0:
                # Create the new dispenser
                try:
                    if dispenser_status == STATUS_OPEN_EMPTY_ADDRESS:
                        cursor.execute(
                            'SELECT count(*) cnt FROM balances WHERE address=:address AND quantity > 0',
                            {'address': action_address})
                        counts = cursor.fetchall()[0]

                        if counts['cnt'] == 0:
                            util.debit(db,
                                       tx['source'],
                                       asset,
                                       escrow_quantity,
                                       action='open dispenser empty addr',
                                       event=tx['tx_hash'])
                            util.credit(db,
                                        action_address,
                                        asset,
                                        escrow_quantity,
                                        action='open dispenser empty addr',
                                        event=tx['tx_hash'])
                            util.debit(db,
                                       action_address,
                                       asset,
                                       escrow_quantity,
                                       action='open dispenser empty addr',
                                       event=tx['tx_hash'])
                        else:
                            status = 'invalid: address not empty'
                    else:
                        util.debit(db,
                                   tx['source'],
                                   asset,
                                   escrow_quantity,
                                   action='open dispenser',
                                   event=tx['tx_hash'])
                except util.DebitError as e:
                    status = 'invalid: insufficient funds'

                if status == 'valid':
                    bindings = {
                        'tx_index': tx['tx_index'],
                        'tx_hash': tx['tx_hash'],
                        'block_index': tx['block_index'],
                        'source': action_address,
                        'asset': asset,
                        'give_quantity': give_quantity,
                        'escrow_quantity': escrow_quantity,
                        'satoshirate': mainchainrate,
                        'status': STATUS_OPEN,
                        'give_remaining': escrow_quantity
                    }
                    sql = 'insert into dispensers values(:tx_index, :tx_hash, :block_index, :source, :asset, :give_quantity, :escrow_quantity, :satoshirate, :status, :give_remaining)'
                    cursor.execute(sql, bindings)
            elif len(existing) == 1 and existing[0][
                    'satoshirate'] == mainchainrate and existing[0][
                        'give_quantity'] == give_quantity:
                if tx["source"] == action_address:
                    # Refill the dispenser by the given amount
                    bindings = {
                        'source': tx['source'],
                        'asset': asset,
                        'status': dispenser_status,
                        'give_remaining':
                        existing[0]['give_remaining'] + escrow_quantity,
                        'status': STATUS_OPEN,
                        'block_index': tx['block_index']
                    }
                    try:
                        util.debit(db,
                                   tx['source'],
                                   asset,
                                   escrow_quantity,
                                   action='refill dispenser',
                                   event=tx['tx_hash'])
                        sql = 'UPDATE dispensers SET give_remaining=:give_remaining \
                            WHERE source=:source AND asset=:asset AND status=:status'

                        cursor.execute(sql, bindings)
                    except (util.DebitError):
                        status = 'insufficient funds'
                else:
                    status = 'invalid: can only refill dispenser from source'
            else:
                status = 'can only have one open dispenser per asset per address'
        elif dispenser_status == STATUS_CLOSED:
            cursor.execute(
                'SELECT give_remaining FROM dispensers WHERE source=:source AND asset=:asset AND status=:status',
                {
                    'source': tx['source'],
                    'asset': asset,
                    'status': STATUS_OPEN
                })
            existing = cursor.fetchall()

            if len(existing) == 1:
                util.credit(db,
                            tx['source'],
                            asset,
                            existing[0]['give_remaining'],
                            action='close dispenser',
                            event=tx['tx_hash'])
                bindings = {
                    'source': tx['source'],
                    'asset': asset,
                    'status': STATUS_CLOSED,
                    'block_index': tx['block_index']
                }
                sql = 'UPDATE dispensers SET give_remaining=0, status=:status WHERE source=:source AND asset=:asset'
                cursor.execute(sql, bindings)
            else:
                status = 'dispenser inexistent'
        else:
            status = 'invalid: status must be one of OPEN or CLOSE'

    if status != 'valid':
        logger.warn("Not storing [dispenser] tx [%s]: %s" %
                    (tx['tx_hash'], status))

    cursor.close()