Skip to content

Commit 38a85e6

Browse files
Rework feature activations alerting integration
* Activations are no longer considered alerts (but an alert is still triggered if the client does not support the feature) * Completed activations are now tracked as well as pending activations * Details on pending and completed activations available via omni_getactivations call * Stale pending activations are removed if an activation is re-issued
1 parent c09c0ed commit 38a85e6

File tree

9 files changed

+199
-40
lines changed

9 files changed

+199
-40
lines changed

src/omnicore/notifications.cpp

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,33 +144,11 @@ bool CheckExpiredAlerts(unsigned int curBlock, uint64_t curTime)
144144
for (std::vector<AlertData>::iterator it = currentOmniAlerts.begin(); it != currentOmniAlerts.end(); ) {
145145
AlertData alert = *it;
146146
switch (alert.alert_type) {
147-
case ALERT_FEATURE_UNSUPPORTED:
148-
if (curBlock >= alert.alert_expiry) {
149-
std::string msgText = strprintf("Shutting down due to alert: %s", alert.alert_message);
150-
PrintToLog(msgText);
151-
PrintToConsole(msgText);
152-
if (!GetBoolArg("-overrideforcedshutdown", false)) {
153-
AbortNode(msgText, msgText);
154-
}
155-
it = currentOmniAlerts.erase(it);
156-
} else {
157-
it++;
158-
}
159-
break;
160147
case ALERT_BLOCK_EXPIRY:
161148
if (curBlock >= alert.alert_expiry) {
162149
PrintToLog("Expiring alert (from %s: type:%d expiry:%d message:%s)\n", alert.alert_sender,
163150
alert.alert_type, alert.alert_expiry, alert.alert_message);
164151
it = currentOmniAlerts.erase(it);
165-
166-
// if expiring a feature activation because it's gone live, add another notification
167-
// to say we're now live and expire it in 1024 blocks.
168-
size_t replacePosition = alert.alert_message.find("') will go live at block ");
169-
if (replacePosition != std::string::npos) {
170-
std::string newAlertMessage = alert.alert_message.substr(0, replacePosition) + "') is now live.";
171-
AddAlert("omnicore", 1, alert.alert_expiry + 1024, newAlertMessage);
172-
}
173-
174152
uiInterface.OmniStateChanged();
175153
} else {
176154
it++;

src/omnicore/omnicore.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2678,7 +2678,7 @@ int mastercore_init()
26782678
}
26792679

26802680
// load feature activation messages from txlistdb and process them accordingly
2681-
p_txlistdb->LoadActivations();
2681+
p_txlistdb->LoadActivations(nWaterlineBlock);
26822682

26832683
// load all alerts from levelDB (and immediately expire old ones)
26842684
p_txlistdb->LoadAlerts(nWaterlineBlock);
@@ -2888,7 +2888,7 @@ int mastercore::ClassAgnosticWalletTXBuilder(const std::string& senderAddress, c
28882888
#endif
28892889
}
28902890

2891-
void CMPTxList::LoadActivations()
2891+
void CMPTxList::LoadActivations(int blockHeight)
28922892
{
28932893
if (!pdb) return;
28942894

@@ -2945,6 +2945,7 @@ void CMPTxList::LoadActivations()
29452945
}
29462946
}
29472947
delete it;
2948+
CheckLiveActivations(blockHeight);
29482949
}
29492950

29502951
void CMPTxList::LoadAlerts(int blockHeight)
@@ -4066,6 +4067,9 @@ int mastercore_handler_block_begin(int nBlockPrev, CBlockIndex const * pBlockInd
40664067
}
40674068
}
40684069

4070+
// handle any features that go live with this block
4071+
CheckLiveActivations(pBlockIndex->nHeight);
4072+
40694073
eraseExpiredCrowdsale(pBlockIndex);
40704074

40714075
return 0;

src/omnicore/omnicore.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class CMPTxList : public CDBBase
245245
bool getTX(const uint256 &txid, string &value);
246246

247247
void LoadAlerts(int blockHeight);
248-
void LoadActivations();
248+
void LoadActivations(int blockHeight);
249249

250250
void printStats();
251251
void printAll();

src/omnicore/rpc.cpp

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1487,13 +1487,77 @@ Value omni_getinfo(const Array& params, bool fHelp)
14871487
alertResponse.push_back(Pair("alerttype", alertTypeStr));
14881488
alertResponse.push_back(Pair("alertexpiry", FormatIndivisibleMP(alert.alert_expiry)));
14891489
alertResponse.push_back(Pair("alertmessage", alert.alert_message));
1490-
alerts.push_back(alertResponse);
1490+
alerts.push_back(alertResponse);
14911491
}
14921492
infoResponse.push_back(Pair("alerts", alerts));
14931493

14941494
return infoResponse;
14951495
}
14961496

1497+
Value omni_getactivations(const Array& params, bool fHelp)
1498+
{
1499+
if (fHelp || params.size() != 0)
1500+
throw runtime_error(
1501+
"omni_getactivations\n"
1502+
"Returns pending and completed feature activations.\n"
1503+
"\nResult:\n"
1504+
"{\n"
1505+
" \"pendingactivations\": [ (array of JSON objects) a list of pending feature activations\n"
1506+
" {\n"
1507+
" \"featureid\" : n (number) the id of the feature\n"
1508+
" \"featurename\" : \"xxxxxxxx\" (string) the name of the feature\n"
1509+
" \"activationblock\" : n (number) the block the feature will be activated\n"
1510+
" \"minimumversion\" : n (number) the minimum client version needed to support this feature\n"
1511+
" },\n"
1512+
" ...\n"
1513+
" ]\n"
1514+
" \"completedactivations\": [ (array of JSON objects) a list of completed feature activations\n"
1515+
" {\n"
1516+
" \"featureid\" : n (number) the id of the feature\n"
1517+
" \"featurename\" : \"xxxxxxxx\" (string) the name of the feature\n"
1518+
" \"activationblock\" : n (number) the block the feature will be activated\n"
1519+
" \"minimumversion\" : n (number) the minimum client version needed to support this feature\n"
1520+
" },\n"
1521+
" ...\n"
1522+
" ]\n"
1523+
"}\n"
1524+
"\nExamples:\n"
1525+
+ HelpExampleCli("omni_getactivations", "")
1526+
+ HelpExampleRpc("omni_getactivations", "")
1527+
);
1528+
1529+
Object response;
1530+
1531+
Array arrayPendingActivations;
1532+
std::vector<FeatureActivation> PendingActivations = GetPendingActivations();
1533+
for (std::vector<FeatureActivation>::iterator it = PendingActivations.begin(); it != PendingActivations.end(); ++it) {
1534+
Object actObj;
1535+
FeatureActivation pendingAct = *it;
1536+
actObj.push_back(Pair("featureid", pendingAct.featureId));
1537+
actObj.push_back(Pair("featurename", pendingAct.featureName));
1538+
actObj.push_back(Pair("activationblock", FormatIndivisibleMP(pendingAct.activationBlock)));
1539+
actObj.push_back(Pair("minimumversion", (uint64_t)pendingAct.minClientVersion));
1540+
arrayPendingActivations.push_back(actObj);
1541+
}
1542+
1543+
Array arrayCompletedActivations;
1544+
std::vector<FeatureActivation> CompletedActivations = GetCompletedActivations();
1545+
for (std::vector<FeatureActivation>::iterator it = CompletedActivations.begin(); it != CompletedActivations.end(); ++it) {
1546+
Object actObj;
1547+
FeatureActivation completedAct = *it;
1548+
actObj.push_back(Pair("featureid", completedAct.featureId));
1549+
actObj.push_back(Pair("featurename", completedAct.featureName));
1550+
actObj.push_back(Pair("activationblock", FormatIndivisibleMP(completedAct.activationBlock)));
1551+
actObj.push_back(Pair("minimumversion", (uint64_t)completedAct.minClientVersion));
1552+
arrayCompletedActivations.push_back(actObj);
1553+
}
1554+
1555+
response.push_back(Pair("pendingactivations", arrayPendingActivations));
1556+
response.push_back(Pair("completedactivations", arrayCompletedActivations));
1557+
1558+
return response;
1559+
}
1560+
14971561
Value omni_getsto(const Array& params, bool fHelp)
14981562
{
14991563
if (fHelp || params.size() < 1 || params.size() > 2)

src/omnicore/rules.cpp

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
#include "omnicore/utilsbitcoin.h"
1313
#include "omnicore/version.h"
1414

15+
#include "alert.h"
1516
#include "chainparams.h"
17+
#include "main.h"
1618
#include "script/standard.h"
1719
#include "uint256.h"
20+
#include "ui_interface.h"
1821

1922
#include <openssl/sha.h>
2023

@@ -28,7 +31,12 @@ namespace mastercore
2831
/**
2932
* Pending activations
3033
*/
31-
std::vector<PendingActivation> PendingActivations;
34+
std::vector<FeatureActivation> PendingActivations;
35+
36+
/**
37+
* Completed activations
38+
*/
39+
std::vector<FeatureActivation> CompletedActivations;
3240

3341
/**
3442
* Returns a mapping of transaction types, and the blocks at which they are enabled.
@@ -318,18 +326,90 @@ bool IsAllowedOutputType(int whichType, int nBlock)
318326
}
319327

320328
/**
321-
* Adds a pending activation to the PendingActivations vector.
329+
* Adds a feature activation to the PendingActivations vector.
322330
*
323331
*/
324332
void AddPendingActivation(uint16_t featureId, int activationBlock, uint32_t minClientVersion, const std::string& featureName)
325333
{
326-
PendingActivation pa;
327-
pa.featureId = featureId;
328-
pa.activationBlock = activationBlock;
329-
pa.minClientVersion = minClientVersion;
330-
pa.featureName = featureName;
334+
FeatureActivation featureActivation;
331335

332-
PendingActivations.push_back(pa);
336+
featureActivation.featureId = featureId;
337+
featureActivation.featureName = featureName;
338+
featureActivation.activationBlock = activationBlock;
339+
featureActivation.minClientVersion = minClientVersion;
340+
341+
PendingActivations.push_back(featureActivation);
342+
}
343+
344+
/**
345+
* Deletes a pending activation from the PendingActivations vector. Deletion is not supported on the CompletedActivations vector.
346+
*
347+
*/
348+
void DeletePendingActivation(uint16_t featureId)
349+
{
350+
for (std::vector<FeatureActivation>::iterator it = PendingActivations.begin(); it != PendingActivations.end(); ) {
351+
if ((*it).featureId == featureId) {
352+
it = PendingActivations.erase(it);
353+
} else {
354+
it++;
355+
}
356+
}
357+
}
358+
359+
/**
360+
* Checks if any activations went live in the block
361+
*
362+
*/
363+
void CheckLiveActivations(int blockHeight)
364+
{
365+
std::vector<FeatureActivation> PendingActivations = GetPendingActivations();
366+
for (std::vector<FeatureActivation>::iterator it = PendingActivations.begin(); it != PendingActivations.end(); ++it) {
367+
if ((*it).activationBlock > blockHeight) continue;
368+
FeatureActivation LiveActivation = *it;
369+
if (OMNICORE_VERSION < LiveActivation.minClientVersion) {
370+
std::string msgText = strprintf("Shutting down due to unsupported feature activation (%d: %s)", LiveActivation.featureId, LiveActivation.featureName);
371+
PrintToLog(msgText);
372+
PrintToConsole(msgText);
373+
if (!GetBoolArg("-overrideforcedshutdown", false)) {
374+
AbortNode(msgText, msgText);
375+
}
376+
}
377+
PendingActivationCompleted(LiveActivation.featureId);
378+
uiInterface.OmniStateChanged();
379+
}
380+
}
381+
382+
/**
383+
* Moves an activation from PendingActivations to CompletedActivations when it is activated
384+
*
385+
*/
386+
void PendingActivationCompleted(uint16_t featureId)
387+
{
388+
for (std::vector<FeatureActivation>::iterator it = PendingActivations.begin(); it != PendingActivations.end(); ) {
389+
if ((*it).featureId == featureId) {
390+
FeatureActivation completedActivation = *it;
391+
CompletedActivations.push_back(completedActivation);
392+
it = PendingActivations.erase(it);
393+
} else {
394+
it++;
395+
}
396+
}
397+
}
398+
399+
/**
400+
* Returns the vector of pending activations.
401+
*/
402+
std::vector<FeatureActivation> GetPendingActivations()
403+
{
404+
return PendingActivations;
405+
}
406+
407+
/**
408+
* Returns the vector of completed activations.
409+
*/
410+
std::vector<FeatureActivation> GetCompletedActivations()
411+
{
412+
return CompletedActivations;
333413
}
334414

335415
/**
@@ -428,13 +508,14 @@ bool ActivateFeature(uint16_t featureId, int activationBlock, uint32_t minClient
428508
break;
429509
}
430510
PrintToLog("Feature activation of ID %d processed. %s will be enabled at block %d.\n", featureId, featureName, activationBlock);
511+
DeletePendingActivation(featureId); // if this feature id was previously scheduled for activation, delete the stale pending object
431512
AddPendingActivation(featureId, activationBlock, minClientVersion, featureName);
432-
AddAlert("omnicore", ALERT_BLOCK_EXPIRY, activationBlock, strprintf("Feature %d ('%s') will go live at block %d", featureId, featureName, activationBlock));
433513
if (!supported) {
434514
PrintToLog("WARNING!!! AS OF BLOCK %d THIS CLIENT WILL BE OUT OF CONSENSUS AND WILL AUTOMATICALLY SHUTDOWN.\n", activationBlock);
435-
AddAlert("omnicore", ALERT_FEATURE_UNSUPPORTED, activationBlock,
436-
strprintf("Your client must be updated and will shutdown at block %d "
437-
"(unsupported feature %d ('%s') activated)\n", activationBlock, featureId, featureName));
515+
std::string alertText = strprintf("Your client must be updated and will shutdown at block %d (unsupported feature %d ('%s') activated)\n",
516+
activationBlock, featureId, featureName);
517+
AddAlert("omnicore", ALERT_BLOCK_EXPIRY, activationBlock, alertText);
518+
CAlert::Notify(alertText, true);
438519
}
439520
return true;
440521
}

src/omnicore/rules.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ const uint16_t FEATURE_GRANTEFFECTS = 4;
2525
//! Feature identifier to disable DEx "over-offers" and to switch to plain integer math
2626
const uint16_t FEATURE_DEXMATH = 5;
2727

28-
/** A structure to represent a pending activation
28+
/** A structure to represent a feature activation
2929
*/
30-
struct PendingActivation
30+
struct FeatureActivation
3131
{
3232
uint16_t featureId;
3333
int activationBlock;
@@ -175,6 +175,16 @@ CConsensusParams& MutableConsensusParams();
175175

176176
/** Determines whether the sender is an authorized source for Omni Core activations. */
177177
bool CheckActivationAuthorization(const std::string& sender);
178+
/** Returns the vector of pending activations */
179+
std::vector<FeatureActivation> GetPendingActivations();
180+
/** Returns the vector of completed activations */
181+
std::vector<FeatureActivation> GetCompletedActivations();
182+
/** Moves a feature activation from pending vector to completed vector */
183+
void PendingActivationCompleted(uint16_t featureId);
184+
/** Checks if any activations went live in the block */
185+
void CheckLiveActivations(int blockHeight);
186+
/** Deletes a pending activation */
187+
void DeletePendingActivation(uint16_t featureId);
178188
/** Activates a feature at a specific block height. */
179189
bool ActivateFeature(uint16_t featureId, int activationBlock, uint32_t minClientVersion, int transactionBlock);
180190
/** Checks, whether a feature is activated at the given block. */

src/qt/overviewpage.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "omnicore/notifications.h"
1818
#include "omnicore/omnicore.h"
19+
#include "omnicore/rules.h"
1920
#include "omnicore/sp.h"
2021
#include "omnicore/tx.h"
2122
#include "omnicore/pending.h"
@@ -622,12 +623,31 @@ void OverviewPage::updateDisplayUnit()
622623
void OverviewPage::updateAlerts()
623624
{
624625
QString alertString = QString::fromStdString(GetWarnings("statusbar")); // get current bitcoin alert/warning directly
626+
627+
// get alert messages
625628
std::vector<std::string> omniAlerts = GetOmniCoreAlertMessages();
626629
for (std::vector<std::string>::iterator it = omniAlerts.begin(); it != omniAlerts.end(); it++) {
627630
if (!alertString.isEmpty()) alertString += "\n";
628631
alertString += QString::fromStdString(*it);
629632
}
630633

634+
// get activations
635+
std::vector<FeatureActivation> PendingActivations = GetPendingActivations();
636+
for (std::vector<FeatureActivation>::iterator it = PendingActivations.begin(); it != PendingActivations.end(); ++it) {
637+
if (!alertString.isEmpty()) alertString += "\n";
638+
FeatureActivation pendingAct = *it;
639+
alertString += QString::fromStdString(strprintf("Feature %d ('%s') will go live at block %d",
640+
pendingAct.featureId, pendingAct.featureName, pendingAct.activationBlock));
641+
}
642+
int currentHeight = GetHeight();
643+
std::vector<FeatureActivation> CompletedActivations = GetCompletedActivations();
644+
for (std::vector<FeatureActivation>::iterator it = CompletedActivations.begin(); it != CompletedActivations.end(); ++it) {
645+
if (currentHeight > (*it).activationBlock+1024) continue; // don't include after live+1024 blocks
646+
if (!alertString.isEmpty()) alertString += "\n";
647+
FeatureActivation completedAct = *it;
648+
alertString += QString::fromStdString(strprintf("Feature %d ('%s') is now live.", completedAct.featureId, completedAct.featureName));
649+
}
650+
631651
if (!alertString.isEmpty()) {
632652
this->ui->labelAlerts->setVisible(true);
633653
this->ui->labelAlerts->setText(alertString);

src/rpcserver.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ static const CRPCCommand vRPCCommands[] =
358358
/* Omni Core data retrieval calls */
359359
/* CATEGORY NAME ACTOR (FUNCTION) OKSAFEMODE THREADSAFE REQWALLET */
360360
{ "omni layer (data retrieval)", "omni_getinfo", &omni_getinfo, true, true, false },
361+
{ "omni layer (data retrieval)", "omni_getactivations", &omni_getactivations, true, true, false },
361362
{ "omni layer (data retrieval)", "omni_getallbalancesforid", &omni_getallbalancesforid, false, true, false },
362363
{ "omni layer (data retrieval)", "omni_getbalance", &omni_getbalance, false, true, false },
363364
{ "omni layer (data retrieval)", "omni_gettransaction", &omni_gettransaction, false, true, false },

src/rpcserver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool
228228

229229
/* Omni Core data retrieval calls */
230230
extern json_spirit::Value omni_getinfo(const json_spirit::Array& params, bool fHelp);
231+
extern json_spirit::Value omni_getactivations(const json_spirit::Array& params, bool fHelp);
231232
extern json_spirit::Value omni_getallbalancesforid(const json_spirit::Array& params, bool fHelp);
232233
extern json_spirit::Value omni_getbalance(const json_spirit::Array& params, bool fHelp);
233234
extern json_spirit::Value omni_gettransaction(const json_spirit::Array& params, bool fHelp);

0 commit comments

Comments
 (0)