1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#include "addrman.h"
#include "protocol.h"
#include "activesystemnode.h"
#include "systemnodeman.h"
#include "systemnode.h"
#include "spork.h"
CActiveSystemnode activeSystemnode;
//
// Bootup the Systemnode, look for a 10000 CRW input and register on the network
//
void CActiveSystemnode::ManageStatus()
{
std::string errorMessage;
if(!fSystemNode) return;
if (fDebug) LogPrintf("CActiveSystemnode::ManageStatus() - Begin\n");
//need correct blocks to send ping
if(Params().NetworkID() != CBaseChainParams::REGTEST && !systemnodeSync.IsBlockchainSynced()) {
status = ACTIVE_SYSTEMNODE_SYNC_IN_PROCESS;
LogPrintf("CActiveSystemnode::ManageStatus() - %s\n", GetStatus());
return;
}
if(status == ACTIVE_SYSTEMNODE_SYNC_IN_PROCESS) status = ACTIVE_SYSTEMNODE_INITIAL;
if(status == ACTIVE_SYSTEMNODE_INITIAL) {
CSystemnode *psn;
psn = snodeman.Find(pubKeySystemnode);
if(psn != NULL) {
psn->Check();
if(psn->IsEnabled() && psn->protocolVersion == PROTOCOL_VERSION) {
EnableHotColdSystemNode(psn->vin, psn->addr);
if (!psn->vchSignover.empty()) {
if (psn->pubkey.Verify(pubKeySystemnode.GetHash(), psn->vchSignover)) {
LogPrintf("%s: Verified pubkey2 signover for staking\n", __func__);
activeSystemnode.vchSigSignover = psn->vchSignover;
} else {
LogPrintf("%s: Failed to verify pubkey on signover!\n", __func__);
}
} else {
LogPrintf("%s: NOT SIGNOVER!\n", __func__);
}
}
}
}
if(status != ACTIVE_SYSTEMNODE_STARTED) {
// Set defaults
status = ACTIVE_SYSTEMNODE_NOT_CAPABLE;
notCapableReason = "";
if(pwalletMain->IsLocked()){
notCapableReason = "Wallet is locked.";
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
if(pwalletMain->GetBalance() == 0){
notCapableReason = "Hot node, waiting for remote activation.";
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
if(strSystemNodeAddr.empty()) {
if(!GetLocal(service)) {
notCapableReason = "Can't detect external address. Please use the systemnodeaddr configuration option.";
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
} else {
service = CService(strSystemNodeAddr);
}
if(Params().NetworkID() == CBaseChainParams::MAIN) {
if(service.GetPort() != 9340) {
notCapableReason = strprintf("Invalid port: %u - only 9340 is supported on mainnet.", service.GetPort());
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
} else if(service.GetPort() == 9340) {
notCapableReason = strprintf("Invalid port: %u - 9340 is only supported on mainnet.", service.GetPort());
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
LogPrintf("CActiveSystemnode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString());
if(!ConnectNode((CAddress)service, NULL, false, true)){
notCapableReason = "Could not connect to " + service.ToString();
LogPrintf("CActiveSystemnode::ManageStatus() - not capable: %s\n", notCapableReason);
return;
}
// Choose coins to use
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
if(pwalletMain->GetSystemnodeVinAndKeys(vin, pubKeyCollateralAddress, keyCollateralAddress)) {
if(GetInputAge(vin) < SYSTEMNODE_MIN_CONFIRMATIONS){
status = ACTIVE_SYSTEMNODE_INPUT_TOO_NEW;
notCapableReason = strprintf("%s - %d confirmations", GetStatus(), GetInputAge(vin));
LogPrintf("CActiveSystemnode::ManageStatus() - %s\n", notCapableReason);
return;
}
LOCK(pwalletMain->cs_wallet);
pwalletMain->LockCoin(vin.prevout);
// send to all nodes
CPubKey pubKeySystemnode;
CKey keySystemnode;
if(!legacySigner.SetKey(strSystemNodePrivKey, errorMessage, keySystemnode, pubKeySystemnode))
{
notCapableReason = "Error upon calling SetKey: " + errorMessage;
LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
return;
}
CSystemnodeBroadcast mnb;
bool fSignOver = true;
if(!CSystemnodeBroadcast::Create(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keySystemnode, pubKeySystemnode, fSignOver, errorMessage, mnb)) {
notCapableReason = "Error on CreateBroadcast: " + errorMessage;
LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
return;
}
//update to masternode list
LogPrintf("CActiveSystemnode::ManageStatus() - Update Systemnode List\n");
snodeman.UpdateSystemnodeList(mnb);
//send to all peers
LogPrintf("CActiveSystemnode::ManageStatus() - Relay broadcast vin = %s\n", vin.ToString());
mnb.Relay();
LogPrintf("CActiveSystemnode::ManageStatus() - Is capable master node!\n");
status = ACTIVE_SYSTEMNODE_STARTED;
return;
} else {
notCapableReason = "Could not find suitable coins!";
LogPrintf("CActiveSystemnode::ManageStatus() - %s\n", notCapableReason);
return;
}
}
//send to all peers
if(!SendSystemnodePing(errorMessage)) {
LogPrintf("CActiveSystemnode::ManageStatus() - Error on Ping: %s\n", errorMessage);
}
}
std::string CActiveSystemnode::GetStatus() {
switch (status) {
case ACTIVE_SYSTEMNODE_INITIAL: return "Node just started, not yet activated";
case ACTIVE_SYSTEMNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Systemnode";
case ACTIVE_SYSTEMNODE_INPUT_TOO_NEW: return strprintf("Systemnode input must have at least %d confirmations", SYSTEMNODE_MIN_CONFIRMATIONS);
case ACTIVE_SYSTEMNODE_NOT_CAPABLE: return "Not capable systemnode: " + notCapableReason;
case ACTIVE_SYSTEMNODE_STARTED: return "Systemnode successfully started";
default: return "unknown";
}
}
bool CActiveSystemnode::SendSystemnodePing(std::string& errorMessage) {
if(status != ACTIVE_SYSTEMNODE_STARTED) {
errorMessage = "Systemnode is not in a running status";
return false;
}
CPubKey pubKeySystemnode;
CKey keySystemnode;
if(!legacySigner.SetKey(strSystemNodePrivKey, errorMessage, keySystemnode, pubKeySystemnode))
{
errorMessage = strprintf("Error upon calling SetKey: %s\n", errorMessage);
return false;
}
LogPrintf("CActiveSystemnode::SendSystemnodePing() - Relay Systemnode Ping vin = %s\n", vin.ToString());
CSystemnodePing mnp(vin);
if(!mnp.Sign(keySystemnode, pubKeySystemnode))
{
errorMessage = "Couldn't sign Systemnode Ping";
return false;
}
// Update lastPing for our systemnode in Systemnode list
CSystemnode* pmn = snodeman.Find(vin);
if(pmn != NULL)
{
if(pmn->IsPingedWithin(SYSTEMNODE_PING_SECONDS, mnp.sigTime)){
errorMessage = "Too early to send Systemnode Ping";
return false;
}
pmn->lastPing = mnp;
snodeman.mapSeenSystemnodePing.insert(make_pair(mnp.GetHash(), mnp));
//snodeman.mapSeenSystemnodeBroadcast.lastPing is probably outdated, so we'll update it
CSystemnodeBroadcast mnb(*pmn);
uint256 hash = mnb.GetHash();
if(snodeman.mapSeenSystemnodeBroadcast.count(hash)) snodeman.mapSeenSystemnodeBroadcast[hash].lastPing = mnp;
mnp.Relay();
return true;
}
else
{
// Seems like we are trying to send a ping while the Systemnode is not registered in the network
errorMessage = "Systemnode List doesn't include our Systemnode, shutting down Systemnode pinging service! " + vin.ToString();
status = ACTIVE_SYSTEMNODE_NOT_CAPABLE;
notCapableReason = errorMessage;
return false;
}
}
// when starting a Systemnode, this can enable to run as a hot wallet with no funds
bool CActiveSystemnode::EnableHotColdSystemNode(const CTxIn& newVin, const CService& newService)
{
if(!fSystemNode) return false;
status = ACTIVE_SYSTEMNODE_STARTED;
//The values below are needed for signing mnping messages going forward
vin = newVin;
service = newService;
LogPrintf("CActiveSystemnode::EnableHotColdSystemNode() - Enabled! You may shut down the cold daemon.\n");
return true;
}