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
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:]
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
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()