def get_holder_count(asset): asset = util.resolve_subasset_longname(self.db, asset) holders = util.holders(self.db, asset, True) addresses = [] for holder in holders: addresses.append(holder['address']) return {asset: len(set(addresses))}
def asset_conservation(db): logger.debug('Checking for conservation of assets.') supplies = util.supplies(db) for asset in supplies.keys(): issued = supplies[asset] held = sum( [holder['address_quantity'] for holder in util.holders(db, asset)]) if held != issued: raise SanityError('{} {} issued ≠ {} {} held'.format( util.value_out(db, issued, asset), asset, util.value_out(db, held, asset), asset)) logger.debug( '{} has been conserved ({} {} both issued and held)'.format( asset, util.value_out(db, issued, asset), asset))
def get_holders(asset): holders = util.holders(db, asset) return holders
def get_holder_count(asset): holders = util.holders(db, asset) addresses = [] for holder in holders: addresses.append(holder['address']) return {asset: len(set(addresses))}
def validate (db, source, quantity_per_unit, asset, dividend_asset, block_index): cursor = db.cursor() problems = [] if asset == config.BTC: problems.append('cannot pay dividends to holders of {}'.format(config.BTC)) if asset == config.XCP: if (not block_index >= 317500) or block_index >= 320000 or config.TESTNET or config.REGTEST: # Protocol change. problems.append('cannot pay dividends to holders of {}'.format(config.XCP)) if quantity_per_unit <= 0: problems.append('non‐positive quantity per unit') # For SQLite3 if quantity_per_unit > config.MAX_INT: problems.append('integer overflow') # Examine asset. issuances = list(cursor.execute('''SELECT * FROM issuances WHERE (status = ? AND asset = ?) ORDER BY tx_index ASC''', ('valid', asset))) if not issuances: problems.append('no such asset, {}.'.format(asset)) return None, None, problems, 0 divisible = issuances[0]['divisible'] # Only issuer can pay dividends. if block_index >= 320000 or config.TESTNET or config.REGTEST: # Protocol change. if issuances[-1]['issuer'] != source: problems.append('only issuer can pay dividends') # Examine dividend asset. if dividend_asset in (config.BTC, config.XCP): dividend_divisible = True else: issuances = list(cursor.execute('''SELECT * FROM issuances WHERE (status = ? AND asset = ?)''', ('valid', dividend_asset))) if not issuances: problems.append('no such dividend asset, {}.'.format(dividend_asset)) return None, None, problems, 0 dividend_divisible = issuances[0]['divisible'] # Calculate dividend quantities. exclude_empty = False if util.enabled('zero_quantity_value_adjustment_1'): exclude_empty = True holders = util.holders(db, asset, exclude_empty) outputs = [] addresses = [] dividend_total = 0 for holder in holders: if block_index < 294500 and not (config.TESTNET or config.REGTEST): # Protocol change. if holder['escrow']: continue address = holder['address'] address_quantity = holder['address_quantity'] if block_index >= 296000 or config.TESTNET or config.REGTEST: # Protocol change. if address == source: continue dividend_quantity = address_quantity * quantity_per_unit if divisible: dividend_quantity /= config.UNIT if not util.enabled('nondivisible_dividend_fix') and not dividend_divisible: dividend_quantity /= config.UNIT # Pre-fix behaviour if dividend_asset == config.BTC and dividend_quantity < config.DEFAULT_MULTISIG_DUST_SIZE: continue # A bit hackish. dividend_quantity = int(dividend_quantity) outputs.append({'address': address, 'address_quantity': address_quantity, 'dividend_quantity': dividend_quantity}) addresses.append(address) dividend_total += dividend_quantity if not dividend_total: problems.append('zero dividend') if dividend_asset != config.BTC: dividend_balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, dividend_asset))) if not dividend_balances or dividend_balances[0]['quantity'] < dividend_total: problems.append('insufficient funds ({})'.format(dividend_asset)) fee = 0 if not problems and dividend_asset != config.BTC: holder_count = len(set(addresses)) if block_index >= 330000 or config.TESTNET or config.REGTEST: # Protocol change. fee = int(0.0002 * config.UNIT * holder_count) if fee: balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, config.XCP))) if not balances or balances[0]['quantity'] < fee: problems.append('insufficient funds ({})'.format(config.XCP)) if not problems and dividend_asset == config.XCP: total_cost = dividend_total + fee if not dividend_balances or dividend_balances[0]['quantity'] < total_cost: problems.append('insufficient funds ({})'.format(dividend_asset)) # For SQLite3 if fee > config.MAX_INT or dividend_total > config.MAX_INT: problems.append('integer overflow') cursor.close() return dividend_total, outputs, problems, fee
def validate (db, source, quantity_per_unit, asset, dividend_asset, block_index): cursor = db.cursor() problems = [] if asset == config.BTC: problems.append('cannot pay dividends to holders of {}'.format(config.BTC)) if asset == config.XCP: if (not block_index >= 317500) or block_index >= 320000 or config.TESTNET: # Protocol change. problems.append('cannot pay dividends to holders of {}'.format(config.XCP)) if quantity_per_unit <= 0: problems.append('non‐positive quantity per unit') # Examine asset. issuances = list(cursor.execute('''SELECT * FROM issuances WHERE (status = ? AND asset = ?) ORDER BY tx_index ASC''', ('valid', asset))) if not issuances: problems.append('no such asset, {}.'.format(asset)) return None, None, problems, 0 divisible = issuances[0]['divisible'] # Only issuer can pay dividends. if block_index >= 320000 or config.TESTNET: # Protocol change. if issuances[-1]['issuer'] != source: problems.append('only issuer can pay dividends') # Examine dividend asset. if dividend_asset in (config.BTC, config.XCP): dividend_divisible = True else: issuances = list(cursor.execute('''SELECT * FROM issuances WHERE (status = ? AND asset = ?)''', ('valid', dividend_asset))) if not issuances: problems.append('no such dividend asset, {}.'.format(dividend_asset)) return None, None, problems, 0 dividend_divisible = issuances[0]['divisible'] # Calculate dividend quantities. holders = util.holders(db, asset) outputs = [] addresses = [] dividend_total = 0 for holder in holders: if block_index < 294500 and not config.TESTNET: # Protocol change. if holder['escrow']: continue address = holder['address'] address_quantity = holder['address_quantity'] if block_index >= 296000 or config.TESTNET: # Protocol change. if address == source: continue dividend_quantity = address_quantity * quantity_per_unit if divisible: dividend_quantity /= config.UNIT if not dividend_divisible: dividend_quantity /= config.UNIT if dividend_asset == config.BTC and dividend_quantity < config.DEFAULT_MULTISIG_DUST_SIZE: continue # A bit hackish. dividend_quantity = int(dividend_quantity) outputs.append({'address': address, 'address_quantity': address_quantity, 'dividend_quantity': dividend_quantity}) addresses.append(address) dividend_total += dividend_quantity if not dividend_total: problems.append('zero dividend') if dividend_asset != config.BTC: dividend_balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, dividend_asset))) if not dividend_balances or dividend_balances[0]['quantity'] < dividend_total: problems.append('insufficient funds ({})'.format(dividend_asset)) fee = 0 if not problems and dividend_asset != config.BTC: holder_count = len(set(addresses)) if block_index >= 330000 or config.TESTNET: # Protocol change. fee = int(0.0002 * config.UNIT * holder_count) if fee: balances = list(cursor.execute('''SELECT * FROM balances WHERE (address = ? AND asset = ?)''', (source, config.XCP))) if not balances or balances[0]['quantity'] < fee: problems.append('insufficient funds ({})'.format(config.XCP)) if not problems and dividend_asset == config.XCP: total_cost = dividend_total + fee if not dividend_balances or dividend_balances[0]['quantity'] < total_cost: problems.append('insufficient funds ({})'.format(dividend_asset)) cursor.close() return dividend_total, outputs, problems, fee
def get_holders(asset): asset = util.resolve_subasset_longname(self.db, asset) holders = util.holders(self.db, asset, True) return holders
def get_holders(asset): asset = util.resolve_subasset_longname(db, asset) holders = util.holders(db, asset) return holders