Beispiel #1
0
def after_update(mapper, connection, alias):
    from app.models import Profile
    with profile_session_scope() as session:
        profile = Profile.get_active(session)
        if alias.address == profile.address:
            profile.alias = alias.alias
    signals.alias_list_changed.emit()
Beispiel #2
0
    def setting_changed_manage_node(self, state):
        self.profile.manage_node = state == 2
        with profile_session_scope() as session:
            session.add(self.profile)

        if self.profile.manage_node:
            self.node.start()
Beispiel #3
0
def init_data_db():
    fp = ''
    with profile_session_scope() as session:
        profile_obj = Profile.get_active(session)
        if profile_obj is None:
            raise RuntimeError('cannot init data db without active profile')
        fp = profile_obj.data_db_filepath

    log.debug('init data db at: {}'.format(fp))
    engine = sqlalchemy.create_engine('sqlite:///{}'.format(fp))
    data_db.configure(bind=engine)
    engine.execute("PRAGMA journal_mode=WAL")

    log.debug("check data-db schema")
    reset_blocks = False
    for table_name, table in data_base.metadata.tables.items():
        log.debug("check {}-db schema".format(table.name))
        if not check_table_ddl_against_model(data_db, table):
            log.debug("{}-db schema outdated, resetting".format(table.name))
            reset_blocks = True
            if engine.dialect.has_table(engine, table_name):
                table.drop(engine)

        else:
            log.debug("{}-db schema up to date".format(table.name))

    data_base.metadata.create_all(engine)
    if reset_blocks:
        data_db().query(Block).delete()
    return data_db
Beispiel #4
0
def get_active_rpc_client(override=None):
    from app.models import Profile
    from app.models.db import profile_session_scope
    with profile_session_scope() as session:
        profile = override or Profile.get_active(session)
    assert isinstance(profile, Profile)
    return RpcClient(profile.rpc_host, profile.rpc_port, profile.rpc_user,
                     profile.rpc_password, profile.rpc_use_ssl)
Beispiel #5
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setupUi(self)
        from app.models.db import profile_session_scope
        with profile_session_scope() as session:
            self.profile = Profile.get_active(session)
        self.on_profile_changed(self.profile)

        signals.profile_changed.connect(self.on_profile_changed)
Beispiel #6
0
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
Beispiel #7
0
def init_profile_db():
    fp = app.PROFILE_DB_FILEPATH
    log.debug('init profile db at {}'.format(fp))
    engine = sqlalchemy.create_engine('sqlite:///{}'.format(fp))

    profile_db.configure(bind=engine)
    engine.execute("PRAGMA journal_mode=WAL")

    log.debug("check {}-db schema".format(Profile.__table__.name))
    backup_profiles = []
    if not check_table_ddl_against_model(profile_db, Profile.__table__):
        log.debug("{}-db schema outdated, resetting".format(
            Profile.__table__.name))
        if engine.dialect.has_table(engine, "profiles"):
            for profile in profile_db().execute(
                    'SELECT * FROM profiles').fetchall():
                backup_profiles.append(profile)

            Profile.__table__.drop(engine)
        elif engine.dialect.has_table(engine, "profile"):
            for profile in profile_db().execute(
                    'SELECT * FROM profile').fetchall():
                backup_profiles.append(profile)
    else:
        log.debug("{}-db schema up to date".format(Profile.__table__.name))

    # create the database
    Profile_Base.metadata.create_all(engine)

    with profile_session_scope() as session:
        for profile in backup_profiles:
            session.add(
                Profile(
                    name=profile.name if 'name' in profile else '',
                    rpc_host=profile.rpc_host
                    if 'rpc_host' in profile else '127.0.0.1',
                    rpc_port=profile.rpc_port
                    if 'rpc_port' in profile else '9719',
                    rpc_user=profile.rpc_user
                    if 'rpc_user' in profile else 'multichainrpc',
                    rpc_password=profile.rpc_password
                    if 'rpc_password' in profile else '',
                    rpc_use_ssl=profile.rpc_use_ssl
                    if 'rpc_use_ssl' in profile else 0,
                    manage_node=profile.manage_node
                    if 'manage_node' in profile else 1,
                    exit_on_close=profile.exit_on_close
                    if 'exit_on_close' in profile else 1,
                    active=profile.active if 'active' in profile else 0,
                    alias=profile.alias if 'alias' in profile else '',
                    address=profile.address if 'address' in profile else '',
                    balance=profile.balance if 'balance' in profile else 0,
                    is_admin=profile.is_admin if 'is_admin' in profile else 0,
                    is_miner=profile.is_miner if 'is_miner' in profile else 0,
                ))

    return profile_db
Beispiel #8
0
 def already_revoked(data_db, perm_type):
     from app.models import Profile
     from app.models.db import profile_session_scope
     with profile_session_scope() as session:
         profile = Profile.get_active(session)
     return data_db.query(
         PendingVote.address_to, PendingVote.perm_type).filter(
             (PendingVote.address_from == profile.address)
             & (PendingVote.start_block == 0) & (PendingVote.end_block == 0)
             & (PendingVote.perm_type == perm_type)).all()
Beispiel #9
0
 def already_granted(data_db):
     from app.models import Permission, Profile
     from app.models.db import profile_session_scope
     with profile_session_scope() as session:
         profile = Profile.get_active(session)
     return data_db.query(
         PendingVote.address_to, PendingVote.perm_type).filter(
             (PendingVote.address_from == profile.address)
             & (PendingVote.start_block == 0)
             & (PendingVote.end_block == Permission.MAX_END_BLOCK)).all()
Beispiel #10
0
def init_node_data_dir():
    from app.models import Profile
    from app.models.db import profile_session_scope
    with profile_session_scope() as session:
        profile = Profile.get_active(session)
        ndd = os.path.join(app.DATA_DIR, 'node_' + profile.name)
        if profile.manage_node:
            if not os.path.exists(ndd):
                log.debug('create node data dir {}'.format(ndd))
                os.makedirs(ndd, exist_ok=True)
        return ndd
Beispiel #11
0
    def __init__(self, *args, **kwargs):
        self.perm_type = kwargs.pop('perm_type')
        QTableView.__init__(self, *args, **kwargs)

        self.setMinimumWidth(400)
        try:
            self.profile = self.parent().profile
        except AttributeError:
            # In case of standalone usage
            with profile_session_scope() as session:
                self.profile = Profile.get_active(session)

        signals.is_admin_changed.connect(self.is_admin_changed)

        # self.pressed.connect(self.on_cell_clicked)

        self.table_model = PermissionModel(self, perm_type=self.perm_type)
        self.setModel(self.table_model)

        font = QFont()
        font.setFamily("Roboto Light")
        font.setPointSize(10)

        self.setColumnHidden(5, not self.profile.is_admin)

        header = self.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.Interactive)
        header.setSectionResizeMode(1, QHeaderView.Stretch)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(5, QHeaderView.ResizeToContents)
        header.setFont(font)

        # Row height
        self.verticalHeader().setVisible(False)
        self.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
        self.verticalHeader().setDefaultSectionSize(40)

        self.setFont(font)
        self.setAlternatingRowColors(True)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setShowGrid(False)
        # TODO implement comminity tables sorting
        self.setSortingEnabled(False)
        self.setCornerButtonEnabled(True)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.openCustomMenu)
        self.balance_is_zero = True
        self.create_table_buttons(self.balance_is_zero)
        signals.on_balance_status_changed.connect(
            self.on_balance_status_changed)
Beispiel #12
0
    def start(self, *args, **kwargs):
        """Start node with active profile settings.

        :param str initprivkey: Optional WIF encoded private key for first time init.
        """

        initprivkey = kwargs.pop('initprivkey', None)

        try:
            self.profile = self.parent().profile
        except AttributeError:
            # In case of standalone usage
            from app.models.db import profile_session_scope
            with profile_session_scope() as session:
                self.profile = Profile.get_active(session)

        assert isinstance(self.profile, Profile)
        assert self.profile.manage_node, "active profile does not want to manage node"

        if self.state() == self.NotRunning:
            node_path = os.path.join(app.APP_DIR, 'app/bin/multichaind')
            if self.reindex_required:
                log.debug('starting node at: {} with -reindex=1'.format(node_path))
            else:
                log.debug('starting node at: {}'.format(node_path))

            # TODO only launch full bootstrap ip in first launch
            launch_args = [
                    app.NODE_BOOTSTRAP,
                    '-server=1',
                    # '-daemon',
                    '-autosubscribe=assets,streams',
                    '-autocombineminconf=4294967294',
                    # '-maxshowndata=32',
                    # '-printtoconsole',
                    '-reindex=' + ("1" if self.reindex_required else "0"),
                    # '-shortoutput',
                    '-rpcuser={}'.format(self.profile.rpc_user),
                    '-rpcpassword={}'.format(self.profile.rpc_password),
                    '-rpcbind={}'.format(self.profile.rpc_host),
                    '-rpcallowip={}'.format(self.profile.rpc_host),
                    '-rpcport={}'.format(self.profile.rpc_port),
                    '-datadir={}'.format(init_node_data_dir()),
                ]

            if initprivkey is not None:
                launch_args.append('-initprivkey={}'.format(initprivkey))

            super().start(node_path, launch_args, QIODevice.ReadOnly)
            self.reindex_required = False
        else:
            log.debug('node already started - state: {}'.format(self.state()))
Beispiel #13
0
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)
Beispiel #14
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)
        from app.models.db import profile_session_scope
        with profile_session_scope() as session:
            self.profile = Profile.get_active(session)
        self.on_profile_changed(self.profile)

        self.edit_alias.setText(self.profile.alias)
        self.edit_alias.textChanged.connect(self.on_alias_changed)

        signals.profile_changed.connect(self.on_profile_changed)
        self.adjustSize()
        self.buttonBox.button(QDialogButtonBox.Save).clicked.connect(self.save)
        self.buttonBox.button(QDialogButtonBox.Save).setDisabled(True)
Beispiel #15
0
    def on_application_start(self):
        init_profile_db()
        self.updater = Updater(self)
        self.node = Node(self)
        self.aboutToQuit.connect(self.cleanup)

        from app.models.db import profile_session_scope
        with profile_session_scope() as session:
            is_first_start = app.is_first_start(session)

        if is_first_start:
            wizard = SetupWizard()
            if wizard.exec() == SetupWizard.Rejected:
                QtWidgets.qApp.quit()
                return
        else:
            init_data_db()

        # Initialize main window
        self.ui = self.main_widget()

        # Init TrayIcon
        self.tray_icon = QtWidgets.QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon(':images/resources/app_icon.png'))
        self.tray_icon.activated.connect(self.on_tray_activated)

        show_action = QtWidgets.QAction("Show", self)
        quit_action = QtWidgets.QAction("Exit", self)
        hide_action = QtWidgets.QAction("Hide", self)
        show_action.triggered.connect(self.ui.show)
        hide_action.triggered.connect(self.ui.hide)
        quit_action.triggered.connect(QtWidgets.qApp.quit)

        tray_menu = QtWidgets.QMenu()
        tray_menu.addAction(show_action)
        tray_menu.addAction(hide_action)
        tray_menu.addAction(quit_action)
        self.tray_icon.setContextMenu(tray_menu)
        self.tray_icon.show()

        # Shortcuts
        if hasattr(self.ui, 'node'):
            self.ui.debug_shortcut = QtWidgets.QShortcut(
                'Ctrl+K', self.ui, self.node.kill)
            self.ui.debug_shortcut = QtWidgets.QShortcut(
                'Ctrl+S', self.ui, self.node.stop)
            self.ui.debug_shortcut = QtWidgets.QShortcut(
                'Ctrl+R', self.ui, self.node.start)
Beispiel #16
0
    def page7_sync_initialize_page(self):
        if self._mnemonic and not self._address:
            self._address = main_address_from_mnemonic(self._mnemonic)

        self.label_address.setText(self._address)
        img = ImageQt(qrcode.make(self._address, box_size=3))
        self.label_qr_code.setPixmap(QPixmap.fromImage(img))

        if not exists(app.DATA_DIR):
            self.log('Creating data dir at: %s' % app.DATA_DIR)
            init_data_dir()

        self.log('Initialize profile database at: %s' %
                 app.PROFILE_DB_FILEPATH)

        with profile_session_scope() as session:
            if self._manage_node:
                Profile.create_default_profile(session)
            elif self._connection_tested:
                session.merge(
                    Profile(
                        name=self.edit_rpc_host.text(),
                        rpc_host=self.edit_rpc_host.text(),
                        rpc_port=self.edit_rpc_port.text(),
                        rpc_user=self.edit_rpc_user.text(),
                        rpc_password=self.edit_rpc_password.text(),
                        rpc_use_ssl=self.cbox_use_ssl.isChecked(),
                        manage_node=False,
                        exit_on_close=True,
                        active=True,
                    ))

        self.log('Initialize node-sync database')
        init_data_db()

        # This fixes our problem with the locked database
        # We have no idea why, but we shouldn't delete this code until we have a better solution
        with data_session_scope() as session:
            session.query('DELETE FROM mining_reward')

        if self._manage_node:
            self.node.start(initprivkey=main_wif_from_mnemonic(self._mnemonic))
        else:
            self._database_sync = True
            if not self.updater.isRunning():
                self.updater.start()
Beispiel #17
0
    def run(self):

        synced_blockhash = ''

        with profile_session_scope() as profile_session:
            profile = Profile.get_active(profile_session)
            with data_session_scope() as data_session:
                profile.alias = Alias.get_alias_by_address(data_session, profile.address)

        while True:

            log.debug('check for new blocks')
            try:
                # This triggers Network Info widget update that we always want
                blockchain_info = sync.getblockchaininfo()
                # The node is downloading blocks if it has more headers than blocks
                if blockchain_info.blocks != blockchain_info.headers or blockchain_info.reindex:
                    log.debug('blockchain syncing - skip expensive rpc calls')
                    self.sleep(self.UPDATE_INTERVALL)
                    continue
                node_block_hash = blockchain_info.bestblockhash
            except Exception as e:
                log.exception('cannot get bestblock via rpc: %s' % e)
                self.sleep(self.UPDATE_INTERVALL)
                continue

            sync.getinfo()

            if node_block_hash != synced_blockhash:
                log.debug('starting full sync round')

                for sync_func in self.sync_funcs:
                    try:
                        log.debug('updating %s' % sync_func.__name__)
                        sync_func()
                    except Exception as e:
                        log.exception(e)

                synced_blockhash = node_block_hash
                signals.sync_cycle_finished.emit()

            self.sleep(self.UPDATE_INTERVALL)
Beispiel #18
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.table_model = CandidateModel(self)
        self.setModel(self.table_model)
        self.setMinimumWidth(400)

        font = QFont()
        font.setFamily("Roboto Light")
        font.setPointSize(10)

        header = self.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(1, QHeaderView.Stretch)
        header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeToContents)
        header.setFont(font)

        # Row height
        self.verticalHeader().setVisible(False)
        self.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
        self.verticalHeader().setDefaultSectionSize(40)

        with profile_session_scope() as session:
            self.setColumnHidden(4, not Profile.get_active(session).is_admin)

        self.setFont(font)
        self.setAlternatingRowColors(True)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setShowGrid(False)
        # TODO implement candidates table sorting
        self.setSortingEnabled(False)
        self.setCornerButtonEnabled(True)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.openCustomMenu)
        self.create_table_buttons()

        signals.is_admin_changed.connect(self.is_admin_changed)
Beispiel #19
0
 def setting_changed_exit_on_close(self, state):
     self.profile.exit_on_close = state == 2
     with profile_session_scope() as session:
         session.add(self.profile)
Beispiel #20
0
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()
Beispiel #21
0
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        # Instantiate workers
        self.updater = QApplication.instance().updater
        self.node = QApplication.instance().node

        self.data_dir = helpers.init_data_dir()
        self.node_data_dir = helpers.init_node_data_dir()
        with profile_session_scope() as session:
            self.profile = Profile.get_active(session)

        # Setup Widgets
        self.setupUi(self)

        # Hide information widget
        font = QFont('Roboto Light', 10)
        self.label_info_text.setFont(font)
        self.btn_close_info.setFont(font)
        font.setUnderline(True)
        self.btn_info_action.setFont(font)
        self.widget_information.setHidden(True)
        self.btn_close_info.clicked.connect(self.hide_information)
        signals.new_unconfirmed.connect(self.show_transaction_info)
        self.information_type = None

        self.on_profile_changed(self.profile)
        signals.profile_changed.connect(self.on_profile_changed)

        self.permissions_changed()
        signals.permissions_changed.connect(self.permissions_changed)

        # Init Navigation
        self.btn_grp_nav.setId(self.btn_nav_wallet, 0)
        self.btn_grp_nav.setId(self.btn_nav_iscc, 1)
        self.btn_grp_nav.setId(self.btn_nav_timestamp, 2)
        self.btn_grp_nav.setId(self.btn_nav_token, 3)
        self.btn_grp_nav.setId(self.btn_nav_community, 4)
        self.btn_grp_nav.setId(self.btn_nav_settings, 5)
        self.btn_nav_wallet.setChecked(True)
        self.wgt_content.setCurrentIndex(0)

        # Patch custom widgets
        self.tab_widget_cummunity.setStyleSheet(
            'QPushButton {padding: 5 12 5 12; font: 10pt "Roboto Light"}')

        self.gbox_wallet_transactions.setParent(None)
        self.gbox_wallet_send.setParent(None)

        wallet_send = WalletSend(self)
        self.lout_page_wallet_v.addWidget(wallet_send)

        wallet_history = WalletHistory(self)
        self.lout_page_wallet_v.addWidget(wallet_history)

        widget_iscc = WidgetISCC(self)
        self.lout_page_iscc_v.addWidget(widget_iscc)

        widget_timestamp = WidgetTimestamping(self)
        self.lout_page_timestamp_v.addWidget(widget_timestamp)

        widget_token = WidgetToken(self)
        self.lout_page_token_v.addWidget(widget_token)

        self.table_validators.setParent(None)
        table_validators = CommunityTableView(self, perm_type=enums.MINE)
        self.tab_validators.layout().insertWidget(0, table_validators)

        self.table_guardians.setParent(None)
        table_guardians = CommunityTableView(self, perm_type=enums.ADMIN)
        self.tab_guardians.layout().insertWidget(0, table_guardians)

        self.table_candidates.setParent(None)
        table_candidates = CandidateTableView(self)
        self.tab_candidates.layout().insertWidget(0, table_candidates)

        # Statusbar
        self.label_statusbar = QtWidgets.QLabel('')
        self.statusbar.addPermanentWidget(self.label_statusbar)

        # Dialog Button hookups
        invite_dialog = InviteDialog(self)
        self.button_invite_canditate.clicked.connect(invite_dialog.exec)
        apply_dialog = ApplyDialog(self)
        self.button_apply_guardian.clicked.connect(apply_dialog.exec)
        self.button_apply_validator.clicked.connect(apply_dialog.exec)

        # Settings
        self.check_box_exit_on_close.setChecked(self.profile.exit_on_close)
        self.check_box_exit_on_close.stateChanged['int'].connect(
            self.setting_changed_exit_on_close)
        self.check_manage_node.setChecked(self.profile.manage_node)
        self.check_manage_node.stateChanged['int'].connect(
            self.setting_changed_manage_node)
        self.btn_alias_change.clicked.connect(self.on_change_alias)

        # Connections
        signals.getinfo.connect(self.getinfo)
        signals.getblockchaininfo.connect(self.getblockchaininfo)
        signals.node_started.connect(self.node_started)
        signals.rpc_error.connect(self.rpc_error)
        signals.blockschanged.connect(self.getdatabaseinfo)
        signals.on_balance_status_changed.connect(
            self.on_balance_status_changed)
        with data_session_scope() as session:
            from app.models import Block
            self.progress_bar_database_info.setValue(
                session.query(Block).count())

        if self.profile.manage_node:
            # Todo check for existing node process
            self.node.start()
        else:
            # No managed node to wait for... start updater
            self.updater.start()

        self.show()
Beispiel #22
0
    from app.models import Profile
    from app.models.db import profile_session_scope
    with profile_session_scope() as session:
        profile = override or Profile.get_active(session)
    assert isinstance(profile, Profile)
    return RpcClient(profile.rpc_host, profile.rpc_port, profile.rpc_user,
                     profile.rpc_password, profile.rpc_use_ssl)


class DecimalEncoder(json.JSONEncoder):
    """Custom json encoder that supports Decimal"""
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)


if __name__ == '__main__':
    from pprint import pprint
    import app
    from app.models import Profile
    from app.models.db import profile_session_scope
    app.init()
    with profile_session_scope() as session:
        print(Profile.get_active(session))
    client = get_active_rpc_client()
    # pprint(client.getmultibalances('*', '*', 1, False, False))
    # pprint(client.getmultibalances('*', '*', 0, False, True))
    print(client.getbestblockhash())
    pprint(client.listwallettransactions(1))