Skip to content

Commit a56361d

Browse files
committed
Merge #220: The Block Clock
6701ad2 qml: introduce the BlockClock (johnny9) 60bd8cb qml: introduce ChainModel (johnny9) eb945ac qml: add sync time related properties to NodeModel (johnny9) 8db7f0f qml: add additional properties in Header (johnny9) 094a2c4 qml: add ability to pause NodeModel (johnny9) 1fce853 Add getBlockTime interface method in src/interfaces/chain.h (shaavan) Pull request description: This is a continuation of #148. The goal of this PR is to get the working features from #148 merged in using a QQuickPainterItem implementation of the dial instead of the javascript canvas. Connection state as well as the animating icon will be implemented in a later PR. Refactoring and clean up from the removal of the Canvas code still remains. [![Windows](https://img.shields.io/badge/OS-Windows-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/win64/insecure_win_gui.zip?branch=pull/220) [![Intel macOS](https://img.shields.io/badge/OS-Intel%20macOS-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/macos/insecure_mac_gui.zip?branch=pull/220) [![Apple Silicon macOS](https://img.shields.io/badge/OS-Apple%20Silicon%20macOS-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/macos_arm64/insecure_mac_arm64_gui.zip?branch=pull/220) [![ARM64 Android](https://img.shields.io/badge/OS-Android-green)](https://api.cirrus-ci.com/v1/artifact/github/bitcoin-core/gui-qml/android/insecure_android_apk.zip?branch=pull/220) ACKs for top commit: jarolrod: ACK 6701ad2 Tree-SHA512: 43b99d1fd69b67b285e91e05d3864c7044917cd6feae97b4c226f3a7b499ca24f6e786575dbc700461b1f6c58c0273746e4ea5834c554fa4dc916868199698df
2 parents d62a49f + 6701ad2 commit a56361d

17 files changed

+653
-25
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ share/qt/Info.plist
4646

4747
src/qt/*.moc
4848
src/qt/moc_*.cpp
49+
src/qml/components/moc_*.cpp
4950
src/qt/forms/ui_*.h
5051

5152
src/qt/test/moc*.cpp

src/Makefile.qt.include

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ QT_FORMS_UI = \
3535
qt/forms/transactiondescdialog.ui
3636

3737
QT_MOC_CPP = \
38+
qml/components/moc_blockclockdial.cpp \
3839
qml/moc_appmode.cpp \
40+
qml/moc_chainmodel.cpp \
3941
qml/moc_nodemodel.cpp \
4042
qml/moc_options_model.cpp \
4143
qt/moc_addressbookpage.cpp \
@@ -111,6 +113,8 @@ QT_QRC_LOCALE = qt/bitcoin_locale.qrc
111113
BITCOIN_QT_H = \
112114
qml/appmode.h \
113115
qml/bitcoin.h \
116+
qml/chainmodel.h \
117+
qml/components/blockclockdial.h \
114118
qml/imageprovider.h \
115119
qml/nodemodel.h \
116120
qml/options_model.h \
@@ -291,6 +295,8 @@ BITCOIN_QT_WALLET_CPP = \
291295

292296
BITCOIN_QML_BASE_CPP = \
293297
qml/bitcoin.cpp \
298+
qml/chainmodel.cpp \
299+
qml/components/blockclockdial.cpp \
294300
qml/imageprovider.cpp \
295301
qml/nodemodel.cpp \
296302
qml/options_model.cpp \
@@ -322,6 +328,7 @@ QML_QRC_CPP = qml/qrc_bitcoin.cpp
322328
QML_QRC = qml/bitcoin_qml.qrc
323329
QML_RES_QML = \
324330
qml/components/AboutOptions.qml \
331+
qml/components/BlockClock.qml \
325332
qml/components/BlockCounter.qml \
326333
qml/components/ConnectionOptions.qml \
327334
qml/components/ConnectionSettings.qml \

src/interfaces/chain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ class Chain
128128
//! Get block hash. Height must be valid or this function will abort.
129129
virtual uint256 getBlockHash(int height) = 0;
130130

131+
//! Get block time, Height must be valid or this function will abort.
132+
virtual int64_t getBlockTime(int height) = 0;
133+
131134
//! Check that the block is available on disk (i.e. has not been
132135
//! pruned), and contains transactions.
133136
virtual bool haveBlockOnDisk(int height) = 0;

src/node/interfaces.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,11 @@ class ChainImpl : public Chain
514514
LOCK(::cs_main);
515515
return Assert(chainman().ActiveChain()[height])->GetBlockHash();
516516
}
517+
int64_t getBlockTime(int height) override
518+
{
519+
LOCK(::cs_main);
520+
return Assert(chainman().ActiveChain()[height])->GetBlockTime();
521+
}
517522
bool haveBlockOnDisk(int height) override
518523
{
519524
LOCK(::cs_main);

src/qml/bitcoin.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@
66

77
#include <chainparams.h>
88
#include <init.h>
9+
#include <interfaces/chain.h>
910
#include <interfaces/init.h>
1011
#include <interfaces/node.h>
1112
#include <logging.h>
1213
#include <node/interface_ui.h>
1314
#include <noui.h>
1415
#include <qml/appmode.h>
16+
#include <qml/chainmodel.h>
17+
#include <qml/components/blockclockdial.h>
1518
#include <qml/imageprovider.h>
1619
#include <qml/nodemodel.h>
1720
#include <qml/options_model.h>
@@ -155,6 +158,7 @@ int QmlGuiMain(int argc, char* argv[])
155158
GUIUtil::LogQtInfo();
156159

157160
std::unique_ptr<interfaces::Node> node = init->makeNode();
161+
std::unique_ptr<interfaces::Chain> chain = init->makeChain();
158162
if (!node->baseInitialize()) {
159163
// A dialog with detailed error will have been shown by InitError().
160164
return EXIT_FAILURE;
@@ -170,6 +174,11 @@ int QmlGuiMain(int argc, char* argv[])
170174
QObject::connect(&init_executor, &InitExecutor::shutdownResult, qGuiApp, &QGuiApplication::quit, Qt::QueuedConnection);
171175
// QObject::connect(&init_executor, &InitExecutor::runawayException, &node_model, &NodeModel::handleRunawayException);
172176

177+
ChainModel chain_model{*chain};
178+
179+
QObject::connect(&node_model, &NodeModel::setTimeRatioList, &chain_model, &ChainModel::setTimeRatioList);
180+
QObject::connect(&node_model, &NodeModel::setTimeRatioListInitial, &chain_model, &ChainModel::setTimeRatioListInitial);
181+
173182
qGuiApp->setQuitOnLastWindowClosed(false);
174183
QObject::connect(qGuiApp, &QGuiApplication::lastWindowClosed, [&] {
175184
node->startShutdown();
@@ -185,6 +194,7 @@ int QmlGuiMain(int argc, char* argv[])
185194
engine.addImageProvider(QStringLiteral("images"), new ImageProvider{network_style.data()});
186195

187196
engine.rootContext()->setContextProperty("nodeModel", &node_model);
197+
engine.rootContext()->setContextProperty("chainModel", &chain_model);
188198

189199
OptionsQmlModel options_model{*node};
190200
engine.rootContext()->setContextProperty("optionsModel", &options_model);
@@ -196,6 +206,7 @@ int QmlGuiMain(int argc, char* argv[])
196206
#endif // __ANDROID__
197207

198208
qmlRegisterSingletonInstance<AppMode>("org.bitcoincore.qt", 1, 0, "AppMode", &app_mode);
209+
qmlRegisterType<BlockClockDial>("org.bitcoincore.qt", 1, 0, "BlockClockDial");
199210

200211
engine.load(QUrl(QStringLiteral("qrc:///qml/pages/main.qml")));
201212
if (engine.rootObjects().isEmpty()) {

src/qml/bitcoin_qml.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<!DOCTYPE RCC><RCC version="1.0">
22
<qresource prefix="/qml">
33
<file>components/AboutOptions.qml</file>
4+
<file>components/BlockClock.qml</file>
45
<file>components/BlockCounter.qml</file>
56
<file>components/ConnectionOptions.qml</file>
67
<file>components/ConnectionSettings.qml</file>

src/qml/chainmodel.cpp

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qml/chainmodel.h>
6+
7+
#include <QDateTime>
8+
#include <QThread>
9+
#include <QTime>
10+
#include <interfaces/chain.h>
11+
12+
ChainModel::ChainModel(interfaces::Chain& chain)
13+
: m_chain{chain}
14+
{
15+
QTimer* timer = new QTimer();
16+
connect(timer, &QTimer::timeout, this, &ChainModel::setCurrentTimeRatio);
17+
timer->start(1000);
18+
19+
QThread* timer_thread = new QThread;
20+
timer->moveToThread(timer_thread);
21+
timer_thread->start();
22+
}
23+
24+
void ChainModel::setTimeRatioList(int new_time)
25+
{
26+
if (m_time_ratio_list.isEmpty()) {
27+
setTimeRatioListInitial();
28+
}
29+
int time_at_meridian = timestampAtMeridian();
30+
31+
if (new_time < time_at_meridian) {
32+
return;
33+
}
34+
m_time_ratio_list.push_back(double(new_time - time_at_meridian) / SECS_IN_12_HOURS);
35+
36+
Q_EMIT timeRatioListChanged();
37+
}
38+
39+
int ChainModel::timestampAtMeridian()
40+
{
41+
int secs_since_meridian = (QTime::currentTime().msecsSinceStartOfDay() / 1000) % SECS_IN_12_HOURS;
42+
int current_timestamp = QDateTime::currentSecsSinceEpoch();
43+
44+
return current_timestamp - secs_since_meridian;
45+
}
46+
47+
void ChainModel::setTimeRatioListInitial()
48+
{
49+
int time_at_meridian = timestampAtMeridian();
50+
m_time_ratio_list.clear();
51+
/* m_time_ratio_list[0] = current_time_ratio
52+
* m_time_ratio_list[1] = 0
53+
* These two positions remain fixed for these
54+
* values in m_time_ratio_list */
55+
m_time_ratio_list.push_back(double(QDateTime::currentSecsSinceEpoch() - time_at_meridian) / SECS_IN_12_HOURS);
56+
m_time_ratio_list.push_back(0);
57+
58+
int first_block_height;
59+
int active_chain_height = m_chain.getHeight().value();
60+
bool success = m_chain.findFirstBlockWithTimeAndHeight(/*min_time=*/time_at_meridian, /*min_height=*/0, interfaces::FoundBlock().height(first_block_height));
61+
62+
if (!success) {
63+
Q_EMIT timeRatioListChanged();
64+
return;
65+
}
66+
67+
for (int height = first_block_height; height < active_chain_height + 1; height++) {
68+
m_time_ratio_list.push_back(double(m_chain.getBlockTime(height) - time_at_meridian) / SECS_IN_12_HOURS);
69+
}
70+
71+
Q_EMIT timeRatioListChanged();
72+
}
73+
74+
void ChainModel::setCurrentTimeRatio()
75+
{
76+
int secs_since_meridian = (QTime::currentTime().msecsSinceStartOfDay() / 1000) % SECS_IN_12_HOURS;
77+
double current_time_ratio = double(secs_since_meridian) / SECS_IN_12_HOURS;
78+
79+
if (current_time_ratio < m_time_ratio_list[0].toDouble()) { // That means time has crossed a meridian
80+
m_time_ratio_list.clear();
81+
}
82+
83+
if (m_time_ratio_list.isEmpty()) {
84+
m_time_ratio_list.push_back(current_time_ratio);
85+
m_time_ratio_list.push_back(0);
86+
} else {
87+
m_time_ratio_list[0] = current_time_ratio;
88+
}
89+
90+
Q_EMIT timeRatioListChanged();
91+
}

src/qml/chainmodel.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2022 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_QML_CHAINMODEL_H
6+
#define BITCOIN_QML_CHAINMODEL_H
7+
8+
#include <interfaces/chain.h>
9+
10+
#include <QObject>
11+
#include <QTimer>
12+
#include <QVariant>
13+
14+
namespace interfaces {
15+
class FoundBlock;
16+
class Chain;
17+
} // namespace interfaces
18+
19+
static const int SECS_IN_12_HOURS = 43200;
20+
21+
class ChainModel : public QObject
22+
{
23+
Q_OBJECT
24+
Q_PROPERTY(QVariantList timeRatioList READ timeRatioList NOTIFY timeRatioListChanged)
25+
26+
public:
27+
explicit ChainModel(interfaces::Chain& chain);
28+
29+
QVariantList timeRatioList() const { return m_time_ratio_list; };
30+
31+
int timestampAtMeridian();
32+
33+
void setCurrentTimeRatio();
34+
35+
public Q_SLOTS:
36+
void setTimeRatioList(int new_time);
37+
void setTimeRatioListInitial();
38+
39+
Q_SIGNALS:
40+
void timeRatioListChanged();
41+
42+
private:
43+
/* time_ratio: Ratio between the time at which an event
44+
* happened and 12 hours. So, for example, if a block is
45+
* found at 4 am or pm, the time_ratio would be 0.3.
46+
* The m_time_ratio_list stores the time ratio value for
47+
* the current_time and the time at which the blocks in
48+
* the last 12 hours were mined. */
49+
QVariantList m_time_ratio_list{0.0};
50+
51+
interfaces::Chain& m_chain;
52+
};
53+
54+
#endif // BITCOIN_QML_CHAINMODEL_H

0 commit comments

Comments
 (0)