activemasternode.cpp 14.8 KB
Newer Older
1
2
3
4

#include "core.h"
#include "protocol.h"
#include "activemasternode.h"
5
#include "masternodeman.h"
6
7
8
#include <boost/lexical_cast.hpp>

//
Mike Kinney's avatar
Mike Kinney committed
9
// Bootup the Masternode, look for a 1000DRK input and register on the network
10
//
11
void CActiveMasternode::ManageStatus()
12
{
13
14
    std::string errorMessage;

Evan Duffield's avatar
Evan Duffield committed
15
    if(!fMasterNode) return;
16

Evan Duffield's avatar
Evan Duffield committed
17
    if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n");
18
19
20
21

    //need correct adjusted time to send ping
    bool fIsInitialDownload = IsInitialBlockDownload();
    if(fIsInitialDownload) {
22
        status = MASTERNODE_SYNC_IN_PROCESS;
Mike Kinney's avatar
Mike Kinney committed
23
        LogPrintf("CActiveMasternode::ManageStatus() - Sync in progress. Must wait until sync is complete to start Masternode.\n");
24
25
26
        return;
    }

27
28
    if(status == MASTERNODE_INPUT_TOO_NEW || status == MASTERNODE_NOT_CAPABLE || status == MASTERNODE_SYNC_IN_PROCESS){
        status = MASTERNODE_NOT_PROCESSED;
29
30
    }

31
    if(status == MASTERNODE_NOT_PROCESSED) {
32
        if(strMasterNodeAddr.empty()) {
33
            if(!GetLocal(service)) {
Mike Kinney's avatar
Mike Kinney committed
34
                notCapableReason = "Can't detect external address. Please use the Masternodeaddr configuration option.";
35
36
                status = MASTERNODE_NOT_CAPABLE;
                LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str());
37
38
39
                return;
            }
        } else {
40
        	service = CService(strMasterNodeAddr);
41
42
        }

43
        LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString().c_str());
44

45
46
        if(Params().NetworkID() == CChainParams::MAIN){
            if(service.GetPort() != 9999) {
47
                notCapableReason = "Invalid port: " + boost::lexical_cast<string>(service.GetPort()) + " - only 9999 is supported on mainnet.";
48
49
50
51
52
53
                status = MASTERNODE_NOT_CAPABLE;
                LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str());
                return;
            }
        }

Evan Duffield's avatar
Evan Duffield committed
54
        if(Params().NetworkID() == CChainParams::MAIN){
55
56
57
58
59
60
            if(!ConnectNode((CAddress)service, service.ToString().c_str())){
                notCapableReason = "Could not connect to " + service.ToString();
                status = MASTERNODE_NOT_CAPABLE;
                LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str());
                return;
            }
61
62
63
        }

        if(pwalletMain->IsLocked()){
64
65
66
            notCapableReason = "Wallet is locked.";
            status = MASTERNODE_NOT_CAPABLE;
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason.c_str());
67
68
69
            return;
        }

70
71
        // Set defaults
        status = MASTERNODE_NOT_CAPABLE;
Evan Duffield's avatar
Evan Duffield committed
72
        notCapableReason = "Unknown. Check debug.log for more information.";
73
74

        // Choose coins to use
75
76
        CPubKey pubKeyCollateralAddress;
        CKey keyCollateralAddress;
77

78
        if(GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress)) {
79

80
            if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
81
82
83
                notCapableReason = "Input must have least " + boost::lexical_cast<string>(MASTERNODE_MIN_CONFIRMATIONS) +
                        " confirmations - " + boost::lexical_cast<string>(GetInputAge(vin)) + " confirmations";
                LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str());
84
                status = MASTERNODE_INPUT_TOO_NEW;
85
86
87
                return;
            }

88
            LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n");
89

90
91
            status = MASTERNODE_IS_CAPABLE;
            notCapableReason = "";
92

93
            pwalletMain->LockCoin(vin.prevout);
94

95
96
97
            // send to all nodes
            CPubKey pubKeyMasternode;
            CKey keyMasternode;
98

99
100
101
102
            if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
            {
            	LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str());
            	return;
103
104
            }

105
            if(!Register(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage)) {
106
                LogPrintf("CActiveMasternode::ManageStatus() - Error on Register: %s\n", errorMessage.c_str());
107
108
109
            }

            return;
110
        } else {
111
112
            notCapableReason = "Could not find suitable coins!";
            LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason.c_str());
113
114
115
        }
    }

116
117
    //send to all peers
    if(!Dseep(errorMessage)) {
118
        LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage.c_str());
119
120
    }
}
121

Mike Kinney's avatar
Mike Kinney committed
122
// Send stop dseep to network for remote Masternode
123
124
125
126
bool CActiveMasternode::StopMasterNode(std::string strService, std::string strKeyMasternode, std::string& errorMessage) {
	CTxIn vin;
    CKey keyMasternode;
    CPubKey pubKeyMasternode;
127

128
129
130
131
    if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode)) {
    	LogPrintf("CActiveMasternode::StopMasterNode() - Error: %s\n", errorMessage.c_str());
		return false;
	}
132

133
134
	return StopMasterNode(vin, CService(strService), keyMasternode, pubKeyMasternode, errorMessage);
}
135

Mike Kinney's avatar
Mike Kinney committed
136
// Send stop dseep to network for main Masternode
137
138
bool CActiveMasternode::StopMasterNode(std::string& errorMessage) {
	if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) {
Mike Kinney's avatar
Mike Kinney committed
139
		errorMessage = "Masternode is not in a running status";
140
141
142
    	LogPrintf("CActiveMasternode::StopMasterNode() - Error: %s\n", errorMessage.c_str());
		return false;
	}
143

144
	status = MASTERNODE_STOPPED;
145

146
147
148
149
150
151
152
    CPubKey pubKeyMasternode;
    CKey keyMasternode;

    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
    {
    	LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str());
    	return false;
153
154
    }

155
156
157
	return StopMasterNode(vin, service, keyMasternode, pubKeyMasternode, errorMessage);
}

Mike Kinney's avatar
Mike Kinney committed
158
// Send stop dseep to network for any Masternode
159
160
161
162
bool CActiveMasternode::StopMasterNode(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string& errorMessage) {
   	pwalletMain->UnlockCoin(vin.prevout);
	return Dseep(vin, service, keyMasternode, pubKeyMasternode, errorMessage, true);
}
163

164
165
bool CActiveMasternode::Dseep(std::string& errorMessage) {
	if(status != MASTERNODE_IS_CAPABLE && status != MASTERNODE_REMOTELY_ENABLED) {
Mike Kinney's avatar
Mike Kinney committed
166
		errorMessage = "Masternode is not in a running status";
167
168
169
    	LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", errorMessage.c_str());
		return false;
	}
170

171
172
173
174
    CPubKey pubKeyMasternode;
    CKey keyMasternode;

    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
175
    {
176
177
    	LogPrintf("Register::ManageStatus() - Error upon calling SetKey: %s\n", errorMessage.c_str());
    	return false;
178
179
    }

180
181
	return Dseep(vin, service, keyMasternode, pubKeyMasternode, errorMessage, false);
}
182

183
bool CActiveMasternode::Dseep(CTxIn vin, CService service, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage, bool stop) {
184
    std::string errorMessage;
185
186
187
    std::vector<unsigned char> vchMasterNodeSignature;
    std::string strMasterNodeSignMessage;
    int64_t masterNodeSignatureTime = GetAdjustedTime();
188

189
    std::string strMessage = service.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + boost::lexical_cast<std::string>(stop);
190

191
192
193
194
195
    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyMasternode)) {
    	retErrorMessage = "sign message failed: " + errorMessage;
    	LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", retErrorMessage.c_str());
        return false;
    }
196

197
198
199
    if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchMasterNodeSignature, strMessage, errorMessage)) {
    	retErrorMessage = "Verify message failed: " + errorMessage;
    	LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", retErrorMessage.c_str());
200
201
202
        return false;
    }

Mike Kinney's avatar
Mike Kinney committed
203
    // Update Last Seen timestamp in Masternode list
UdjinM6's avatar
UdjinM6 committed
204
205
    CMasternode* pmn = mnodeman.Find(vin);
    if(pmn != NULL)
206
    {
UdjinM6's avatar
UdjinM6 committed
207
        pmn->UpdateLastSeen();
208
    }
209
210
    else
    {
Mike Kinney's avatar
Mike Kinney committed
211
212
    	// Seems like we are trying to send a ping while the Masternode is not registered in the network
    	retErrorMessage = "Darksend Masternode List doesn't include our Masternode, Shutting down Masternode pinging service! " + vin.ToString();
213
214
215
    	LogPrintf("CActiveMasternode::Dseep() - Error: %s\n", retErrorMessage.c_str());
        status = MASTERNODE_NOT_CAPABLE;
        notCapableReason = retErrorMessage;
216
217
218
        return false;
    }

219
    //send to all peers
Evan Duffield's avatar
Evan Duffield committed
220
221
    LogPrintf("CActiveMasternode::Dseep() - RelayMasternodeEntryPing vin = %s\n", vin.ToString().c_str());
    mnodeman.RelayMasternodeEntryPing(vin, vchMasterNodeSignature, masterNodeSignatureTime, stop);
222

223
224
    return true;
}
225

226
227
228
229
230
231
232
233
234
235
236
bool CActiveMasternode::Register(std::string strService, std::string strKeyMasternode, std::string txHash, std::string strOutputIndex, std::string& errorMessage) {
	CTxIn vin;
    CPubKey pubKeyCollateralAddress;
    CKey keyCollateralAddress;
    CPubKey pubKeyMasternode;
    CKey keyMasternode;

    if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode))
    {
    	LogPrintf("CActiveMasternode::Register() - Error upon calling SetKey: %s\n", errorMessage.c_str());
    	return false;
237
238
    }

239
240
241
242
243
244
245
    if(!GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress, txHash, strOutputIndex)) {
		errorMessage = "could not allocate vin";
    	LogPrintf("Register::Register() - Error: %s\n", errorMessage.c_str());
		return false;
	}
	return Register(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage);
}
246

247
248
249
250
251
bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &retErrorMessage) {
    std::string errorMessage;
    std::vector<unsigned char> vchMasterNodeSignature;
    std::string strMasterNodeSignMessage;
    int64_t masterNodeSignatureTime = GetAdjustedTime();
252

253
254
    std::string vchPubKey(pubKeyCollateralAddress.begin(), pubKeyCollateralAddress.end());
    std::string vchPubKey2(pubKeyMasternode.begin(), pubKeyMasternode.end());
255

256
    std::string strMessage = service.ToString() + boost::lexical_cast<std::string>(masterNodeSignatureTime) + vchPubKey + vchPubKey2 + boost::lexical_cast<std::string>(PROTOCOL_VERSION);
257

258
259
260
261
262
    if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchMasterNodeSignature, keyCollateralAddress)) {
		retErrorMessage = "sign message failed: " + errorMessage;
		LogPrintf("CActiveMasternode::Register() - Error: %s\n", retErrorMessage.c_str());
		return false;
    }
263

264
265
266
267
268
    if(!darkSendSigner.VerifyMessage(pubKeyCollateralAddress, vchMasterNodeSignature, strMessage, errorMessage)) {
		retErrorMessage = "Verify message failed: " + errorMessage;
		LogPrintf("CActiveMasternode::Register() - Error: %s\n", retErrorMessage.c_str());
		return false;
	}
269

UdjinM6's avatar
UdjinM6 committed
270
271
    CMasternode* pmn = mnodeman.Find(vin);
    if(pmn == NULL)
272
    {
Mike Kinney's avatar
Mike Kinney committed
273
        LogPrintf("CActiveMasternode::Register() - Adding to Masternode list service: %s - vin: %s\n", service.ToString().c_str(), vin.ToString().c_str());
274
        CMasternode mn(service, vin, pubKeyCollateralAddress, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyMasternode, PROTOCOL_VERSION);
275
        mn.UpdateLastSeen(masterNodeSignatureTime);
276
        mnodeman.Add(mn);
277
    }
278

279
    //send to all peers
Evan Duffield's avatar
Evan Duffield committed
280
281
    LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString().c_str());
    mnodeman.RelayMasternodeEntry(vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION);
282

283
284
285
286
287
288
    return true;
}

bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey) {
	return GetMasterNodeVin(vin, pubkey, secretKey, "", "");
}
289

290
291
292
293
294
295
296
297
298
299
300
bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) {
    CScript pubScript;

    // Find possible candidates
    vector<COutput> possibleCoins = SelectCoinsMasternode();
    COutput *selectedOutput;

    // Find the vin
	if(!strTxHash.empty()) {
		// Let's find it
		uint256 txHash(strTxHash);
301
        int outputIndex = boost::lexical_cast<int>(strOutputIndex);
302
303
		bool found = false;
		BOOST_FOREACH(COutput& out, possibleCoins) {
304
305
			if(out.tx->GetHash() == txHash && out.i == outputIndex)
			{
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
				selectedOutput = &out;
				found = true;
				break;
			}
		}
		if(!found) {
			LogPrintf("CActiveMasternode::GetMasterNodeVin - Could not locate valid vin\n");
			return false;
		}
	} else {
		// No output specified,  Select the first one
		if(possibleCoins.size() > 0) {
			selectedOutput = &possibleCoins[0];
		} else {
			LogPrintf("CActiveMasternode::GetMasterNodeVin - Could not locate specified vin from possible list\n");
			return false;
		}
323
324
    }

325
326
	// At this point we have a selected output, retrieve the associated info
	return GetVinFromOutput(*selectedOutput, vin, pubkey, secretKey);
327
328
329
}


Mike Kinney's avatar
Mike Kinney committed
330
// Extract Masternode vin information from output
331
332
bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey) {

333
334
    CScript pubScript;

335
336
	vin = CTxIn(out.tx->GetHash(),out.i);
    pubScript = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
337

338
	CTxDestination address1;
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
    ExtractDestination(pubScript, address1);
    CBitcoinAddress address2(address1);

    CKeyID keyID;
    if (!address2.GetKeyID(keyID)) {
        LogPrintf("CActiveMasternode::GetMasterNodeVin - Address does not refer to a key\n");
        return false;
    }

    if (!pwalletMain->GetKey(keyID, secretKey)) {
        LogPrintf ("CActiveMasternode::GetMasterNodeVin - Private key for address is not known\n");
        return false;
    }

    pubkey = secretKey.GetPubKey();
    return true;
}

Mike Kinney's avatar
Mike Kinney committed
357
// get all possible outputs for running Masternode
358
359
360
361
362
363
vector<COutput> CActiveMasternode::SelectCoinsMasternode()
{
    vector<COutput> vCoins;
    vector<COutput> filteredCoins;

    // Retrieve all possible outputs
364
    pwalletMain->AvailableCoins(vCoins);
365
366
367
368
369
370
371
372
373
374
375

    // Filter
    BOOST_FOREACH(const COutput& out, vCoins)
    {
        if(out.tx->vout[out.i].nValue == 1000*COIN) { //exactly
        	filteredCoins.push_back(out);
        }
    }
    return filteredCoins;
}

Mike Kinney's avatar
Mike Kinney committed
376
// when starting a Masternode, this can enable to run as a hot wallet with no funds
377
bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newService)
378
379
380
{
    if(!fMasterNode) return false;

381
    status = MASTERNODE_REMOTELY_ENABLED;
382

383
384
385
    //The values below are needed for signing dseep messages going forward
    this->vin = newVin;
    this->service = newService;
386
387
388
389
390

    LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n");

    return true;
}