def listblocks() -> int: """Synch block data from node :return int: number of new blocks synched to database """ # TODO: Handle blockchain forks gracefully client = get_active_rpc_client() height_node = client.getblockcount()['result'] latest_block_obj = Block.select().order_by(Block.height.desc()).first() if latest_block_obj is None: height_db = 0 else: height_db = latest_block_obj.height if height_db == height_node: return 0 synced = 0 for batch in batchwise(range(height_db, height_node), 100): new_blocks = client.listblocks(batch) with data_db.atomic(): for block in new_blocks['result']: addr_obj, adr_created = Address.get_or_create( address=block['miner']) block_obj, blk_created = Block.get_or_create( hash=unhexlify(block['hash']), defaults=dict( time=datetime.fromtimestamp(block['time']), miner=addr_obj, txcount=block['txcount'], height=block['height'], )) if blk_created: synced += 1 log.debug('Synced block {}'.format(block_obj.height)) signals.database_blocks_updated.emit(block_obj.height, height_node) log.debug('Synced {} blocks total.'.format(synced)) return synced
def getblock(): """Process detailed data from individual blocks to find last votes from guardians""" # TODO cleanup this deeply nested mess :) client = get_active_rpc_client() global getblock_proccessed_height blockchain_params = client.getblockchainparams()['result'] pubkeyhash_version = blockchain_params['address-pubkeyhash-version'] checksum_value = blockchain_params['address-checksum-value'] block_objs = Block.multi_tx_blocks().where( Block.height > getblock_proccessed_height) votes_changed = False with data_db.atomic(): for block_obj in block_objs: height = block_obj.height block_info = client.getblock("{}".format(height))['result'] for txid in block_info['tx']: transaction = client.getrawtransaction(txid, 4) if transaction['error'] is None: if 'vout' in transaction['result']: vout = transaction['result']['vout'] permissions = [] start_block = None end_block = None for vout_key, entry in enumerate(vout): if len(entry['permissions']) > 0: for key, perm in entry['permissions'][0].items( ): if perm and key in permission_candidates: permissions.append(key) if key == 'startblock': start_block = perm if key == 'endblock': end_block = perm in_entry = transaction['result']['vin'][ vout_key] public_key = in_entry['scriptSig'][ 'asm'].split(' ')[1] from_pubkey = public_key_to_address( public_key, pubkeyhash_version, checksum_value) given_to = entry['scriptPubKey']['addresses'] for addr in given_to: log.debug( 'Grant or Revoke {} given by {} to {} at time {}' .format(permissions, from_pubkey, addr, block_obj.time)) addr_from_obj, _ = Address.get_or_create( address=from_pubkey) addr_to_obj, _ = Address.get_or_create( address=addr) vote_obj, created = Vote.get_or_create( txid=txid, defaults=dict( from_address=addr_from_obj, to_address_id=addr_to_obj, time=block_obj.time)) if created: votes_changed = True getblock_proccessed_height = height if votes_changed: signals.votes_changed.emit()
def listpermissions(): client = get_active_rpc_client() node_height = client.getblockcount()['result'] perms = client.listpermissions() if not perms: log.warning('no permissions from api') return new_perms, new_votes = False, False Permission.delete().execute() CurrentVote.delete().execute() admin_addresses = set() miner_addresses = set() with data_db.atomic(): profile = Profile.get_active() for perm in perms['result']: perm_type = perm['type'] perm_start = perm['startblock'] perm_end = perm['endblock'] if perm_type not in Permission.PERM_TYPES: continue if perm_type == Permission.ADMIN and perm_start < node_height < perm_end: admin_addresses.add(perm['address']) if perm_type == Permission.MINE and perm_start < node_height < perm_end: miner_addresses.add(perm['address']) addr_obj, created = Address.get_or_create(address=perm['address']) for vote in perm['pending']: # If candidate has already the permission continue. if vote['startblock'] == perm['startblock'] and vote[ 'endblock'] == perm['endblock']: continue start_block = vote['startblock'] end_block = vote['endblock'] # new stuff start for admin in vote['admins']: admin_obj, created = Address.get_or_create(address=admin) vote_obj, created = CurrentVote.get_or_create( address=addr_obj, perm_type=perm_type, start_block=start_block, end_block=end_block, given_from=admin_obj) vote_obj.set_vote_type() # new stuff end approbations = len(vote['admins']) # TODO: Fix: current time of syncing is not the time of first_vote! start_block = perm['startblock'] end_block = perm['endblock'] # TODO Why get_or_create ... we just deleted all Permission objects perm_obj, created = Permission.get_or_create( address=addr_obj, perm_type=perm_type, defaults=dict(start_block=start_block, end_block=end_block)) if created: new_perms = True else: perm_obj.save() new_is_admin = profile.address in admin_addresses if profile.is_admin != new_is_admin: profile.is_admin = new_is_admin new_is_miner = profile.address in miner_addresses if profile.is_miner != new_is_miner: profile.is_miner = new_is_miner if profile.dirty_fields: profile.save() # Todo: maybe only trigger table updates on actual change? signals.listpermissions.emit() # triggers community tab updates signals.votes_changed.emit() # triggers community tab updates return {'new_perms': new_perms, 'new_votes': new_votes}