activemasternode.cpp 15.2 KB
Newer Older
1

UdjinM6's avatar
fix    
UdjinM6 committed
2
#include "addrman.h"
3
4
#include "protocol.h"
#include "activemasternode.h"
5
#include "masternodeman.h"
Evan Duffield's avatar
Evan Duffield committed
6
#include "masternode.h"
7
#include "masternodeconfig.h"
UdjinM6's avatar
UdjinM6 committed
8
#include "spork.h"
9
10

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

Evan Duffield's avatar
Evan Duffield committed
17
    if(!fMasterNode) return;
18

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

21
    //need correct blocks to send ping
22
    if(Params().NetworkID() != CBaseChainParams::REGTEST && !masternodeSync.IsBlockchainSynced()) {
23
        status = ACTIVE_MASTERNODE_SYNC_IN_PROCESS;
UdjinM6's avatar
UdjinM6 committed
24
        LogPrintf("CActiveMasternode::ManageStatus() - %s\n", GetStatus());
25
26
27
        return;
    }

UdjinM6's avatar
UdjinM6 committed
28
29
30
    if(status == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) status = ACTIVE_MASTERNODE_INITIAL;

    if(status == ACTIVE_MASTERNODE_INITIAL) {
31
32
33
34
        CMasternode *pmn;
        pmn = mnodeman.Find(pubKeyMasternode);
        if(pmn != NULL) {
            pmn->Check();
35
            if(pmn->IsEnabled() && pmn->protocolVersion == PROTOCOL_VERSION) EnableHotColdMasterNode(pmn->vin, pmn->addr);
36
        }
37
38
    }

39
    if(status != ACTIVE_MASTERNODE_STARTED) {
40
41

        // Set defaults
42
        status = ACTIVE_MASTERNODE_NOT_CAPABLE;
43
44
        notCapableReason = "";

45
46
47
48
49
50
51
52
53
54
55
56
        if(pwalletMain->IsLocked()){
            notCapableReason = "Wallet is locked.";
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
            return;
        }

        if(pwalletMain->GetBalance() == 0){
            notCapableReason = "Hot node, waiting for remote activation.";
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
            return;
        }

57
        if(strMasterNodeAddr.empty()) {
58
            if(!GetLocal(service)) {
UdjinM6's avatar
UdjinM6 committed
59
                notCapableReason = "Can't detect external address. Please use the masternodeaddr configuration option.";
60
                LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
61
62
63
                return;
            }
        } else {
UdjinM6's avatar
UdjinM6 committed
64
            service = CService(strMasterNodeAddr);
65
66
        }

67
        if(Params().NetworkID() == CBaseChainParams::MAIN) {
68
            if(service.GetPort() != 9999) {
UdjinM6's avatar
UdjinM6 committed
69
                notCapableReason = strprintf("Invalid port: %u - only 9999 is supported on mainnet.", service.GetPort());
70
                LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
71
72
                return;
            }
UdjinM6's avatar
UdjinM6 committed
73
        } else if(service.GetPort() == 9999) {
UdjinM6's avatar
UdjinM6 committed
74
            notCapableReason = strprintf("Invalid port: %u - 9999 is only supported on mainnet.", service.GetPort());
75
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
UdjinM6's avatar
UdjinM6 committed
76
            return;
77
78
        }

79
80
81
82
        LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString());

        CNode *pnode = ConnectNode((CAddress)service, NULL, false);
        if(!pnode){
83
            notCapableReason = "Could not connect to " + service.ToString();
84
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
85
            return;
86
        }
87
        pnode->Release();
88
89

        // Choose coins to use
90
91
        CPubKey pubKeyCollateralAddress;
        CKey keyCollateralAddress;
92

93
        if(GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress)) {
94

95
            if(GetInputAge(vin) < MASTERNODE_MIN_CONFIRMATIONS){
96
                status = ACTIVE_MASTERNODE_INPUT_TOO_NEW;
UdjinM6's avatar
UdjinM6 committed
97
98
                notCapableReason = strprintf("%s - %d confirmations", GetStatus(), GetInputAge(vin));
                LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason);
99
100
101
                return;
            }

UdjinM6's avatar
UdjinM6 committed
102
            LOCK(pwalletMain->cs_wallet);
103
            pwalletMain->LockCoin(vin.prevout);
104

105
106
107
            // send to all nodes
            CPubKey pubKeyMasternode;
            CKey keyMasternode;
108

109
110
            if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
            {
111
112
                notCapableReason = "Error upon calling SetKey: " + errorMessage;
                LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
UdjinM6's avatar
UdjinM6 committed
113
                return;
114
115
            }

116
117
118
            CMasternodeBroadcast mnb;
            if(!CreateBroadcast(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb)) {
                notCapableReason = "Error on CreateBroadcast: " + errorMessage;
119
120
                LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
                return;
121
122
            }

123
124
125
126
            //send to all peers
            LogPrintf("CActiveMasternode::ManageStatus() - Relay broadcast vin = %s\n", vin.ToString());
            mnb.Relay();

127
            LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n");
128
            status = ACTIVE_MASTERNODE_STARTED;
129

130
            return;
131
        } else {
132
            notCapableReason = "Could not find suitable coins!";
133
134
            LogPrintf("CActiveMasternode::ManageStatus() - %s\n", notCapableReason);
            return;
135
136
137
        }
    }

138
    //send to all peers
139
140
141
142
143
144
145
    if(!SendMasternodePing(errorMessage)) {
        LogPrintf("CActiveMasternode::ManageStatus() - Error on Ping: %s\n", errorMessage);
    }
}

std::string CActiveMasternode::GetStatus() {
    switch (status) {
UdjinM6's avatar
UdjinM6 committed
146
147
148
149
150
    case ACTIVE_MASTERNODE_INITIAL: return "Node just started, not yet activated";
    case ACTIVE_MASTERNODE_SYNC_IN_PROCESS: return "Sync in progress. Must wait until sync is complete to start Masternode";
    case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return strprintf("Masternode input must have at least %d confirmations", MASTERNODE_MIN_CONFIRMATIONS);
    case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable masternode: " + notCapableReason;
    case ACTIVE_MASTERNODE_STARTED: return "Masternode successfully started";
151
    default: return "unknown";
152
153
    }
}
154

155
bool CActiveMasternode::SendMasternodePing(std::string& errorMessage) {
156
    if(status != ACTIVE_MASTERNODE_STARTED) {
UdjinM6's avatar
UdjinM6 committed
157
158
159
        errorMessage = "Masternode is not in a running status";
        return false;
    }
160

161
162
163
164
165
    CPubKey pubKeyMasternode;
    CKey keyMasternode;

    if(!darkSendSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
    {
166
        errorMessage = strprintf("Error upon calling SetKey: %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
167
        return false;
168
169
    }

170
    LogPrintf("CActiveMasternode::SendMasternodePing() - Relay Masternode Ping vin = %s\n", vin.ToString());
Evan Duffield's avatar
Evan Duffield committed
171
172
173
    
    CMasternodePing mnp(vin);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode))
174
    {
175
        errorMessage = "Couldn't sign Masternode Ping";
176
177
178
        return false;
    }

179
    // Update lastPing for our masternode in Masternode list
UdjinM6's avatar
UdjinM6 committed
180
181
    CMasternode* pmn = mnodeman.Find(vin);
    if(pmn != NULL)
182
    {
183
184
185
186
187
188
        if(pmn->IsPingedWithin(MASTERNODE_PING_SECONDS, mnp.sigTime)){
            errorMessage = "Too early to send Masternode Ping";
            return false;
        }

        pmn->lastPing = mnp;
UdjinM6's avatar
UdjinM6 committed
189
        mnodeman.mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp));
190
191
192
193
194
195

        //mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it
        CMasternodeBroadcast mnb(*pmn);
        uint256 hash = mnb.GetHash();
        if(mnodeman.mapSeenMasternodeBroadcast.count(hash)) mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = mnp;

196
        mnp.Relay();
197

198
        return true;
199
    }
200
201
    else
    {
UdjinM6's avatar
UdjinM6 committed
202
        // Seems like we are trying to send a ping while the Masternode is not registered in the network
203
        errorMessage = "Darksend Masternode List doesn't include our Masternode, shutting down Masternode pinging service! " + vin.ToString();
204
        status = ACTIVE_MASTERNODE_NOT_CAPABLE;
205
        notCapableReason = errorMessage;
206
207
208
        return false;
    }

209
}
210

211
bool CActiveMasternode::CreateBroadcast(std::string strService, std::string strKeyMasternode, std::string strTxHash, std::string strOutputIndex, std::string& errorMessage, CMasternodeBroadcast &mnb, bool fOffline) {
UdjinM6's avatar
UdjinM6 committed
212
    CTxIn vin;
213
214
215
216
217
    CPubKey pubKeyCollateralAddress;
    CKey keyCollateralAddress;
    CPubKey pubKeyMasternode;
    CKey keyMasternode;

UdjinM6's avatar
UdjinM6 committed
218
    //need correct blocks to send ping
219
220
221
    if(!fOffline && !masternodeSync.IsBlockchainSynced()) {
        errorMessage = "Sync in progress. Must wait until sync is complete to start Masternode";
        LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
222
223
224
        return false;
    }

225
226
    if(!darkSendSigner.SetKey(strKeyMasternode, errorMessage, keyMasternode, pubKeyMasternode))
    {
UdjinM6's avatar
UdjinM6 committed
227
        errorMessage = strprintf("Can't find keys for masternode %s - %s", strService, errorMessage);
228
        LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
229
230
231
232
233
        return false;
    }

    if(!GetMasterNodeVin(vin, pubKeyCollateralAddress, keyCollateralAddress, strTxHash, strOutputIndex)) {
        errorMessage = strprintf("Could not allocate vin %s:%s for masternode %s", strTxHash, strOutputIndex, strService);
234
        LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
235
236
237
238
239
240
241
        return false;
    }

    CService service = CService(strService);
    if(Params().NetworkID() == CBaseChainParams::MAIN) {
        if(service.GetPort() != 9999) {
            errorMessage = strprintf("Invalid port %u for masternode %s - only 9999 is supported on mainnet.", service.GetPort(), strService);
242
            LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
243
244
245
246
            return false;
        }
    } else if(service.GetPort() == 9999) {
        errorMessage = strprintf("Invalid port %u for masternode %s - 9999 is only supported on mainnet.", service.GetPort(), strService);
247
        LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
UdjinM6's avatar
UdjinM6 committed
248
        return false;
249
250
    }

UdjinM6's avatar
fix    
UdjinM6 committed
251
252
    addrman.Add(CAddress(service), CNetAddr("127.0.0.1"), 2*60*60);

253
    return CreateBroadcast(vin, CService(strService), keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb);
254
}
255

256
257
258
259
bool CActiveMasternode::CreateBroadcast(CTxIn vin, CService service, CKey keyCollateralAddress, CPubKey pubKeyCollateralAddress, CKey keyMasternode, CPubKey pubKeyMasternode, std::string &errorMessage, CMasternodeBroadcast &mnb) {
    // wait for reindex and/or import to finish
    if (fImporting || fReindex) return false;

260
261
    CMasternodePing mnp(vin);
    if(!mnp.Sign(keyMasternode, pubKeyMasternode)){
UdjinM6's avatar
UdjinM6 committed
262
        errorMessage = strprintf("Failed to sign ping, vin: %s", vin.ToString());
263
264
        LogPrintf("CActiveMasternode::CreateBroadcast() -  %s\n", errorMessage);
        mnb = CMasternodeBroadcast();
265
266
267
268
269
270
        return false;
    }

    mnb = CMasternodeBroadcast(service, vin, pubKeyCollateralAddress, pubKeyMasternode, PROTOCOL_VERSION);
    mnb.lastPing = mnp;
    if(!mnb.Sign(keyCollateralAddress)){
UdjinM6's avatar
UdjinM6 committed
271
        errorMessage = strprintf("Failed to sign broadcast, vin: %s", vin.ToString());
272
273
        LogPrintf("CActiveMasternode::CreateBroadcast() - %s\n", errorMessage);
        mnb = CMasternodeBroadcast();
274
275
        return false;
    }
276

277
278
279
280
    return true;
}

bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey) {
UdjinM6's avatar
UdjinM6 committed
281
    return GetMasterNodeVin(vin, pubkey, secretKey, "", "");
282
}
283

284
bool CActiveMasternode::GetMasterNodeVin(CTxIn& vin, CPubKey& pubkey, CKey& secretKey, std::string strTxHash, std::string strOutputIndex) {
285
286
287
    // wait for reindex and/or import to finish
    if (fImporting || fReindex) return false;

288
    // Find possible candidates
Evan Duffield's avatar
Evan Duffield committed
289
290
291
    TRY_LOCK(pwalletMain->cs_wallet, fWallet);
    if(!fWallet) return false;

292
293
294
295
    vector<COutput> possibleCoins = SelectCoinsMasternode();
    COutput *selectedOutput;

    // Find the vin
UdjinM6's avatar
UdjinM6 committed
296
297
298
    if(!strTxHash.empty()) {
        // Let's find it
        uint256 txHash(strTxHash);
UdjinM6's avatar
UdjinM6 committed
299
        int outputIndex = atoi(strOutputIndex.c_str());
UdjinM6's avatar
UdjinM6 committed
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
        bool found = false;
        BOOST_FOREACH(COutput& out, possibleCoins) {
            if(out.tx->GetHash() == txHash && out.i == outputIndex)
            {
                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;
        }
321
322
    }

UdjinM6's avatar
UdjinM6 committed
323
324
    // At this point we have a selected output, retrieve the associated info
    return GetVinFromOutput(*selectedOutput, vin, pubkey, secretKey);
325
326
327
}


Mike Kinney's avatar
Mike Kinney committed
328
// Extract Masternode vin information from output
329
bool CActiveMasternode::GetVinFromOutput(COutput out, CTxIn& vin, CPubKey& pubkey, CKey& secretKey) {
330
331
    // wait for reindex and/or import to finish
    if (fImporting || fReindex) return false;
332

333
334
    CScript pubScript;

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

UdjinM6's avatar
UdjinM6 committed
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
vector<COutput> CActiveMasternode::SelectCoinsMasternode()
{
    vector<COutput> vCoins;
    vector<COutput> filteredCoins;
362
363
364
365
366
367
368
    vector<COutPoint> confLockedCoins;

    // Temporary unlock MN coins from masternode.conf
    if(GetBoolArg("-mnconflock", true)) {
        uint256 mnTxHash;
        BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
            mnTxHash.SetHex(mne.getTxHash());
UdjinM6's avatar
UdjinM6 committed
369
            COutPoint outpoint = COutPoint(mnTxHash, atoi(mne.getOutputIndex().c_str()));
370
371
372
373
            confLockedCoins.push_back(outpoint);
            pwalletMain->UnlockCoin(outpoint);
        }
    }
374
375

    // Retrieve all possible outputs
376
    pwalletMain->AvailableCoins(vCoins);
377

378
379
380
381
382
383
    // Lock MN coins from masternode.conf back if they where temporary unlocked
    if(!confLockedCoins.empty()) {
        BOOST_FOREACH(COutPoint outpoint, confLockedCoins)
            pwalletMain->LockCoin(outpoint);
    }

384
385
386
387
    // Filter
    BOOST_FOREACH(const COutput& out, vCoins)
    {
        if(out.tx->vout[out.i].nValue == 1000*COIN) { //exactly
UdjinM6's avatar
UdjinM6 committed
388
            filteredCoins.push_back(out);
389
390
391
392
393
        }
    }
    return filteredCoins;
}

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

399
    status = ACTIVE_MASTERNODE_STARTED;
400

Evan Duffield's avatar
Evan Duffield committed
401
    //The values below are needed for signing mnping messages going forward
UdjinM6's avatar
UdjinM6 committed
402
403
    vin = newVin;
    service = newService;
404
405
406
407
408

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

    return true;
}