def validate(db, source, destination, asset, quantity, block_index): try: util.get_asset_id(db, asset, block_index) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') try: script.validate(destination) except AddressError: raise ValidateError('destination address invalid') if asset == config.BTC: raise ValidateError('cannot send {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('quantity too large') if quantity <= 0: raise ValidateError('quantity non‐positive') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
def validate(db, source, destination, asset, quantity): try: util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') if destination: raise ValidateError('destination exists') if asset == config.BTC: raise ValidateError('cannot destroy {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('integer overflow, quantity too large') if quantity < 0: raise ValidateError('quantity negative') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
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)
def validate (db, source, destination, asset, quantity): try: util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') if destination: raise ValidateError('destination exists') if asset == config.BTC: raise ValidateError('cannot destroy {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('integer overflow, quantity too large') if quantity < 0: raise ValidateError('quantity negative') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient')
def compose (db, source, quantity_per_unit, asset, 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 = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT_2, quantity_per_unit, asset_id, dividend_asset_id) return (source, [], data)
def validate(db, source, destination, asset, quantity, block_index): try: util.get_asset_id(db, asset, block_index) except AssetError: raise ValidateError('asset invalid') try: script.validate(source) except AddressError: raise ValidateError('source address invalid') try: script.validate(destination) except AddressError: raise ValidateError('destination address invalid') if asset == config.BTC: raise ValidateError('cannot send {}'.format(config.BTC)) if type(quantity) != int: raise ValidateError('quantity not integer') if quantity > config.MAX_INT: raise ValidateError('quantity too large') if quantity <= 0: raise ValidateError('quantity non‐positive') if util.get_balance(db, source, asset) < quantity: raise BalanceError('balance insufficient') if util.enabled('options_require_memo'): # Check destination address options cursor = db.cursor() try: results = cursor.execute( 'SELECT options FROM addresses WHERE address=?', (destination, )) if results: result = results.fetchone() if result and result[ 'options'] & config.ADDRESS_OPTION_REQUIRE_MEMO: raise ValidateError('destination requires memo') finally: cursor.close()
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
def compose (db, source, give_asset, give_quantity, get_asset, get_quantity, expiration, fee_required): cursor = db.cursor() # 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 = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, give_id, give_quantity, get_id, get_quantity, expiration, fee_required) cursor.close() return (source, [], data)
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
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)
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)
def _solve_asset(db, assetName, block_index): asset = util.resolve_subasset_longname(db, assetName) return util.get_asset_id(db, asset, block_index)
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
def pack(db, asset, quantity, tag): data = struct.pack(config.TXTYPE_FORMAT, ID) data += struct.pack(FORMAT, util.get_asset_id(db, asset, util.CURRENT_BLOCK_INDEX), quantity, tag) return data