def register(self): client = get_active_rpc_client() data = { 'json': { 'title': self.title_formatted, 'tophash': self.instance_hash } } if self.extra_formatted: data['json']['extra'] = self.extra_formatted try: client.publish(app.STREAM_ISCC, [ self.meta_id, self.content_id, self.data_id, self.instance_id ], data) self.edit_title.clear() self.label_qr.clear() self.label_iscc.clear() self.meta_id = None self.content_id = None self.data_id = None self.instance_id = None self.iscc = None self.title_formatted = None self.extra_formatted = None self.instance_hash = None self.widget_generated_iscc.setHidden(True) self.button_dropzone.setText( 'Drop your image or text file here or click to choose.') self.label_title_conflicts.setHidden(True) self.table_conflicts.setHidden(True) signals.new_unconfirmed.emit('ISCC registration') except Exception as e: QMessageBox.warning(QMessageBox(), 'Error while publishing', str(e), QMessageBox.Close, QMessageBox.Close)
def send(self): QApplication.setOverrideCursor(Qt.WaitCursor) client = get_active_rpc_client() address = self.edit_resale_to.text() amount = float(self.edit_amount.text()) token = self.licenses[self.cb_smart_license.currentIndex()] comment = self.edit_comment.text() try: if comment: client.sendasset(address, token, amount, 0.1, comment) else: client.sendasset(address, token, amount) signals.new_unconfirmed.emit('transfer') self.edit_comment.setText('') self.edit_resale_to.setText('') self.edit_resale_to.setStyleSheet( 'QLineEdit { background-color: #fff }') self.edit_amount.setValue(1) QApplication.restoreOverrideCursor() except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while sending token') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) QApplication.restoreOverrideCursor() error_dialog.exec_()
def process_transactions(data_db, block_height, pubkeyhash_version, checksum_value, client=None): if client == None: client = get_active_rpc_client() try: block = client.getblock('{}'.format(block_height), 4) except Exception as e: log.debug(e) return for pos_in_block, tx in enumerate(block['tx']): try: tx_relevant = process_inputs_and_outputs(data_db, tx, pubkeyhash_version, checksum_value) except Exception as e: log.debug(e) return # add only relevant TXs to the database. if tx_relevant: Transaction.create_if_not_exists( data_db, Transaction(txid=tx['txid'], pos_in_block=pos_in_block, block=unhexlify(block['hash'])))
def getblockchaininfo(): """Emit headers and blocks (block sync status)""" client = get_active_rpc_client() result = client.getblockchaininfo()['result'] # Todo: Maybe track headers/blocks on Profile db model signals.getblockchaininfo.emit(Getblockchaininfo(**result)) return result
def on_revoke_clicked(self): sender = self.sender() address = sender.objectName() perm_type = self.parent().perm_type skill_name = perm_type if perm_type == 'admin': skill_name = 'guardian' elif perm_type == 'mine': skill_name = 'validator' message_box = QMessageBox() answer = message_box.question( QWidget(), "Revoke Skills", "Are you sure you want to revoke {} skills from {}?".format( skill_name, address), message_box.Yes | message_box.No) if answer == message_box.Yes: QApplication.setOverrideCursor(Qt.WaitCursor) client = get_active_rpc_client() try: client.revoke(address, perm_type) sender.setDisabled(True) sender.setStyleSheet( "QPushButton {background-color: #aeaeae; margin: 8 4 8 4; color: white; font-size: 8pt; width: 70px}" ) signals.new_unconfirmed.emit('vote') QApplication.restoreOverrideCursor() except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while revoking') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) QApplication.restoreOverrideCursor() error_dialog.exec_()
def on_grant_clicked(self, skill): sender = self.sender() address = sender.objectName() skill_name = skill if skill == 'admin': skill_name = 'guardian' elif skill == 'mine': skill_name = 'validator' message_box = QMessageBox() answer = message_box.question(QWidget(), "Grant Skills", "Are you sure you want to grant {} skills to {}?".format(skill_name, address), message_box.Yes | message_box.No) if answer == message_box.Yes: QApplication.setOverrideCursor(Qt.WaitCursor) client = get_active_rpc_client() try: response = client.grant(address, skill) if response['error'] is not None: err_msg = response['error']['message'] raise RuntimeError(err_msg) else: sender.setDisabled(True) sender.setStyleSheet( "QPushButton {background-color: #aeaeae; margin: 8 4 8 4; color: white; font-size: 8pt; width: 70px}") QApplication.restoreOverrideCursor() except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while granting') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) QApplication.restoreOverrideCursor() error_dialog.exec_()
def getruntimeparams(): """Update wallet main address on current profile""" client = get_active_rpc_client() profile = Profile.get_active() result = client.getruntimeparams()['result'] if result['handshakelocal'] != profile.address: profile.address = result['handshakelocal'] profile.save()
def getinfo(): """Update latest wallet balance on current profile""" client = get_active_rpc_client() profile = Profile.get_active() result = client.getinfo()['result'] if result['balance'] != profile.balance: profile.balance = result['balance'] profile.save()
def getruntimeparams(): """Update wallet main address on current profile""" client = get_active_rpc_client() with profile_session_scope() as session: profile = Profile.get_active(session) params = client.getruntimeparams() if params.handshakelocal != profile.address: profile.address = params.handshakelocal
def getblockchaininfo(): """Emit headers and blocks (block sync status)""" client = get_active_rpc_client() try: info = client.getblockchaininfo() # Todo: Maybe track headers/blocks on Profile db model signals.getblockchaininfo.emit(info) return info except Exception as e: log.debug(e) return
def generate_api_sample_responses(): """Creates sample response json data in .scratch folder. Note: Calls rpc.RpcClient methods with their default args. Other args may yield different json structures! """ init_profile_db() client = get_active_rpc_client() for method in scan: result = getattr(client, method)() fp = '.scratch/{}.json'.format(method) json.dump(result, open(fp, 'w'), indent=4, cls=DecimalEncoder)
def save(self): client = get_active_rpc_client() try: client.publish(app.STREAM_ALIAS, self.edit_alias.text(), '') signals.new_unconfirmed.emit('alias change') except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while changing alias') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) error_dialog.exec_() self.close()
def getinfo(): """Update latest wallet balance on current profile""" client = get_active_rpc_client() with profile_session_scope() as session: profile = Profile.get_active(session) try: info = client.getinfo() signals.getinfo.emit(info) new_balance = Decimal(str(info.balance)) if new_balance != profile.balance: profile.balance = Decimal(info.balance) except Exception as e: log.debug(e)
def listwallettransactions(): client = get_active_rpc_client() txs = client.listwallettransactions(10000000) if not txs: log.warning('no transactions from api') return balance = 0 new_transactions = [] new_confirmations = [] with data_db.atomic(): for tx in txs['result']: if tx['valid']: txid = tx['txid'] dt = datetime.fromtimestamp(tx['time']) description = tx.get('comment', '') perm = tx['permissions'] if perm: description = 'Skills grant/revoke' items = tx['items'] if items: first_item_type = items[0].get('type') if first_item_type == 'stream': description = 'Stream publishing' if tx.get('generated'): description = 'Mining reward' amount = tx['balance']['amount'] balance += amount confirmations = tx['confirmations'] tx_obj, created = Transaction.get_or_create( txid=txid, defaults=dict(datetime=dt, comment=description, amount=amount, balance=balance, confirmations=confirmations)) if created: new_transactions.append(tx_obj) elif tx_obj.confirmations == 0 and confirmations != 0: tx_obj.confirmations = confirmations new_confirmations.append(tx_obj) tx_obj.save() if len(new_transactions) > 0 or len(new_confirmations) > 0: signals.listwallettransactions.emit(new_transactions, new_confirmations) return len(new_transactions) != 0
def fetch_next_wallet_transactions(self): client = get_active_rpc_client() new_txs = [] try: new_txs = client.listwallettransactions(100, len(self.raw_txs), False, True) if len(new_txs) < 100: self.wallet_transactions_left = False except Exception as e: log.debug(e) last_balance = self.txs[-1][self.BALANCE] if len(self.txs)>0 else self.balance processed_transactions = self.process_wallet_transactions(new_txs, last_balance) self.beginInsertRows(QModelIndex(), len(self.txs), len(self.txs)+len(processed_transactions)) self.raw_txs = new_txs + self.raw_txs self.txs += processed_transactions self.endInsertRows()
def put_timestamp(hexhash: str, comment: str='', stream='timestamp') -> Optional[TxId]: client = get_active_rpc_client() if comment: data = dict(comment=comment) serialized = ubjson.dumpb(data) data_hex = hexlify(serialized).decode('utf-8') response = client.publish(stream, hexhash, data_hex) else: response = client.publish(stream, hexhash) if response['error'] is not None: raise RpcResponseError(response['error']['message']) return TxId(response['result'])
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 run(self): client = get_active_rpc_client() log.debug('sleeping %i seconds before starting to sync token updates' % self.STARTUP_DELAY) self.sleep(self.STARTUP_DELAY) while True: log.debug('check for new local token updates') try: # This triggers Network Info widget update that we always want blockchain_info = client.getblockchaininfo() # The node is downloading blocks if it has more headers than blocks if blockchain_info.blocks != blockchain_info.headers: log.debug('blockchain syncing - skip expensive rpc calls') self.sleep(self.UPDATE_INTERVALL) continue wallet_tokens = client.getmultibalances() except Exception as e: log.exception('cannot get blocks via rpc: %s' % e) self.sleep(self.UPDATE_INTERVALL) continue tokens = [] for token in wallet_tokens['total']: if 'name' not in token: continue try: token_info = client.listassets(token['name'], True)[0] except Exception as e: log.debug(e) continue if 'type' in token_info['details'] and token_info['details'][ 'type'] == 'smart-license': tokens.append([ token_info['details']['info'] if 'info' in token_info['details'] else '', token['qty'], token_info['issueqty'], 'No' if token_info['open'] else 'Yes', token['name'] if 'name' in token else '', token['assetref'] if 'assetref' in token else None ]) signals.wallet_tokens_changed.emit(tokens) self.sleep(self.UPDATE_INTERVALL)
def put_timestamp(hexhash: str, comment: str = '', stream=app.STREAM_TIMESTAMP) -> Optional[TxId]: client = get_active_rpc_client() try: if comment: data = dict(comment=comment) serialized = ubjson.dumpb(data) data_hex = hexlify(serialized).decode('utf-8') response = client.publish(stream, hexhash, data_hex) else: response = client.publish(stream, hexhash, "") return TxId(response) except Exception as e: log.debug(e) raise RpcResponseError(str(e))
def generate_classes(): init_profile_db() client = get_active_rpc_client() class_blocks = [] for method in generate: result = getattr(client, method)() classname = method.title() setters = [] for field in result['result'].keys(): setter = 'self.{} = kwargs["{}"]'.format(field, field) setters.append(setter) setters = '\n '.join(setters) class_block = class_template.format( classname=classname, setters=setters ) class_blocks.append(class_block) module_code = module_header + "\n".join(class_blocks) with open('app/responses.py', 'w') as outf: outf.write(module_code)
def on_accepted(self): log.debug('sending invite...') address = self.edit_candidate_address.text() # TODO: check if address already has permissions if not address_valid(address): return QMessageBox.critical(self, 'Invalid Address', 'Invalid Address') perms = [] if self.cbox_grant_guardian_skills.isChecked(): perms.append('admin') if self.cbox_grant_validator_skills.isChecked(): perms.append('mine') perms = ','.join(perms) comment = self.edit_public_comment.text() if comment: comment = hexlify(comment.encode('utf-8')).decode('utf-8') else: comment = '' log.debug('granting %s to %s - reason: %s' % (perms, address, comment)) client = get_active_rpc_client() response = client.grantwithdata(address, perms, data_hex=comment) if response['error']: return QMessageBox.critical(self, 'Error sending invitation', response['error']['message']) if response['result']: self.edit_candidate_address.clear() self.edit_candidate_address.setStyleSheet( 'QLineEdit { background-color: #fff }') self.edit_public_comment.clear() self.cbox_grant_validator_skills.setChecked(True) self.cbox_grant_guardian_skills.setChecked(False) msg = 'Your invitation has been sent. The Transaction id is: \n%s' % response[ 'result'] return QMessageBox.information(self, 'Charm - Invitation Sent', msg)
def on_send_clicked(self): QApplication.setOverrideCursor(Qt.WaitCursor) client = get_active_rpc_client() try: response = client.send( address=self.edit_address.text(), amount=Decimal(self.edit_amount.text()), comment=self.edit_description.text() ) if response['error'] is not None: err_msg = response['error']['message'] raise RuntimeError(err_msg) self.on_cancel_clicked() QApplication.restoreOverrideCursor() except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while sending') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) QApplication.restoreOverrideCursor() error_dialog.exec_()
def on_accepted(self): log.debug('sending invite...') address = self.edit_candidate_address.text() # TODO: check if address already has permissions if not address_valid(address): return QMessageBox.critical(self, 'Invalid Address', 'Invalid Address') perms = [] if self.cbox_grant_guardian_skills.isChecked(): perms.append('admin') if self.cbox_grant_validator_skills.isChecked(): perms.append('mine') perms = ','.join(perms) comment = self.edit_public_comment.text() if comment: comment = hexlify(comment.encode('utf-8')).decode('utf-8') else: comment = '' log.debug('granting %s to %s - reason: %s' % (perms, address, comment)) client = get_active_rpc_client() try: client.grantwithdata(address, perms, comment) self.edit_candidate_address.clear() self.edit_candidate_address.setStyleSheet( 'QLineEdit { background-color: #fff }') self.edit_public_comment.clear() self.cbox_grant_validator_skills.setChecked(True) self.cbox_grant_guardian_skills.setChecked(False) signals.new_unconfirmed.emit('vote') except Exception as e: return QMessageBox.critical(self, 'Error sending invitation', "{}".format(e))
def get_timestamps(hash_value: str, stream='timestamp') -> Optional[List]: client = get_active_rpc_client() response = client.liststreamkeyitems(stream, hash_value, verbose=True, count=1000, start=-1000) if response['error'] is not None: raise RpcResponseError(response['error']['message']) result = response['result'] timestamps = [] for entry in result: if entry['data']: if not isinstance(entry['data'], str): log.warning('Stream item data is not a string: %s' % entry['data']) # Todo investigate dict with size, txid, vout in stream item data continue data = ubjson.loadb(unhexlify(entry['data'])) comment = data.get('comment', '') else: comment = '' for publisher in entry['publishers']: timestamps.append((entry['time'], publisher, comment)) return timestamps
def on_send_clicked(self): QApplication.setOverrideCursor(Qt.WaitCursor) client = get_active_rpc_client() address = self.edit_address.text() amount = float(self.edit_amount.text()) comment = self.edit_description.text() try: if self.cb_comment_type.currentIndex() == 0 or len( comment) == 0: # private comment client.send(address, amount, comment) else: # public comment comment_object = {"json": {"comment": comment}} client.sendwithdata(address, amount, comment_object) signals.new_unconfirmed.emit('transfer') self.on_cancel_clicked() QApplication.restoreOverrideCursor() except Exception as e: err_msg = str(e) error_dialog = QMessageBox() error_dialog.setWindowTitle('Error while sending') error_dialog.setText(err_msg) error_dialog.setIcon(QMessageBox.Warning) QApplication.restoreOverrideCursor() error_dialog.exec_()
def client(self): """Always use the rpc connection for the current profile""" return get_active_rpc_client()
def process_blocks(): """ Find last valid Block, delete every Block above in DB and get all Blocks above from Node. Process through new Blocks: Add them to DB. Process through all transactions in block. """ client = get_active_rpc_client() ### get last valid block in DB ### last_valid_height = -1 last_block_is_valid = False with data_session_scope() as session: while not last_block_is_valid: latest_block = session.query(Block).order_by( Block.height.desc()).first() if not latest_block: break try: block_from_chain = client.getblock('{}'.format( latest_block.height)) except Exception as e: log.debug(e) return if latest_block.hash == unhexlify(block_from_chain['hash']): last_block_is_valid = True last_valid_height = latest_block.height else: session.delete(latest_block) blockchain_params = client.getblockchainparams() pubkeyhash_version = blockchain_params['address-pubkeyhash-version'] checksum_value = blockchain_params['address-checksum-value'] block_count_node = client.getblockcount() with data_session_scope() as session: # height is 0 indexed, for batch in batchwise(range(last_valid_height + 1, block_count_node), 100): try: with data_session_scope() as session: signals.batch_gui_updates_allowed.emit(False) new_blocks = client.listblocks(batch) first = True for block in new_blocks: # Allow emitting certain GUI update signals for the first block in the batch # or if we're close to the current node block count if first or block_count_node - block['height'] < 16: signals.batch_gui_updates_allowed.emit(True) block_obj = Block( hash=unhexlify(block['hash']), height=block['height'], mining_time=datetime.fromtimestamp(block['time']), ) session.add(block_obj) session.add( MiningReward(block=unhexlify(block['hash']), address=block['miner'])) Address.create_if_not_exists(session, block['miner']) if block['txcount'] > 1: process_transactions(session, block['height'], pubkeyhash_version, checksum_value, client) signals.database_blocks_updated.emit( block['height'], block_count_node) signals.blockschanged.emit( session.query(Block).count()) # Skip certain GUI update signals for the remainder of the batch if first: signals.batch_gui_updates_allowed.emit(False) first = False except Exception as e: signals.batch_gui_updates_allowed.emit(True) log.debug('Exception in process_blocks:') log.debug(e) return signals.batch_gui_updates_allowed.emit(True) if last_valid_height != block_count_node: # permissions and votes tables are completely refreshed after each new block process_permissions()
def process_permissions(): # todo: check if we have new perms / votes client = get_active_rpc_client() try: perms = client.listpermissions("*", "*", True) except Exception as e: log.debug(e) return with data_session_scope() as session: session.query(Permission).delete() session.query(PendingVote).delete() with data_session_scope() as session: for perm in perms: perm_type = perm['type'] perm_start = perm['startblock'] perm_end = perm['endblock'] address = perm['address'] Address.create_if_not_exists(session, address) if perm_type not in [ enums.ISSUE, enums.CREATE, enums.MINE, enums.ADMIN ]: continue perm_obj = Permission(address=address, perm_type=perm_type, start_block=perm_start, end_block=perm_end) session.add(perm_obj) for vote in perm['pending']: start_block = vote['startblock'] end_block = vote['endblock'] # If candidate has already the permission continue. if start_block == perm['startblock'] and end_block == perm[ 'endblock']: continue for admin in vote['admins']: Address.create_if_not_exists(session, admin) vote_obj = PendingVote(address_from=admin, address_to=address, perm_type=perm_type, start_block=start_block, end_block=end_block) session.add(vote_obj) signals.votes_changed.emit() with profile_session_scope() as profile_db: profile = Profile.get_active(profile_db) with data_session_scope() as data_db: is_admin, is_miner = Permission.get_permissions_for_address( data_db, profile.address) if is_admin != profile.is_admin: profile.is_admin = is_admin signals.is_admin_changed.emit(is_admin) if is_miner != profile.is_miner: profile.is_miner = is_miner signals.is_miner_changed.emit(is_miner) signals.permissions_changed.emit()
def stop(self): if self.state() == self.NotRunning: log.debug('node already stopped') else: return get_active_rpc_client().stop()
import app app.init() from datetime import datetime from app.backend.rpc import get_active_rpc_client client = get_active_rpc_client() txs = client.listwallettransactions(10000000) balance = 0 with open('3_post_rescan_txes.txt', 'wb') as outf: outf.write('datetime;amount;balance;txid\n'.encode('utf-8')) for tx in txs['result']: if tx['valid']: txid = tx['txid'] dt = datetime.fromtimestamp(tx['time']) description = tx.get('comment', '') perm = tx['permissions'] if perm: description = 'Skills grant/revoke' items = tx['items'] if items: first_item_type = items[0].get('type') if first_item_type == 'stream': description = 'Stream publishing' if tx.get('generated'): description = 'Mining reward' amount = tx['balance']['amount'] balance += amount