2015-12-13 14:51:43 +01:00
// Copyright (c) 2011-2015 The Bitcoin Core developers
2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2014-12-13 05:09:33 +01:00
// Distributed under the MIT software license, see the accompanying
2013-11-04 16:20:43 +01:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2016-02-04 13:41:58 +01:00
# if defined(HAVE_CONFIG_H)
# include "config/dash-config.h"
# endif
2012-04-09 21:07:25 +02:00
# include "rpcconsole.h"
2015-08-18 19:24:10 +02:00
# include "ui_debugwindow.h"
2012-04-09 21:07:25 +02:00
2015-06-23 21:10:42 +02:00
# include "bantablemodel.h"
2012-04-09 21:07:25 +02:00
# include "clientmodel.h"
# include "guiutil.h"
2015-07-28 15:20:14 +02:00
# include "platformstyle.h"
2012-04-09 21:07:25 +02:00
2014-06-04 12:06:18 +02:00
# include "chainparams.h"
2017-09-03 15:29:10 +02:00
# include "netbase.h"
2017-07-03 15:13:34 +02:00
# include "rpc/server.h"
# include "rpc/client.h"
2014-06-03 14:42:20 +02:00
# include "util.h"
2013-04-13 07:13:08 +02:00
# include <openssl/crypto.h>
2014-09-05 13:18:35 +02:00
2015-09-04 16:11:34 +02:00
# include <univalue.h>
2014-08-20 21:15:16 +02:00
2014-06-05 07:00:16 +02:00
# ifdef ENABLE_WALLET
2014-06-04 22:00:59 +02:00
# include <db_cxx.h>
2014-06-05 07:00:16 +02:00
# endif
2014-06-04 22:00:59 +02:00
2015-10-25 20:54:46 +01:00
# include <QDir>
2012-04-09 21:07:25 +02:00
# include <QKeyEvent>
2015-06-01 15:32:25 +02:00
# include <QMenu>
2017-01-03 16:57:15 +01:00
# include <QMessageBox>
2013-04-13 07:13:08 +02:00
# include <QScrollBar>
2017-09-07 17:59:00 +02:00
# include <QSettings>
2015-07-29 14:34:14 +02:00
# include <QSignalMapper>
2013-04-13 07:13:08 +02:00
# include <QThread>
# include <QTime>
2015-08-28 16:46:20 +02:00
# include <QTimer>
2016-02-27 04:57:12 +01:00
# include <QStringList>
2013-04-13 07:13:08 +02:00
2013-05-31 14:02:24 +02:00
# if QT_VERSION < 0x050000
2012-05-12 12:30:07 +02:00
# include <QUrl>
2013-05-31 14:02:24 +02:00
# endif
2012-04-09 21:07:25 +02:00
2012-08-31 09:43:40 +02:00
// TODO: add a scrollback limit, as there is currently none
2012-04-09 21:07:25 +02:00
// TODO: make it possible to filter out categories (esp debug messages when implemented)
// TODO: receive errors and debug messages through ClientModel
const int CONSOLE_HISTORY = 50 ;
2017-09-07 17:59:00 +02:00
const QSize FONT_RANGE ( 4 , 40 ) ;
const char fontSizeSettingsKey [ ] = " consoleFontSize " ;
2012-05-12 12:30:07 +02:00
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
const TrafficGraphData : : GraphRange INITIAL_TRAFFIC_GRAPH_SETTING = TrafficGraphData : : Range_30m ;
2013-08-22 18:09:32 +02:00
2015-05-28 23:09:14 +02:00
// Repair parameters
const QString SALVAGEWALLET ( " -salvagewallet " ) ;
const QString RESCAN ( " -rescan " ) ;
const QString ZAPTXES1 ( " -zapwallettxes=1 " ) ;
const QString ZAPTXES2 ( " -zapwallettxes=2 " ) ;
const QString UPGRADEWALLET ( " -upgradewallet " ) ;
const QString REINDEX ( " -reindex " ) ;
2012-05-12 12:30:07 +02:00
const struct {
const char * url ;
const char * source ;
} ICON_MAPPING [ ] = {
2015-09-16 05:29:57 +02:00
{ " cmd-request " , " tx_input " } ,
{ " cmd-reply " , " tx_output " } ,
{ " cmd-error " , " tx_output " } ,
{ " misc " , " tx_inout " } ,
2012-05-12 12:30:07 +02:00
{ NULL , NULL }
} ;
2017-01-03 16:57:15 +01:00
namespace {
// don't add private key handling cmd's to the history
const QStringList historyFilter = QStringList ( )
< < " importprivkey "
< < " importmulti "
< < " signmessagewithprivkey "
< < " signrawtransaction "
< < " walletpassphrase "
< < " walletpassphrasechange "
< < " encryptwallet " ;
}
2012-04-09 21:07:25 +02:00
/* Object for executing console RPC commands in a separate thread.
*/
2013-01-23 21:51:02 +01:00
class RPCExecutor : public QObject
2012-04-09 21:07:25 +02:00
{
Q_OBJECT
2013-01-23 21:51:02 +01:00
2015-07-14 13:59:05 +02:00
public Q_SLOTS :
2012-04-09 21:07:25 +02:00
void request ( const QString & command ) ;
2013-01-23 21:51:02 +01:00
2015-07-14 13:59:05 +02:00
Q_SIGNALS :
2012-04-09 21:07:25 +02:00
void reply ( int category , const QString & command ) ;
} ;
2015-08-28 16:46:20 +02:00
/** Class for handling RPC timers
* ( used for e . g . re - locking the wallet after a timeout )
*/
class QtRPCTimerBase : public QObject , public RPCTimerBase
{
Q_OBJECT
public :
2016-09-23 12:44:09 +02:00
QtRPCTimerBase ( boost : : function < void ( void ) > & _func , int64_t millis ) :
func ( _func )
2015-08-28 16:46:20 +02:00
{
timer . setSingleShot ( true ) ;
connect ( & timer , SIGNAL ( timeout ( ) ) , this , SLOT ( timeout ( ) ) ) ;
timer . start ( millis ) ;
}
~ QtRPCTimerBase ( ) { }
private Q_SLOTS :
void timeout ( ) { func ( ) ; }
private :
QTimer timer ;
boost : : function < void ( void ) > func ;
} ;
class QtRPCTimerInterface : public RPCTimerInterface
{
public :
~ QtRPCTimerInterface ( ) { }
const char * Name ( ) { return " Qt " ; }
RPCTimerBase * NewTimer ( boost : : function < void ( void ) > & func , int64_t millis )
{
return new QtRPCTimerBase ( func , millis ) ;
}
} ;
2012-04-09 21:07:25 +02:00
# include "rpcconsole.moc"
2012-08-30 21:42:18 +02:00
/**
2017-01-03 16:57:15 +01:00
* Split shell command line into a list of arguments and optionally execute the command ( s ) .
2016-09-20 12:59:08 +02:00
* Aims to emulate \ c bash and friends .
2012-08-30 21:42:18 +02:00
*
2017-01-03 16:57:15 +01:00
* - Command nesting is possible with parenthesis ; for example : validateaddress ( getnewaddress ( ) )
2016-09-20 12:59:08 +02:00
* - Arguments are delimited with whitespace or comma
2012-08-30 21:42:18 +02:00
* - Extra whitespace at the beginning and end and between arguments will be ignored
2012-08-30 21:42:18 +02:00
* - Text can be " double " or ' single ' quoted
* - The backslash \ c \ is used as escape character
2012-08-30 21:42:18 +02:00
* - Outside quotes , any character can be escaped
2012-08-30 21:42:18 +02:00
* - Within double quotes , only escape \ c " and backslashes before a \ c " or another backslash
* - Within single quotes , no escaping is possible and no special interpretation takes place
2012-08-30 21:42:18 +02:00
*
2016-09-20 12:59:08 +02:00
* @ param [ out ] result stringified Result from the executed command ( chain )
2012-08-30 21:42:18 +02:00
* @ param [ in ] strCommand Command line to split
2017-01-03 16:57:15 +01:00
* @ param [ in ] fExecute set true if you want the command to be executed
* @ param [ out ] pstrFilteredOut Command line , filtered to remove any sensitive data
2012-08-30 21:42:18 +02:00
*/
2016-09-20 12:59:08 +02:00
2017-01-03 16:57:15 +01:00
bool RPCConsole : : RPCParseCommandLine ( std : : string & strResult , const std : : string & strCommand , const bool fExecute , std : : string * const pstrFilteredOut )
2012-04-09 21:07:25 +02:00
{
2016-09-20 12:59:08 +02:00
std : : vector < std : : vector < std : : string > > stack ;
stack . push_back ( std : : vector < std : : string > ( ) ) ;
2012-08-30 21:42:18 +02:00
enum CmdParseState
{
STATE_EATING_SPACES ,
2016-12-19 09:08:00 +01:00
STATE_EATING_SPACES_IN_ARG ,
STATE_EATING_SPACES_IN_BRACKETS ,
2012-08-30 21:42:18 +02:00
STATE_ARGUMENT ,
STATE_SINGLEQUOTED ,
STATE_DOUBLEQUOTED ,
STATE_ESCAPE_OUTER ,
2016-09-20 12:59:08 +02:00
STATE_ESCAPE_DOUBLEQUOTED ,
STATE_COMMAND_EXECUTED ,
STATE_COMMAND_EXECUTED_INNER
2012-08-30 21:42:18 +02:00
} state = STATE_EATING_SPACES ;
std : : string curarg ;
2016-09-20 12:59:08 +02:00
UniValue lastResult ;
2017-01-03 16:57:15 +01:00
unsigned nDepthInsideSensitive = 0 ;
size_t filter_begin_pos = 0 , chpos ;
std : : vector < std : : pair < size_t , size_t > > filter_ranges ;
2017-01-10 10:14:15 +01:00
auto add_to_current_stack = [ & ] ( const std : : string & strArg ) {
if ( stack . back ( ) . empty ( ) & & ( ! nDepthInsideSensitive ) & & historyFilter . contains ( QString : : fromStdString ( strArg ) , Qt : : CaseInsensitive ) ) {
2017-01-03 16:57:15 +01:00
nDepthInsideSensitive = 1 ;
filter_begin_pos = chpos ;
}
2017-03-27 09:55:11 +02:00
// Make sure stack is not empty before adding something
if ( stack . empty ( ) ) {
stack . push_back ( std : : vector < std : : string > ( ) ) ;
}
2017-01-10 10:14:15 +01:00
stack . back ( ) . push_back ( strArg ) ;
2017-01-03 16:57:15 +01:00
} ;
auto close_out_params = [ & ] ( ) {
if ( nDepthInsideSensitive ) {
if ( ! - - nDepthInsideSensitive ) {
assert ( filter_begin_pos ) ;
filter_ranges . push_back ( std : : make_pair ( filter_begin_pos , chpos ) ) ;
filter_begin_pos = 0 ;
}
}
stack . pop_back ( ) ;
} ;
2016-09-20 12:59:08 +02:00
std : : string strCommandTerminated = strCommand ;
if ( strCommandTerminated . back ( ) ! = ' \n ' )
strCommandTerminated + = " \n " ;
2017-01-03 16:57:15 +01:00
for ( chpos = 0 ; chpos < strCommandTerminated . size ( ) ; + + chpos )
2012-08-30 21:42:18 +02:00
{
2017-01-03 16:57:15 +01:00
char ch = strCommandTerminated [ chpos ] ;
2012-08-30 21:42:18 +02:00
switch ( state )
2012-05-12 18:14:29 +02:00
{
2016-09-20 12:59:08 +02:00
case STATE_COMMAND_EXECUTED_INNER :
case STATE_COMMAND_EXECUTED :
2012-08-30 21:42:18 +02:00
{
2016-09-20 12:59:08 +02:00
bool breakParsing = true ;
switch ( ch )
2012-08-30 21:42:18 +02:00
{
2016-09-20 12:59:08 +02:00
case ' [ ' : curarg . clear ( ) ; state = STATE_COMMAND_EXECUTED_INNER ; break ;
default :
if ( state = = STATE_COMMAND_EXECUTED_INNER )
{
if ( ch ! = ' ] ' )
{
// append char to the current argument (which is also used for the query command)
curarg + = ch ;
break ;
}
2017-01-03 16:57:15 +01:00
if ( curarg . size ( ) & & fExecute )
2016-09-20 12:59:08 +02:00
{
// if we have a value query, query arrays with index and objects with a string key
UniValue subelement ;
if ( lastResult . isArray ( ) )
{
for ( char argch : curarg )
if ( ! std : : isdigit ( argch ) )
throw std : : runtime_error ( " Invalid result query " ) ;
subelement = lastResult [ atoi ( curarg . c_str ( ) ) ] ;
}
else if ( lastResult . isObject ( ) )
subelement = find_value ( lastResult , curarg ) ;
else
throw std : : runtime_error ( " Invalid result query " ) ; //no array or object: abort
lastResult = subelement ;
}
state = STATE_COMMAND_EXECUTED ;
break ;
}
// don't break parsing when the char is required for the next argument
breakParsing = false ;
// pop the stack and return the result to the current command arguments
2017-01-03 16:57:15 +01:00
close_out_params ( ) ;
2016-09-20 12:59:08 +02:00
// don't stringify the json in case of a string to avoid doublequotes
if ( lastResult . isStr ( ) )
curarg = lastResult . get_str ( ) ;
else
curarg = lastResult . write ( 2 ) ;
// if we have a non empty result, use it as stack argument otherwise as general result
if ( curarg . size ( ) )
{
if ( stack . size ( ) )
2017-01-03 16:57:15 +01:00
add_to_current_stack ( curarg ) ;
2016-09-20 12:59:08 +02:00
else
strResult = curarg ;
}
curarg . clear ( ) ;
// assume eating space state
state = STATE_EATING_SPACES ;
2012-08-30 21:42:18 +02:00
}
2016-09-20 12:59:08 +02:00
if ( breakParsing )
break ;
}
case STATE_ARGUMENT : // In or after argument
2016-12-19 09:08:00 +01:00
case STATE_EATING_SPACES_IN_ARG :
case STATE_EATING_SPACES_IN_BRACKETS :
2016-09-20 12:59:08 +02:00
case STATE_EATING_SPACES : // Handle runs of whitespace
switch ( ch )
{
case ' " ' : state = STATE_DOUBLEQUOTED ; break ;
case ' \' ' : state = STATE_SINGLEQUOTED ; break ;
case ' \\ ' : state = STATE_ESCAPE_OUTER ; break ;
case ' ( ' : case ' ) ' : case ' \n ' :
2016-12-19 09:08:00 +01:00
if ( state = = STATE_EATING_SPACES_IN_ARG )
throw std : : runtime_error ( " Invalid Syntax " ) ;
2016-09-20 12:59:08 +02:00
if ( state = = STATE_ARGUMENT )
{
if ( ch = = ' ( ' & & stack . size ( ) & & stack . back ( ) . size ( ) > 0 )
2017-01-03 16:57:15 +01:00
{
if ( nDepthInsideSensitive ) {
+ + nDepthInsideSensitive ;
}
2016-09-20 12:59:08 +02:00
stack . push_back ( std : : vector < std : : string > ( ) ) ;
2017-01-03 16:57:15 +01:00
}
2016-12-19 09:08:00 +01:00
// don't allow commands after executed commands on baselevel
if ( ! stack . size ( ) )
throw std : : runtime_error ( " Invalid Syntax " ) ;
2017-01-03 16:57:15 +01:00
add_to_current_stack ( curarg ) ;
2016-09-20 12:59:08 +02:00
curarg . clear ( ) ;
2016-12-19 09:08:00 +01:00
state = STATE_EATING_SPACES_IN_BRACKETS ;
2016-09-20 12:59:08 +02:00
}
if ( ( ch = = ' ) ' | | ch = = ' \n ' ) & & stack . size ( ) > 0 )
{
2017-01-03 16:57:15 +01:00
if ( fExecute ) {
// Convert argument list to JSON objects in method-dependent way,
// and pass it along with the method name to the dispatcher.
JSONRPCRequest req ;
req . params = RPCConvertValues ( stack . back ( ) [ 0 ] , std : : vector < std : : string > ( stack . back ( ) . begin ( ) + 1 , stack . back ( ) . end ( ) ) ) ;
req . strMethod = stack . back ( ) [ 0 ] ;
lastResult = tableRPC . execute ( req ) ;
}
2016-09-20 12:59:08 +02:00
state = STATE_COMMAND_EXECUTED ;
curarg . clear ( ) ;
}
break ;
case ' ' : case ' , ' : case ' \t ' :
2016-12-19 09:08:00 +01:00
if ( state = = STATE_EATING_SPACES_IN_ARG & & curarg . empty ( ) & & ch = = ' , ' )
throw std : : runtime_error ( " Invalid Syntax " ) ;
else if ( state = = STATE_ARGUMENT ) // Space ends argument
2016-09-20 12:59:08 +02:00
{
2017-01-03 16:57:15 +01:00
add_to_current_stack ( curarg ) ;
2016-09-20 12:59:08 +02:00
curarg . clear ( ) ;
}
2016-12-19 09:08:00 +01:00
if ( ( state = = STATE_EATING_SPACES_IN_BRACKETS | | state = = STATE_ARGUMENT ) & & ch = = ' , ' )
{
state = STATE_EATING_SPACES_IN_ARG ;
break ;
}
2016-09-20 12:59:08 +02:00
state = STATE_EATING_SPACES ;
break ;
default : curarg + = ch ; state = STATE_ARGUMENT ;
2012-08-30 21:42:18 +02:00
}
2016-09-20 12:59:08 +02:00
break ;
case STATE_SINGLEQUOTED : // Single-quoted string
switch ( ch )
2012-08-30 21:42:18 +02:00
{
2016-09-20 12:59:08 +02:00
case ' \' ' : state = STATE_ARGUMENT ; break ;
default : curarg + = ch ;
2012-08-30 21:42:18 +02:00
}
2016-09-20 12:59:08 +02:00
break ;
case STATE_DOUBLEQUOTED : // Double-quoted string
switch ( ch )
2012-08-30 21:42:18 +02:00
{
2016-09-20 12:59:08 +02:00
case ' " ' : state = STATE_ARGUMENT ; break ;
case ' \\ ' : state = STATE_ESCAPE_DOUBLEQUOTED ; break ;
default : curarg + = ch ;
2012-08-30 21:42:18 +02:00
}
2016-09-20 12:59:08 +02:00
break ;
case STATE_ESCAPE_OUTER : // '\' outside quotes
curarg + = ch ; state = STATE_ARGUMENT ;
break ;
case STATE_ESCAPE_DOUBLEQUOTED : // '\' in double-quoted text
if ( ch ! = ' " ' & & ch ! = ' \\ ' ) curarg + = ' \\ ' ; // keep '\' for everything but the quote and '\' itself
curarg + = ch ; state = STATE_DOUBLEQUOTED ;
break ;
2012-05-12 18:14:29 +02:00
}
}
2017-01-03 16:57:15 +01:00
if ( pstrFilteredOut ) {
if ( STATE_COMMAND_EXECUTED = = state ) {
assert ( ! stack . empty ( ) ) ;
close_out_params ( ) ;
}
* pstrFilteredOut = strCommand ;
for ( auto i = filter_ranges . rbegin ( ) ; i ! = filter_ranges . rend ( ) ; + + i ) {
pstrFilteredOut - > replace ( i - > first , i - > second - i - > first , " (…) " ) ;
}
}
2012-08-30 21:42:18 +02:00
switch ( state ) // final state
2012-04-09 21:07:25 +02:00
{
2016-09-20 12:59:08 +02:00
case STATE_COMMAND_EXECUTED :
if ( lastResult . isStr ( ) )
strResult = lastResult . get_str ( ) ;
else
strResult = lastResult . write ( 2 ) ;
case STATE_ARGUMENT :
case STATE_EATING_SPACES :
return true ;
default : // ERROR to end in one of the other states
return false ;
2012-04-09 21:07:25 +02:00
}
2012-08-30 21:42:18 +02:00
}
2012-04-09 21:07:25 +02:00
2012-08-30 21:42:18 +02:00
void RPCExecutor : : request ( const QString & command )
{
2012-08-31 17:40:13 +02:00
try
{
2016-09-20 12:59:08 +02:00
std : : string result ;
std : : string executableCommand = command . toStdString ( ) + " \n " ;
if ( ! RPCConsole : : RPCExecuteCommandLine ( result , executableCommand ) )
{
Q_EMIT reply ( RPCConsole : : CMD_ERROR , QString ( " Parse error: unbalanced ' or \" " ) ) ;
return ;
}
Q_EMIT reply ( RPCConsole : : CMD_REPLY , QString : : fromStdString ( result ) ) ;
2012-04-09 21:07:25 +02:00
}
2014-08-20 21:15:16 +02:00
catch ( UniValue & objError )
2012-04-09 21:07:25 +02:00
{
2012-08-31 17:40:13 +02:00
try // Nice formatting for standard-format error
{
int code = find_value ( objError , " code " ) . get_int ( ) ;
std : : string message = find_value ( objError , " message " ) . get_str ( ) ;
2015-07-14 13:59:05 +02:00
Q_EMIT reply ( RPCConsole : : CMD_ERROR , QString : : fromStdString ( message ) + " (code " + QString : : number ( code ) + " ) " ) ;
2012-08-31 17:40:13 +02:00
}
2014-12-07 13:29:06 +01:00
catch ( const std : : runtime_error & ) // raised when converting to invalid type, i.e. missing code or message
2012-08-30 21:42:18 +02:00
{ // Show raw JSON object
2015-07-14 13:59:05 +02:00
Q_EMIT reply ( RPCConsole : : CMD_ERROR , QString : : fromStdString ( objError . write ( ) ) ) ;
2012-08-31 17:40:13 +02:00
}
2012-04-09 21:07:25 +02:00
}
2014-12-07 13:29:06 +01:00
catch ( const std : : exception & e )
2012-04-09 21:07:25 +02:00
{
2015-07-14 13:59:05 +02:00
Q_EMIT reply ( RPCConsole : : CMD_ERROR , QString ( " Error: " ) + QString : : fromStdString ( e . what ( ) ) ) ;
2012-04-09 21:07:25 +02:00
}
}
2016-09-23 12:44:09 +02:00
RPCConsole : : RPCConsole ( const PlatformStyle * _platformStyle , QWidget * parent ) :
2014-11-10 16:41:57 +01:00
QWidget ( parent ) ,
2012-04-09 21:07:25 +02:00
ui ( new Ui : : RPCConsole ) ,
2013-04-02 11:24:10 +02:00
clientModel ( 0 ) ,
2014-06-04 12:06:18 +02:00
historyPtr ( 0 ) ,
2016-09-23 12:44:09 +02:00
platformStyle ( _platformStyle ) ,
2015-06-20 20:55:21 +02:00
peersTableContextMenu ( 0 ) ,
2017-09-07 17:59:00 +02:00
banTableContextMenu ( 0 ) ,
consoleFontSize ( 0 )
2012-04-09 21:07:25 +02:00
{
ui - > setupUi ( this ) ;
2013-07-13 13:14:23 +02:00
GUIUtil : : restoreWindowGeometry ( " nRPCConsoleWindow " , this - > size ( ) , this ) ;
2016-02-04 13:41:58 +01:00
ui - > openDebugLogfileButton - > setToolTip ( ui - > openDebugLogfileButton - > toolTip ( ) . arg ( tr ( PACKAGE_NAME ) ) ) ;
2015-09-12 23:42:04 +02:00
QString theme = GUIUtil : : getThemeName ( ) ;
2015-07-28 15:20:14 +02:00
if ( platformStyle - > getImagesOnButtons ( ) ) {
2016-02-02 16:28:56 +01:00
ui - > openDebugLogfileButton - > setIcon ( QIcon ( " :/icons/ " + theme + " /export " ) ) ;
2015-07-28 15:20:14 +02:00
}
2015-09-05 22:54:11 +02:00
// Needed on Mac also
2015-09-12 23:42:04 +02:00
ui - > clearButton - > setIcon ( QIcon ( " :/icons/ " + theme + " /remove " ) ) ;
2017-09-07 17:59:00 +02:00
ui - > fontBiggerButton - > setIcon ( QIcon ( " :/icons/ " + theme + " /fontbigger " ) ) ;
ui - > fontSmallerButton - > setIcon ( QIcon ( " :/icons/ " + theme + " /fontsmaller " ) ) ;
2015-09-05 22:54:11 +02:00
2012-04-09 21:07:25 +02:00
// Install event filter for up and down arrow
ui - > lineEdit - > installEventFilter ( this ) ;
2012-09-09 20:07:22 +02:00
ui - > messagesWidget - > installEventFilter ( this ) ;
2012-04-09 21:07:25 +02:00
connect ( ui - > clearButton , SIGNAL ( clicked ( ) ) , this , SLOT ( clear ( ) ) ) ;
2017-09-07 17:59:00 +02:00
connect ( ui - > fontBiggerButton , SIGNAL ( clicked ( ) ) , this , SLOT ( fontBigger ( ) ) ) ;
connect ( ui - > fontSmallerButton , SIGNAL ( clicked ( ) ) , this , SLOT ( fontSmaller ( ) ) ) ;
2013-11-08 08:13:08 +01:00
connect ( ui - > btnClearTrafficGraph , SIGNAL ( clicked ( ) ) , ui - > trafficGraph , SLOT ( clear ( ) ) ) ;
2015-05-23 13:28:33 +02:00
2015-05-25 18:29:11 +02:00
// Wallet Repair Buttons
2017-03-15 00:56:09 +01:00
// connect(ui->btn_salvagewallet, SIGNAL(clicked()), this, SLOT(walletSalvage()));
// Disable salvage option in GUI, it's way too powerful and can lead to funds loss
ui - > btn_salvagewallet - > setEnabled ( false ) ;
2015-05-28 23:09:14 +02:00
connect ( ui - > btn_rescan , SIGNAL ( clicked ( ) ) , this , SLOT ( walletRescan ( ) ) ) ;
connect ( ui - > btn_zapwallettxes1 , SIGNAL ( clicked ( ) ) , this , SLOT ( walletZaptxes1 ( ) ) ) ;
connect ( ui - > btn_zapwallettxes2 , SIGNAL ( clicked ( ) ) , this , SLOT ( walletZaptxes2 ( ) ) ) ;
connect ( ui - > btn_upgradewallet , SIGNAL ( clicked ( ) ) , this , SLOT ( walletUpgrade ( ) ) ) ;
connect ( ui - > btn_reindex , SIGNAL ( clicked ( ) ) , this , SLOT ( walletReindex ( ) ) ) ;
2012-04-09 21:07:25 +02:00
2014-06-04 22:00:59 +02:00
// set library version labels
# ifdef ENABLE_WALLET
ui - > berkeleyDBVersion - > setText ( DbEnv : : version ( 0 , 0 , 0 ) ) ;
2015-10-25 20:54:46 +01:00
std : : string walletPath = GetDataDir ( ) . string ( ) ;
2015-10-25 21:45:08 +01:00
walletPath + = QDir : : separator ( ) . toLatin1 ( ) + GetArg ( " -wallet " , " wallet.dat " ) ;
2015-10-25 21:28:18 +01:00
ui - > wallet_path - > setText ( QString : : fromStdString ( walletPath ) ) ;
2014-06-04 22:00:59 +02:00
# else
ui - > label_berkeleyDBVersion - > hide ( ) ;
ui - > berkeleyDBVersion - > hide ( ) ;
# endif
2015-08-28 16:46:20 +02:00
// Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface ( ) ;
2016-01-08 17:34:41 +01:00
// avoid accidentally overwriting an existing, non QTThread
// based timer interface
RPCSetTimerInterfaceIfUnset ( rpcTimerInterface ) ;
2012-06-14 19:18:30 +02:00
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
setTrafficGraphRange ( INITIAL_TRAFFIC_GRAPH_SETTING ) ;
2012-04-09 21:07:25 +02:00
2014-06-04 12:06:18 +02:00
ui - > peerHeading - > setText ( tr ( " Select a peer to view detailed information. " ) ) ;
2012-04-09 21:07:25 +02:00
2017-09-07 17:59:00 +02:00
QSettings settings ;
consoleFontSize = settings . value ( fontSizeSettingsKey , QFontInfo ( QFont ( ) ) . pointSize ( ) ) . toInt ( ) ;
2012-04-09 21:07:25 +02:00
clear ( ) ;
}
RPCConsole : : ~ RPCConsole ( )
{
2013-07-13 13:14:23 +02:00
GUIUtil : : saveWindowGeometry ( " nRPCConsoleWindow " , this ) ;
2016-01-08 17:34:41 +01:00
RPCUnsetTimerInterface ( rpcTimerInterface ) ;
2015-08-28 16:46:20 +02:00
delete rpcTimerInterface ;
2012-04-09 21:07:25 +02:00
delete ui ;
}
bool RPCConsole : : eventFilter ( QObject * obj , QEvent * event )
{
2012-09-09 20:07:22 +02:00
if ( event - > type ( ) = = QEvent : : KeyPress ) // Special key handling
2012-04-09 21:07:25 +02:00
{
2012-09-09 20:07:22 +02:00
QKeyEvent * keyevt = static_cast < QKeyEvent * > ( event ) ;
int key = keyevt - > key ( ) ;
Qt : : KeyboardModifiers mod = keyevt - > modifiers ( ) ;
switch ( key )
2012-04-09 21:07:25 +02:00
{
2012-09-09 20:07:22 +02:00
case Qt : : Key_Up : if ( obj = = ui - > lineEdit ) { browseHistory ( - 1 ) ; return true ; } break ;
case Qt : : Key_Down : if ( obj = = ui - > lineEdit ) { browseHistory ( 1 ) ; return true ; } break ;
case Qt : : Key_PageUp : /* pass paging keys to messages widget */
case Qt : : Key_PageDown :
if ( obj = = ui - > lineEdit )
2012-04-09 21:07:25 +02:00
{
2012-09-09 20:07:22 +02:00
QApplication : : postEvent ( ui - > messagesWidget , new QKeyEvent ( * keyevt ) ) ;
return true ;
}
break ;
2016-05-31 06:56:58 +02:00
case Qt : : Key_Return :
case Qt : : Key_Enter :
// forward these events to lineEdit
if ( obj = = autoCompleter - > popup ( ) ) {
2018-02-06 18:24:37 +01:00
autoCompleter - > popup ( ) - > hide ( ) ;
2016-05-31 06:56:58 +02:00
QApplication : : postEvent ( ui - > lineEdit , new QKeyEvent ( * keyevt ) ) ;
return true ;
}
break ;
2012-09-09 20:07:22 +02:00
default :
// Typing in messages widget brings focus to line edit, and redirects key there
// Exclude most combinations and keys that emit no text, except paste shortcuts
if ( obj = = ui - > messagesWidget & & (
( ! mod & & ! keyevt - > text ( ) . isEmpty ( ) & & key ! = Qt : : Key_Tab ) | |
( ( mod & Qt : : ControlModifier ) & & key = = Qt : : Key_V ) | |
( ( mod & Qt : : ShiftModifier ) & & key = = Qt : : Key_Insert ) ) )
{
ui - > lineEdit - > setFocus ( ) ;
QApplication : : postEvent ( ui - > lineEdit , new QKeyEvent ( * keyevt ) ) ;
return true ;
2012-04-09 21:07:25 +02:00
}
}
}
2014-11-10 16:41:57 +01:00
return QWidget : : eventFilter ( obj , event ) ;
2012-04-09 21:07:25 +02:00
}
void RPCConsole : : setClientModel ( ClientModel * model )
{
2013-08-22 18:09:32 +02:00
clientModel = model ;
ui - > trafficGraph - > setClientModel ( model ) ;
2015-06-26 10:23:51 +02:00
if ( model & & clientModel - > getPeerTableModel ( ) & & clientModel - > getBanTableModel ( ) ) {
2013-06-03 14:10:14 +02:00
// Keep up to date with client
setNumConnections ( model - > getNumConnections ( ) ) ;
2012-04-09 21:07:25 +02:00
connect ( model , SIGNAL ( numConnectionsChanged ( int ) ) , this , SLOT ( setNumConnections ( int ) ) ) ;
2013-06-03 14:10:14 +02:00
2017-07-10 16:41:14 +02:00
setNumBlocks ( model - > getNumBlocks ( ) , model - > getLastBlockDate ( ) , model - > getVerificationProgress ( NULL ) , false ) ;
connect ( model , SIGNAL ( numBlocksChanged ( int , QDateTime , double , bool ) ) , this , SLOT ( setNumBlocks ( int , QDateTime , double , bool ) ) ) ;
2012-04-09 21:07:25 +02:00
2017-09-11 15:38:14 +02:00
updateNetworkState ( ) ;
connect ( model , SIGNAL ( networkActiveChanged ( bool ) ) , this , SLOT ( setNetworkActive ( bool ) ) ) ;
2015-02-24 14:24:42 +01:00
setMasternodeCount ( model - > getMasternodeCountString ( ) ) ;
connect ( model , SIGNAL ( strMasternodesChanged ( QString ) ) , this , SLOT ( setMasternodeCount ( QString ) ) ) ;
2013-08-22 18:09:32 +02:00
updateTrafficStats ( model - > getTotalBytesRecv ( ) , model - > getTotalBytesSent ( ) ) ;
connect ( model , SIGNAL ( bytesChanged ( quint64 , quint64 ) ) , this , SLOT ( updateTrafficStats ( quint64 , quint64 ) ) ) ;
2015-11-09 11:45:07 +01:00
connect ( model , SIGNAL ( mempoolSizeChanged ( long , size_t ) ) , this , SLOT ( setMempoolSize ( long , size_t ) ) ) ;
2014-05-23 19:09:59 +02:00
// set up peer table
ui - > peerWidget - > setModel ( model - > getPeerTableModel ( ) ) ;
ui - > peerWidget - > verticalHeader ( ) - > hide ( ) ;
ui - > peerWidget - > setEditTriggers ( QAbstractItemView : : NoEditTriggers ) ;
ui - > peerWidget - > setSelectionBehavior ( QAbstractItemView : : SelectRows ) ;
2017-09-11 15:38:14 +02:00
ui - > peerWidget - > setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
2015-06-01 15:32:25 +02:00
ui - > peerWidget - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
2014-05-23 19:09:59 +02:00
ui - > peerWidget - > setColumnWidth ( PeerTableModel : : Address , ADDRESS_COLUMN_WIDTH ) ;
2014-06-04 12:06:18 +02:00
ui - > peerWidget - > setColumnWidth ( PeerTableModel : : Subversion , SUBVERSION_COLUMN_WIDTH ) ;
ui - > peerWidget - > setColumnWidth ( PeerTableModel : : Ping , PING_COLUMN_WIDTH ) ;
2015-06-20 21:48:10 +02:00
ui - > peerWidget - > horizontalHeader ( ) - > setStretchLastSection ( true ) ;
2015-06-20 20:27:03 +02:00
2015-06-26 14:55:52 +02:00
// create peer table context menu actions
2017-09-11 15:38:14 +02:00
QAction * disconnectAction = new QAction ( tr ( " &Disconnect " ) , this ) ;
QAction * banAction1h = new QAction ( tr ( " Ban for " ) + " " + tr ( " 1 &hour " ) , this ) ;
QAction * banAction24h = new QAction ( tr ( " Ban for " ) + " " + tr ( " 1 &day " ) , this ) ;
QAction * banAction7d = new QAction ( tr ( " Ban for " ) + " " + tr ( " 1 &week " ) , this ) ;
QAction * banAction365d = new QAction ( tr ( " Ban for " ) + " " + tr ( " 1 &year " ) , this ) ;
2015-06-26 14:55:52 +02:00
// create peer table context menu
2017-09-11 15:38:14 +02:00
peersTableContextMenu = new QMenu ( this ) ;
2015-06-20 20:55:21 +02:00
peersTableContextMenu - > addAction ( disconnectAction ) ;
peersTableContextMenu - > addAction ( banAction1h ) ;
peersTableContextMenu - > addAction ( banAction24h ) ;
peersTableContextMenu - > addAction ( banAction7d ) ;
peersTableContextMenu - > addAction ( banAction365d ) ;
2015-06-01 15:32:25 +02:00
2015-06-23 21:10:42 +02:00
// Add a signal mapping to allow dynamic context menu arguments.
// We need to use int (instead of int64_t), because signal mapper only supports
// int or objects, which is okay because max bantime (1 year) is < int_max.
2015-06-19 13:24:34 +02:00
QSignalMapper * signalMapper = new QSignalMapper ( this ) ;
signalMapper - > setMapping ( banAction1h , 60 * 60 ) ;
signalMapper - > setMapping ( banAction24h , 60 * 60 * 24 ) ;
signalMapper - > setMapping ( banAction7d , 60 * 60 * 24 * 7 ) ;
signalMapper - > setMapping ( banAction365d , 60 * 60 * 24 * 365 ) ;
connect ( banAction1h , SIGNAL ( triggered ( ) ) , signalMapper , SLOT ( map ( ) ) ) ;
connect ( banAction24h , SIGNAL ( triggered ( ) ) , signalMapper , SLOT ( map ( ) ) ) ;
connect ( banAction7d , SIGNAL ( triggered ( ) ) , signalMapper , SLOT ( map ( ) ) ) ;
connect ( banAction365d , SIGNAL ( triggered ( ) ) , signalMapper , SLOT ( map ( ) ) ) ;
2015-06-23 21:10:42 +02:00
connect ( signalMapper , SIGNAL ( mapped ( int ) ) , this , SLOT ( banSelectedNode ( int ) ) ) ;
2015-06-19 13:24:34 +02:00
2015-06-26 14:55:52 +02:00
// peer table context menu signals
connect ( ui - > peerWidget , SIGNAL ( customContextMenuRequested ( const QPoint & ) ) , this , SLOT ( showPeersTableContextMenu ( const QPoint & ) ) ) ;
connect ( disconnectAction , SIGNAL ( triggered ( ) ) , this , SLOT ( disconnectSelectedNode ( ) ) ) ;
// peer table signal handling - update peer details when selecting new node
2014-06-04 12:06:18 +02:00
connect ( ui - > peerWidget - > selectionModel ( ) , SIGNAL ( selectionChanged ( const QItemSelection & , const QItemSelection & ) ) ,
2015-06-26 14:55:52 +02:00
this , SLOT ( peerSelected ( const QItemSelection & , const QItemSelection & ) ) ) ;
// peer table signal handling - update peer details when new nodes are added to the model
2014-05-23 19:09:59 +02:00
connect ( model - > getPeerTableModel ( ) , SIGNAL ( layoutChanged ( ) ) , this , SLOT ( peerLayoutChanged ( ) ) ) ;
2017-09-11 15:38:14 +02:00
// peer table signal handling - cache selected node ids
connect ( model - > getPeerTableModel ( ) , SIGNAL ( layoutAboutToBeChanged ( ) ) , this , SLOT ( peerLayoutAboutToChange ( ) ) ) ;
2015-06-20 20:55:21 +02:00
// set up ban table
ui - > banlistWidget - > setModel ( model - > getBanTableModel ( ) ) ;
ui - > banlistWidget - > verticalHeader ( ) - > hide ( ) ;
ui - > banlistWidget - > setEditTriggers ( QAbstractItemView : : NoEditTriggers ) ;
ui - > banlistWidget - > setSelectionBehavior ( QAbstractItemView : : SelectRows ) ;
ui - > banlistWidget - > setSelectionMode ( QAbstractItemView : : SingleSelection ) ;
ui - > banlistWidget - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
2015-06-26 14:55:52 +02:00
ui - > banlistWidget - > setColumnWidth ( BanTableModel : : Address , BANSUBNET_COLUMN_WIDTH ) ;
ui - > banlistWidget - > setColumnWidth ( BanTableModel : : Bantime , BANTIME_COLUMN_WIDTH ) ;
2015-06-20 21:48:10 +02:00
ui - > banlistWidget - > horizontalHeader ( ) - > setStretchLastSection ( true ) ;
2015-06-20 20:55:21 +02:00
2015-06-26 10:23:51 +02:00
// create ban table context menu action
2017-09-11 15:38:14 +02:00
QAction * unbanAction = new QAction ( tr ( " &Unban " ) , this ) ;
2015-06-26 10:23:51 +02:00
// create ban table context menu
2017-09-11 15:38:14 +02:00
banTableContextMenu = new QMenu ( this ) ;
2015-06-20 20:55:21 +02:00
banTableContextMenu - > addAction ( unbanAction ) ;
2015-06-26 10:23:51 +02:00
// ban table context menu signals
2015-06-20 20:55:21 +02:00
connect ( ui - > banlistWidget , SIGNAL ( customContextMenuRequested ( const QPoint & ) ) , this , SLOT ( showBanTableContextMenu ( const QPoint & ) ) ) ;
connect ( unbanAction , SIGNAL ( triggered ( ) ) , this , SLOT ( unbanSelectedNode ( ) ) ) ;
2015-06-26 10:23:51 +02:00
// ban table signal handling - clear peer details when clicking a peer in the ban table
connect ( ui - > banlistWidget , SIGNAL ( clicked ( const QModelIndex & ) ) , this , SLOT ( clearSelectedNode ( ) ) ) ;
// ban table signal handling - ensure ban table is shown or hidden (if empty)
connect ( model - > getBanTableModel ( ) , SIGNAL ( layoutChanged ( ) ) , this , SLOT ( showOrHideBanTableIfRequired ( ) ) ) ;
showOrHideBanTableIfRequired ( ) ;
2012-04-09 21:07:25 +02:00
// Provide initial values
ui - > clientVersion - > setText ( model - > formatFullVersion ( ) ) ;
2015-08-06 15:40:50 +02:00
ui - > clientUserAgent - > setText ( model - > formatSubVersion ( ) ) ;
2017-09-09 09:04:02 +02:00
ui - > dataDir - > setText ( model - > dataDir ( ) ) ;
2012-05-21 23:05:54 +02:00
ui - > startupTime - > setText ( model - > formatClientStartupTime ( ) ) ;
2014-06-11 12:23:49 +02:00
ui - > networkName - > setText ( QString : : fromStdString ( Params ( ) . NetworkIDString ( ) ) ) ;
2016-02-27 04:57:12 +01:00
//Setup autocomplete and attach it
QStringList wordList ;
std : : vector < std : : string > commandList = tableRPC . listCommands ( ) ;
for ( size_t i = 0 ; i < commandList . size ( ) ; + + i )
{
wordList < < commandList [ i ] . c_str ( ) ;
}
autoCompleter = new QCompleter ( wordList , this ) ;
ui - > lineEdit - > setCompleter ( autoCompleter ) ;
2016-05-31 06:56:58 +02:00
autoCompleter - > popup ( ) - > installEventFilter ( this ) ;
2017-09-11 15:38:14 +02:00
// Start thread to execute RPC commands.
startExecutor ( ) ;
}
if ( ! model ) {
// Client model is being set to 0, this means shutdown() is about to be called.
// Make sure we clean up the executor thread
Q_EMIT stopExecutor ( ) ;
thread . wait ( ) ;
2012-04-09 21:07:25 +02:00
}
}
2012-05-12 12:30:07 +02:00
static QString categoryClass ( int category )
2012-04-09 21:07:25 +02:00
{
switch ( category )
{
2012-05-12 12:30:07 +02:00
case RPCConsole : : CMD_REQUEST : return " cmd-request " ; break ;
case RPCConsole : : CMD_REPLY : return " cmd-reply " ; break ;
case RPCConsole : : CMD_ERROR : return " cmd-error " ; break ;
default : return " misc " ;
2012-04-09 21:07:25 +02:00
}
}
2017-09-07 17:59:00 +02:00
void RPCConsole : : fontBigger ( )
{
setFontSize ( consoleFontSize + 1 ) ;
}
void RPCConsole : : fontSmaller ( )
{
setFontSize ( consoleFontSize - 1 ) ;
}
void RPCConsole : : setFontSize ( int newSize )
{
QSettings settings ;
//don't allow a insane font size
if ( newSize < FONT_RANGE . width ( ) | | newSize > FONT_RANGE . height ( ) )
return ;
// temp. store the console content
QString str = ui - > messagesWidget - > toHtml ( ) ;
// replace font tags size in current content
str . replace ( QString ( " font-size:%1pt " ) . arg ( consoleFontSize ) , QString ( " font-size:%1pt " ) . arg ( newSize ) ) ;
// store the new font size
consoleFontSize = newSize ;
settings . setValue ( fontSizeSettingsKey , consoleFontSize ) ;
// clear console (reset icon sizes, default stylesheet) and re-add the content
float oldPosFactor = 1.0 / ui - > messagesWidget - > verticalScrollBar ( ) - > maximum ( ) * ui - > messagesWidget - > verticalScrollBar ( ) - > value ( ) ;
clear ( false ) ;
ui - > messagesWidget - > setHtml ( str ) ;
ui - > messagesWidget - > verticalScrollBar ( ) - > setValue ( oldPosFactor * ui - > messagesWidget - > verticalScrollBar ( ) - > maximum ( ) ) ;
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-salvagewallet" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletSalvage ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( SALVAGEWALLET ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-rescan" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletRescan ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( RESCAN ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-zapwallettxes=1" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletZaptxes1 ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( ZAPTXES1 ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-zapwallettxes=2" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletZaptxes2 ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( ZAPTXES2 ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-upgradewallet" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletUpgrade ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( UPGRADEWALLET ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Restart wallet with "-reindex" */
2015-05-28 23:09:14 +02:00
void RPCConsole : : walletReindex ( )
2015-05-23 13:28:33 +02:00
{
2015-05-28 23:09:14 +02:00
buildParameterlist ( REINDEX ) ;
2015-05-23 13:28:33 +02:00
}
2015-05-25 18:29:11 +02:00
/** Build command-line parameter list for restart */
2015-05-28 23:09:14 +02:00
void RPCConsole : : buildParameterlist ( QString arg )
2015-05-23 13:28:33 +02:00
{
2015-05-25 18:29:11 +02:00
// Get command-line arguments and remove the application name
QStringList args = QApplication : : arguments ( ) ;
args . removeFirst ( ) ;
2015-05-28 23:09:14 +02:00
// Remove existing repair-options
args . removeAll ( SALVAGEWALLET ) ;
args . removeAll ( RESCAN ) ;
args . removeAll ( ZAPTXES1 ) ;
args . removeAll ( ZAPTXES2 ) ;
args . removeAll ( UPGRADEWALLET ) ;
args . removeAll ( REINDEX ) ;
2015-05-28 23:14:09 +02:00
// Append repair parameter to command line.
2015-05-25 18:29:11 +02:00
args . append ( arg ) ;
2015-05-28 23:09:14 +02:00
2015-05-25 18:29:11 +02:00
// Send command-line arguments to BitcoinGUI::handleRestart()
2016-02-02 16:28:56 +01:00
Q_EMIT handleRestart ( args ) ;
2015-05-23 13:28:33 +02:00
}
2017-09-07 17:59:00 +02:00
void RPCConsole : : clear ( bool clearHistory )
2012-04-09 21:07:25 +02:00
{
ui - > messagesWidget - > clear ( ) ;
2017-09-07 17:59:00 +02:00
if ( clearHistory )
{
history . clear ( ) ;
historyPtr = 0 ;
}
2012-04-09 21:07:25 +02:00
ui - > lineEdit - > clear ( ) ;
ui - > lineEdit - > setFocus ( ) ;
2012-05-12 12:30:07 +02:00
// Add smoothly scaled icon images.
// (when using width/height on an img, Qt uses nearest instead of linear interpolation)
2015-09-16 05:29:57 +02:00
QString iconPath = " :/icons/ " + GUIUtil : : getThemeName ( ) + " / " ;
QString iconName = " " ;
2012-05-12 12:30:07 +02:00
for ( int i = 0 ; ICON_MAPPING [ i ] . url ; + + i )
{
2015-09-16 05:29:57 +02:00
iconName = ICON_MAPPING [ i ] . source ;
2012-05-12 12:30:07 +02:00
ui - > messagesWidget - > document ( ) - > addResource (
QTextDocument : : ImageResource ,
QUrl ( ICON_MAPPING [ i ] . url ) ,
2017-09-07 17:59:00 +02:00
QImage ( iconPath + iconName ) . scaled ( QSize ( consoleFontSize * 2 , consoleFontSize * 2 ) , Qt : : IgnoreAspectRatio , Qt : : SmoothTransformation ) ) ;
2012-05-12 12:30:07 +02:00
}
// Set default style sheet
2015-10-22 13:33:58 +02:00
QFontInfo fixedFontInfo ( GUIUtil : : fixedPitchFont ( ) ) ;
2012-05-12 12:30:07 +02:00
ui - > messagesWidget - > document ( ) - > setDefaultStyleSheet (
2015-10-22 13:33:58 +02:00
QString (
2012-05-12 12:30:07 +02:00
" table { } "
2017-09-07 17:59:00 +02:00
" td.time { color: #808080; font-size: %2; padding-top: 3px; } "
2015-10-22 13:33:58 +02:00
" td.message { font-family: %1; font-size: %2; white-space:pre-wrap; } "
2012-05-12 12:30:07 +02:00
" td.cmd-request { color: #006060; } "
" td.cmd-error { color: red; } "
2016-12-14 09:34:25 +01:00
" .secwarning { color: red; } "
2012-05-12 12:30:07 +02:00
" b { color: #006060; } "
2017-09-07 17:59:00 +02:00
) . arg ( fixedFontInfo . family ( ) , QString ( " %1pt " ) . arg ( consoleFontSize ) )
2015-10-22 13:33:58 +02:00
) ;
2012-05-12 12:30:07 +02:00
2016-02-04 13:41:58 +01:00
message ( CMD_REPLY , ( tr ( " Welcome to the %1 RPC console. " ) . arg ( tr ( PACKAGE_NAME ) ) + " <br> " +
2012-05-16 15:34:29 +02:00
tr ( " Use up and down arrows to navigate history, and <b>Ctrl-L</b> to clear screen. " ) + " <br> " +
2016-12-14 09:34:25 +01:00
tr ( " Type <b>help</b> for an overview of available commands. " ) ) +
" <br><span class= \" secwarning \" > " +
tr ( " WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command. " ) +
" </span> " ,
true ) ;
2012-04-09 21:07:25 +02:00
}
2014-11-10 16:41:57 +01:00
void RPCConsole : : keyPressEvent ( QKeyEvent * event )
2014-03-18 14:51:28 +01:00
{
2014-11-10 16:41:57 +01:00
if ( windowType ( ) ! = Qt : : Widget & & event - > key ( ) = = Qt : : Key_Escape )
{
close ( ) ;
}
2014-03-18 14:51:28 +01:00
}
2012-05-12 12:30:07 +02:00
void RPCConsole : : message ( int category , const QString & message , bool html )
2012-04-09 21:07:25 +02:00
{
QTime time = QTime : : currentTime ( ) ;
2012-05-12 12:30:07 +02:00
QString timeString = time . toString ( ) ;
QString out ;
out + = " <table><tr><td class= \" time \" width= \" 65 \" > " + timeString + " </td> " ;
out + = " <td class= \" icon \" width= \" 32 \" ><img src= \" " + categoryClass ( category ) + " \" ></td> " ;
out + = " <td class= \" message " + categoryClass ( category ) + " \" valign= \" middle \" > " ;
if ( html )
out + = message ;
else
2015-10-22 13:33:58 +02:00
out + = GUIUtil : : HtmlEscape ( message , false ) ;
2012-05-12 12:30:07 +02:00
out + = " </td></tr></table> " ;
ui - > messagesWidget - > append ( out ) ;
2012-04-09 21:07:25 +02:00
}
2017-09-11 15:38:14 +02:00
void RPCConsole : : updateNetworkState ( )
{
QString connections = QString : : number ( clientModel - > getNumConnections ( ) ) + " ( " ;
connections + = tr ( " In: " ) + " " + QString : : number ( clientModel - > getNumConnections ( CONNECTIONS_IN ) ) + " / " ;
connections + = tr ( " Out: " ) + " " + QString : : number ( clientModel - > getNumConnections ( CONNECTIONS_OUT ) ) + " ) " ;
if ( ! clientModel - > getNetworkActive ( ) ) {
connections + = " ( " + tr ( " Network activity disabled " ) + " ) " ;
}
ui - > numberOfConnections - > setText ( connections ) ;
}
2012-04-09 21:07:25 +02:00
void RPCConsole : : setNumConnections ( int count )
{
2014-02-16 19:48:27 +01:00
if ( ! clientModel )
return ;
2017-09-11 15:38:14 +02:00
updateNetworkState ( ) ;
}
2014-02-16 19:48:27 +01:00
2017-09-11 15:38:14 +02:00
void RPCConsole : : setNetworkActive ( bool networkActive )
{
updateNetworkState ( ) ;
2012-04-09 21:07:25 +02:00
}
2017-07-10 16:41:14 +02:00
void RPCConsole : : setNumBlocks ( int count , const QDateTime & blockDate , double nVerificationProgress , bool headers )
2012-04-09 21:07:25 +02:00
{
2017-07-10 16:41:14 +02:00
if ( ! headers ) {
ui - > numberOfBlocks - > setText ( QString : : number ( count ) ) ;
ui - > lastBlockTime - > setText ( blockDate . toString ( ) ) ;
}
2015-02-24 14:24:42 +01:00
}
2014-12-31 03:54:00 +01:00
2015-02-24 14:24:42 +01:00
void RPCConsole : : setMasternodeCount ( const QString & strMasternodes )
{
ui - > masternodeCount - > setText ( strMasternodes ) ;
2012-04-09 21:07:25 +02:00
}
2015-11-09 11:45:07 +01:00
void RPCConsole : : setMempoolSize ( long numberOfTxs , size_t dynUsage )
{
ui - > mempoolNumberTxs - > setText ( QString : : number ( numberOfTxs ) ) ;
if ( dynUsage < 1000000 )
ui - > mempoolSize - > setText ( QString : : number ( dynUsage / 1000.0 , ' f ' , 2 ) + " KB " ) ;
else
ui - > mempoolSize - > setText ( QString : : number ( dynUsage / 1000000.0 , ' f ' , 2 ) + " MB " ) ;
}
2012-04-09 21:07:25 +02:00
void RPCConsole : : on_lineEdit_returnPressed ( )
{
QString cmd = ui - > lineEdit - > text ( ) ;
if ( ! cmd . isEmpty ( ) )
{
2017-01-03 16:57:15 +01:00
std : : string strFilteredCmd ;
try {
std : : string dummy ;
if ( ! RPCParseCommandLine ( dummy , cmd . toStdString ( ) , false , & strFilteredCmd ) ) {
// Failed to parse command, so we cannot even filter it for the history
throw std : : runtime_error ( " Invalid command line " ) ;
}
} catch ( const std : : exception & e ) {
QMessageBox : : critical ( this , " Error " , QString ( " Error: " ) + QString : : fromStdString ( e . what ( ) ) ) ;
return ;
}
ui - > lineEdit - > clear ( ) ;
cmdBeforeBrowsing = QString ( ) ;
2012-04-09 21:07:25 +02:00
message ( CMD_REQUEST , cmd ) ;
2015-07-14 13:59:05 +02:00
Q_EMIT cmdRequest ( cmd ) ;
2017-01-03 16:57:15 +01:00
cmd = QString : : fromStdString ( strFilteredCmd ) ;
2015-03-25 10:16:46 +01:00
// Remove command, if already in history
history . removeOne ( cmd ) ;
2012-04-09 21:07:25 +02:00
// Append command to history
history . append ( cmd ) ;
// Enforce maximum history size
while ( history . size ( ) > CONSOLE_HISTORY )
history . removeFirst ( ) ;
// Set pointer to end of history
historyPtr = history . size ( ) ;
2017-01-03 16:57:15 +01:00
2012-05-14 18:17:12 +02:00
// Scroll console view to end
scrollToEnd ( ) ;
2012-04-09 21:07:25 +02:00
}
}
void RPCConsole : : browseHistory ( int offset )
{
2017-01-03 16:57:15 +01:00
// store current text when start browsing through the history
if ( historyPtr = = history . size ( ) ) {
cmdBeforeBrowsing = ui - > lineEdit - > text ( ) ;
}
2012-04-09 21:07:25 +02:00
historyPtr + = offset ;
if ( historyPtr < 0 )
historyPtr = 0 ;
if ( historyPtr > history . size ( ) )
historyPtr = history . size ( ) ;
QString cmd ;
if ( historyPtr < history . size ( ) )
cmd = history . at ( historyPtr ) ;
2017-01-03 16:57:15 +01:00
else if ( ! cmdBeforeBrowsing . isNull ( ) ) {
cmd = cmdBeforeBrowsing ;
}
2012-04-09 21:07:25 +02:00
ui - > lineEdit - > setText ( cmd ) ;
}
void RPCConsole : : startExecutor ( )
{
RPCExecutor * executor = new RPCExecutor ( ) ;
2017-09-11 15:38:14 +02:00
executor - > moveToThread ( & thread ) ;
2012-04-09 21:07:25 +02:00
// Replies from executor object must go to this object
connect ( executor , SIGNAL ( reply ( int , QString ) ) , this , SLOT ( message ( int , QString ) ) ) ;
// Requests from this object must go to executor
connect ( this , SIGNAL ( cmdRequest ( QString ) ) , executor , SLOT ( request ( QString ) ) ) ;
2013-04-02 11:24:10 +02:00
2012-04-09 21:07:25 +02:00
// On stopExecutor signal
// - quit the Qt event loop in the execution thread
2017-09-11 15:38:14 +02:00
connect ( this , SIGNAL ( stopExecutor ( ) ) , & thread , SLOT ( quit ( ) ) ) ;
// - queue executor for deletion (in execution thread)
connect ( & thread , SIGNAL ( finished ( ) ) , executor , SLOT ( deleteLater ( ) ) , Qt : : DirectConnection ) ;
2012-04-09 21:07:25 +02:00
// Default implementation of QThread::run() simply spins up an event loop in the thread,
// which is what we want.
2017-09-11 15:38:14 +02:00
thread . start ( ) ;
2012-04-09 21:07:25 +02:00
}
2012-05-09 17:12:05 +02:00
void RPCConsole : : on_tabWidget_currentChanged ( int index )
{
2015-06-06 10:38:15 +02:00
if ( ui - > tabWidget - > widget ( index ) = = ui - > tab_console )
2012-05-09 17:12:05 +02:00
ui - > lineEdit - > setFocus ( ) ;
2015-06-06 10:38:15 +02:00
else if ( ui - > tabWidget - > widget ( index ) ! = ui - > tab_peers )
clearSelectedNode ( ) ;
2012-05-09 17:12:05 +02:00
}
2012-05-09 22:07:00 +02:00
void RPCConsole : : on_openDebugLogfileButton_clicked ( )
{
GUIUtil : : openDebugLogfile ( ) ;
}
2012-05-14 18:17:12 +02:00
void RPCConsole : : scrollToEnd ( )
{
QScrollBar * scrollbar = ui - > messagesWidget - > verticalScrollBar ( ) ;
scrollbar - > setValue ( scrollbar - > maximum ( ) ) ;
}
2012-05-20 15:49:17 +02:00
2013-08-22 18:09:32 +02:00
void RPCConsole : : on_sldGraphRange_valueChanged ( int value )
{
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
setTrafficGraphRange ( static_cast < TrafficGraphData : : GraphRange > ( value ) ) ;
2013-08-22 18:09:32 +02:00
}
QString RPCConsole : : FormatBytes ( quint64 bytes )
{
if ( bytes < 1024 )
return QString ( tr ( " %1 B " ) ) . arg ( bytes ) ;
if ( bytes < 1024 * 1024 )
return QString ( tr ( " %1 KB " ) ) . arg ( bytes / 1024 ) ;
if ( bytes < 1024 * 1024 * 1024 )
return QString ( tr ( " %1 MB " ) ) . arg ( bytes / 1024 / 1024 ) ;
return QString ( tr ( " %1 GB " ) ) . arg ( bytes / 1024 / 1024 / 1024 ) ;
}
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
void RPCConsole : : setTrafficGraphRange ( TrafficGraphData : : GraphRange range )
2013-08-22 18:09:32 +02:00
{
Qt: bug fixes and enhancement to traffic graph widget (#1429)
* clear trafficgraph on clear button click
* set default sample height
set default sample height so after clearing traffic graph have some
scale
* reduce available traffic graph ranges, add optimized graph data storage
reduce available traffic graph ranges to 10
(5m,10m,15m,30m,1h,2h,3h,6h,12h,24h),
store graph data so range change is possible,
data storage contains only necessary data to create graphs for all
supported ranges
eg. for 10m range storage only half of 10m samples - the second half is
calculated from 5m range samples,
encapsulate all traffic graph related data into one class
* code formatting corrections
2017-05-28 15:49:34 +02:00
ui - > trafficGraph - > setGraphRangeMins ( range ) ;
ui - > lblGraphRange - > setText ( GUIUtil : : formatDurationStr ( TrafficGraphData : : RangeMinutes [ range ] * 60 ) ) ;
2013-08-22 18:09:32 +02:00
}
void RPCConsole : : updateTrafficStats ( quint64 totalBytesIn , quint64 totalBytesOut )
{
ui - > lblBytesIn - > setText ( FormatBytes ( totalBytesIn ) ) ;
ui - > lblBytesOut - > setText ( FormatBytes ( totalBytesOut ) ) ;
}
2015-01-16 10:55:24 +01:00
2014-05-23 19:09:59 +02:00
void RPCConsole : : peerSelected ( const QItemSelection & selected , const QItemSelection & deselected )
{
2014-06-03 14:42:20 +02:00
Q_UNUSED ( deselected ) ;
2015-06-26 14:55:52 +02:00
if ( ! clientModel | | ! clientModel - > getPeerTableModel ( ) | | selected . indexes ( ) . isEmpty ( ) )
2014-05-23 19:09:59 +02:00
return ;
const CNodeCombinedStats * stats = clientModel - > getPeerTableModel ( ) - > getNodeStats ( selected . indexes ( ) . first ( ) . row ( ) ) ;
if ( stats )
updateNodeDetail ( stats ) ;
}
2017-09-11 15:38:14 +02:00
void RPCConsole : : peerLayoutAboutToChange ( )
{
QModelIndexList selected = ui - > peerWidget - > selectionModel ( ) - > selectedIndexes ( ) ;
cachedNodeids . clear ( ) ;
for ( int i = 0 ; i < selected . size ( ) ; i + + )
{
const CNodeCombinedStats * stats = clientModel - > getPeerTableModel ( ) - > getNodeStats ( selected . at ( i ) . row ( ) ) ;
cachedNodeids . append ( stats - > nodeStats . nodeid ) ;
}
}
2014-05-23 19:09:59 +02:00
void RPCConsole : : peerLayoutChanged ( )
{
2015-06-26 14:55:52 +02:00
if ( ! clientModel | | ! clientModel - > getPeerTableModel ( ) )
2014-06-04 12:06:18 +02:00
return ;
2014-05-23 19:09:59 +02:00
const CNodeCombinedStats * stats = NULL ;
2014-06-04 12:06:18 +02:00
bool fUnselect = false ;
bool fReselect = false ;
2014-05-23 19:09:59 +02:00
2017-09-11 15:38:14 +02:00
if ( cachedNodeids . empty ( ) ) // no node selected yet
2014-05-23 19:09:59 +02:00
return ;
// find the currently selected row
2015-06-06 10:38:15 +02:00
int selectedRow = - 1 ;
2014-05-23 19:09:59 +02:00
QModelIndexList selectedModelIndex = ui - > peerWidget - > selectionModel ( ) - > selectedIndexes ( ) ;
2015-06-06 10:38:15 +02:00
if ( ! selectedModelIndex . isEmpty ( ) ) {
2014-05-23 19:09:59 +02:00
selectedRow = selectedModelIndex . first ( ) . row ( ) ;
2015-06-06 10:38:15 +02:00
}
2014-05-23 19:09:59 +02:00
// check if our detail node has a row in the table (it may not necessarily
// be at selectedRow since its position can change after a layout change)
2017-09-11 15:38:14 +02:00
int detailNodeRow = clientModel - > getPeerTableModel ( ) - > getRowByNodeId ( cachedNodeids . first ( ) ) ;
2014-05-23 19:09:59 +02:00
if ( detailNodeRow < 0 )
{
2015-08-09 01:17:27 +02:00
// detail node disappeared from table (node disconnected)
2014-05-23 19:09:59 +02:00
fUnselect = true ;
}
else
{
if ( detailNodeRow ! = selectedRow )
{
// detail node moved position
fUnselect = true ;
fReselect = true ;
}
// get fresh stats on the detail node.
stats = clientModel - > getPeerTableModel ( ) - > getNodeStats ( detailNodeRow ) ;
}
2015-06-06 10:38:15 +02:00
if ( fUnselect & & selectedRow > = 0 ) {
clearSelectedNode ( ) ;
2014-05-23 19:09:59 +02:00
}
if ( fReselect )
{
2017-09-11 15:38:14 +02:00
for ( int i = 0 ; i < cachedNodeids . size ( ) ; i + + )
{
ui - > peerWidget - > selectRow ( clientModel - > getPeerTableModel ( ) - > getRowByNodeId ( cachedNodeids . at ( i ) ) ) ;
}
2014-05-23 19:09:59 +02:00
}
if ( stats )
updateNodeDetail ( stats ) ;
}
2014-06-04 12:06:18 +02:00
void RPCConsole : : updateNodeDetail ( const CNodeCombinedStats * stats )
2014-05-23 19:09:59 +02:00
{
// update the detail ui with latest node information
2015-06-01 09:09:51 +02:00
QString peerAddrDetails ( QString : : fromStdString ( stats - > nodeStats . addrName ) + " " ) ;
peerAddrDetails + = tr ( " (node id: %1) " ) . arg ( QString : : number ( stats - > nodeStats . nodeid ) ) ;
2014-06-04 12:06:18 +02:00
if ( ! stats - > nodeStats . addrLocal . empty ( ) )
peerAddrDetails + = " <br /> " + tr ( " via %1 " ) . arg ( QString : : fromStdString ( stats - > nodeStats . addrLocal ) ) ;
ui - > peerHeading - > setText ( peerAddrDetails ) ;
ui - > peerServices - > setText ( GUIUtil : : formatServicesStr ( stats - > nodeStats . nServices ) ) ;
2017-08-24 01:38:29 +02:00
ui - > peerLastSend - > setText ( stats - > nodeStats . nLastSend ? GUIUtil : : formatDurationStr ( GetSystemTimeInSeconds ( ) - stats - > nodeStats . nLastSend ) : tr ( " never " ) ) ;
ui - > peerLastRecv - > setText ( stats - > nodeStats . nLastRecv ? GUIUtil : : formatDurationStr ( GetSystemTimeInSeconds ( ) - stats - > nodeStats . nLastRecv ) : tr ( " never " ) ) ;
2014-06-04 12:06:18 +02:00
ui - > peerBytesSent - > setText ( FormatBytes ( stats - > nodeStats . nSendBytes ) ) ;
ui - > peerBytesRecv - > setText ( FormatBytes ( stats - > nodeStats . nRecvBytes ) ) ;
2017-08-24 01:38:29 +02:00
ui - > peerConnTime - > setText ( GUIUtil : : formatDurationStr ( GetSystemTimeInSeconds ( ) - stats - > nodeStats . nTimeConnected ) ) ;
2014-06-04 12:06:18 +02:00
ui - > peerPingTime - > setText ( GUIUtil : : formatPingTime ( stats - > nodeStats . dPingTime ) ) ;
2015-06-01 09:09:51 +02:00
ui - > peerPingWait - > setText ( GUIUtil : : formatPingTime ( stats - > nodeStats . dPingWait ) ) ;
2017-09-09 09:04:02 +02:00
ui - > peerMinPing - > setText ( GUIUtil : : formatPingTime ( stats - > nodeStats . dMinPing ) ) ;
2014-12-15 11:07:55 +01:00
ui - > timeoffset - > setText ( GUIUtil : : formatTimeOffset ( stats - > nodeStats . nTimeOffset ) ) ;
2015-06-01 09:09:51 +02:00
ui - > peerVersion - > setText ( QString ( " %1 " ) . arg ( QString : : number ( stats - > nodeStats . nVersion ) ) ) ;
2014-06-04 12:06:18 +02:00
ui - > peerSubversion - > setText ( QString : : fromStdString ( stats - > nodeStats . cleanSubVer ) ) ;
ui - > peerDirection - > setText ( stats - > nodeStats . fInbound ? tr ( " Inbound " ) : tr ( " Outbound " ) ) ;
2015-06-01 09:09:51 +02:00
ui - > peerHeight - > setText ( QString ( " %1 " ) . arg ( QString : : number ( stats - > nodeStats . nStartingHeight ) ) ) ;
ui - > peerWhitelisted - > setText ( stats - > nodeStats . fWhitelisted ? tr ( " Yes " ) : tr ( " No " ) ) ;
2014-06-04 12:06:18 +02:00
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
if ( stats - > fNodeStateStatsAvailable ) {
// Ban score is init to 0
ui - > peerBanScore - > setText ( QString ( " %1 " ) . arg ( stats - > nodeStateStats . nMisbehavior ) ) ;
// Sync height is init to -1
if ( stats - > nodeStateStats . nSyncHeight > - 1 )
ui - > peerSyncHeight - > setText ( QString ( " %1 " ) . arg ( stats - > nodeStateStats . nSyncHeight ) ) ;
else
ui - > peerSyncHeight - > setText ( tr ( " Unknown " ) ) ;
2015-06-01 09:09:51 +02:00
// Common height is init to -1
if ( stats - > nodeStateStats . nCommonHeight > - 1 )
ui - > peerCommonHeight - > setText ( QString ( " %1 " ) . arg ( stats - > nodeStateStats . nCommonHeight ) ) ;
else
ui - > peerCommonHeight - > setText ( tr ( " Unknown " ) ) ;
2014-06-04 12:06:18 +02:00
}
2014-07-13 06:27:29 +02:00
2014-06-04 12:06:18 +02:00
ui - > detailWidget - > show ( ) ;
2014-07-13 06:27:29 +02:00
}
2014-05-23 19:09:59 +02:00
void RPCConsole : : resizeEvent ( QResizeEvent * event )
{
QWidget : : resizeEvent ( event ) ;
}
void RPCConsole : : showEvent ( QShowEvent * event )
{
QWidget : : showEvent ( event ) ;
2015-06-26 14:55:52 +02:00
if ( ! clientModel | | ! clientModel - > getPeerTableModel ( ) )
2014-06-04 12:06:18 +02:00
return ;
// start PeerTableModel auto refresh
clientModel - > getPeerTableModel ( ) - > startAutoRefresh ( ) ;
2014-05-23 19:09:59 +02:00
}
void RPCConsole : : hideEvent ( QHideEvent * event )
{
QWidget : : hideEvent ( event ) ;
2015-06-26 14:55:52 +02:00
if ( ! clientModel | | ! clientModel - > getPeerTableModel ( ) )
2014-07-13 06:27:29 +02:00
return ;
2014-05-23 19:09:59 +02:00
// stop PeerTableModel auto refresh
clientModel - > getPeerTableModel ( ) - > stopAutoRefresh ( ) ;
}
2015-04-11 06:14:18 +02:00
2015-06-20 20:55:21 +02:00
void RPCConsole : : showPeersTableContextMenu ( const QPoint & point )
2015-06-01 15:32:25 +02:00
{
QModelIndex index = ui - > peerWidget - > indexAt ( point ) ;
if ( index . isValid ( ) )
2015-06-20 20:55:21 +02:00
peersTableContextMenu - > exec ( QCursor : : pos ( ) ) ;
}
void RPCConsole : : showBanTableContextMenu ( const QPoint & point )
{
QModelIndex index = ui - > banlistWidget - > indexAt ( point ) ;
if ( index . isValid ( ) )
banTableContextMenu - > exec ( QCursor : : pos ( ) ) ;
2015-06-01 15:32:25 +02:00
}
void RPCConsole : : disconnectSelectedNode ( )
{
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
if ( ! g_connman )
return ;
2017-09-11 15:38:14 +02:00
// Get selected peer addresses
QList < QModelIndex > nodes = GUIUtil : : getEntryData ( ui - > peerWidget , PeerTableModel : : NetNodeId ) ;
for ( int i = 0 ; i < nodes . count ( ) ; i + + )
{
// Get currently selected peer address
2017-04-13 16:30:38 +02:00
NodeId id = nodes . at ( i ) . data ( ) . toLongLong ( ) ;
2017-09-11 15:38:14 +02:00
// Find the node, disconnect it and clear the selected node
if ( g_connman - > DisconnectNode ( id ) )
clearSelectedNode ( ) ;
}
2015-06-01 15:32:25 +02:00
}
2015-06-06 10:38:15 +02:00
2015-06-19 13:24:34 +02:00
void RPCConsole : : banSelectedNode ( int bantime )
{
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
if ( ! clientModel | | ! g_connman )
2015-06-26 10:23:51 +02:00
return ;
2017-09-11 15:38:14 +02:00
// Get selected peer addresses
QList < QModelIndex > nodes = GUIUtil : : getEntryData ( ui - > peerWidget , PeerTableModel : : NetNodeId ) ;
for ( int i = 0 ; i < nodes . count ( ) ; i + + )
{
// Get currently selected peer address
2017-04-13 16:30:38 +02:00
NodeId id = nodes . at ( i ) . data ( ) . toLongLong ( ) ;
2017-09-11 15:38:14 +02:00
// Get currently selected peer address
int detailNodeRow = clientModel - > getPeerTableModel ( ) - > getRowByNodeId ( id ) ;
if ( detailNodeRow < 0 )
return ;
// Find possible nodes, ban it and clear the selected node
const CNodeCombinedStats * stats = clientModel - > getPeerTableModel ( ) - > getNodeStats ( detailNodeRow ) ;
if ( stats ) {
g_connman - > Ban ( stats - > nodeStats . addr , BanReasonManuallyAdded , bantime ) ;
}
2017-09-09 09:04:02 +02:00
}
2017-09-11 15:38:14 +02:00
clearSelectedNode ( ) ;
clientModel - > getBanTableModel ( ) - > refresh ( ) ;
2015-06-19 13:24:34 +02:00
}
2015-06-20 20:55:21 +02:00
void RPCConsole : : unbanSelectedNode ( )
{
2015-06-26 10:23:51 +02:00
if ( ! clientModel )
return ;
2017-09-11 15:38:14 +02:00
// Get selected ban addresses
QList < QModelIndex > nodes = GUIUtil : : getEntryData ( ui - > banlistWidget , BanTableModel : : Address ) ;
for ( int i = 0 ; i < nodes . count ( ) ; i + + )
2015-06-20 20:55:21 +02:00
{
2017-09-11 15:38:14 +02:00
// Get currently selected ban address
QString strNode = nodes . at ( i ) . data ( ) . toString ( ) ;
CSubNet possibleSubnet ;
LookupSubNet ( strNode . toStdString ( ) . c_str ( ) , possibleSubnet ) ;
if ( possibleSubnet . IsValid ( ) & & g_connman )
{
g_connman - > Unban ( possibleSubnet ) ;
clientModel - > getBanTableModel ( ) - > refresh ( ) ;
}
2015-06-20 20:55:21 +02:00
}
}
2015-06-06 10:38:15 +02:00
void RPCConsole : : clearSelectedNode ( )
{
ui - > peerWidget - > selectionModel ( ) - > clearSelection ( ) ;
2017-09-11 15:38:14 +02:00
cachedNodeids . clear ( ) ;
2015-06-06 10:38:15 +02:00
ui - > detailWidget - > hide ( ) ;
ui - > peerHeading - > setText ( tr ( " Select a peer to view detailed information. " ) ) ;
}
2015-06-20 21:48:10 +02:00
void RPCConsole : : showOrHideBanTableIfRequired ( )
{
2015-06-21 10:44:48 +02:00
if ( ! clientModel )
return ;
2015-06-23 21:10:42 +02:00
2015-06-20 21:48:10 +02:00
bool visible = clientModel - > getBanTableModel ( ) - > shouldShow ( ) ;
ui - > banlistWidget - > setVisible ( visible ) ;
ui - > banHeading - > setVisible ( visible ) ;
2015-10-22 13:33:58 +02:00
}
2015-11-12 12:59:26 +01:00
void RPCConsole : : setTabFocus ( enum TabTypes tabType )
{
ui - > tabWidget - > setCurrentIndex ( tabType ) ;
}