activemasternode.cpp 8.33 KB
Newer Older
1

UdjinM6's avatar
fix    
UdjinM6 committed
2
#include "addrman.h"
3
4
5
#include "protocol.h"
#include "activethrone.h"
#include "throneman.h"
infernoman's avatar
infernoman committed
6
#include "throne.h"
UdjinM6's avatar
UdjinM6 committed
7
#include "spork.h"
8
9

//
Alastair Clark's avatar
Alastair Clark committed
10
// Bootup the Masternode, look for a 10000 CRW input and register on the network
11
//
Alastair Clark's avatar
Alastair Clark committed
12
void CActiveMasternode::ManageStatus()
Evan Duffield's avatar
Evan Duffield committed
13
{    
14
15
    std::string errorMessage;

Alastair Clark's avatar
Alastair Clark committed
16
    if(!fMasterNode) return;
17

Alastair Clark's avatar
Alastair Clark committed
18
    if (fDebug) LogPrintf("CActiveMasternode::ManageStatus() - Begin\n");
19

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

Alastair Clark's avatar
Alastair Clark committed
27
    if(status == ACTIVE_MASTERNODE_SYNC_IN_PROCESS) status = ACTIVE_MASTERNODE_INITIAL;
UdjinM6's avatar
UdjinM6 committed
28

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

Alastair Clark's avatar
Alastair Clark committed
38
    if(status != ACTIVE_MASTERNODE_STARTED) {
39
40

        // Set defaults
Alastair Clark's avatar
Alastair Clark committed
41
        status = ACTIVE_MASTERNODE_NOT_CAPABLE;
42
43
        notCapableReason = "";

44
45
        if(pwalletMain->IsLocked()){
            notCapableReason = "Wallet is locked.";
Alastair Clark's avatar
Alastair Clark committed
46
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
47
48
49
50
51
            return;
        }

        if(pwalletMain->GetBalance() == 0){
            notCapableReason = "Hot node, waiting for remote activation.";
Alastair Clark's avatar
Alastair Clark committed
52
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
53
54
55
            return;
        }

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

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

Alastair Clark's avatar
Alastair Clark committed
78
        LogPrintf("CActiveMasternode::ManageStatus() - Checking inbound connection to '%s'\n", service.ToString());
79

Infernoman's avatar
Infernoman committed
80
        if(!ConnectNode((CAddress)service, NULL, true)){
81
            notCapableReason = "Could not connect to " + service.ToString();
Alastair Clark's avatar
Alastair Clark committed
82
            LogPrintf("CActiveMasternode::ManageStatus() - not capable: %s\n", notCapableReason);
83
84
85
86
87
88
89
            return;
        }

        // Choose coins to use
        CPubKey pubKeyCollateralAddress;
        CKey keyCollateralAddress;

Alastair Clark's avatar
Alastair Clark committed
90
        if(pwalletMain->GetMasternodeVinAndKeys(vin, pubKeyCollateralAddress, keyCollateralAddress)) {
91

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

UdjinM6's avatar
UdjinM6 committed
99
            LOCK(pwalletMain->cs_wallet);
100
101
102
            pwalletMain->LockCoin(vin.prevout);

            // send to all nodes
Alastair Clark's avatar
Alastair Clark committed
103
104
            CPubKey pubKeyMasternode;
            CKey keyMasternode;
105

Alastair Clark's avatar
Alastair Clark committed
106
            if(!legacySigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
107
            {
108
109
                notCapableReason = "Error upon calling SetKey: " + errorMessage;
                LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
110
111
112
                return;
            }

Alastair Clark's avatar
Alastair Clark committed
113
114
            CMasternodeBroadcast mnb;
            if(!CMasternodeBroadcast::Create(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyMasternode, pubKeyMasternode, errorMessage, mnb)) {
115
                notCapableReason = "Error on CreateBroadcast: " + errorMessage;
116
117
                LogPrintf("Register::ManageStatus() - %s\n", notCapableReason);
                return;
118
119
            }

Infernoman's avatar
Infernoman committed
120
            //update to masternode list
Alastair Clark's avatar
Alastair Clark committed
121
122
            LogPrintf("CActiveMasternode::ManageStatus() - Update Masternode List\n");
            mnodeman.UpdateMasternodeList(mnb);
Infernoman's avatar
Infernoman committed
123

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

Alastair Clark's avatar
Alastair Clark committed
128
            LogPrintf("CActiveMasternode::ManageStatus() - Is capable master node!\n");
Alastair Clark's avatar
Alastair Clark committed
129
            status = ACTIVE_MASTERNODE_STARTED;
130

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

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

Alastair Clark's avatar
Alastair Clark committed
145
std::string CActiveMasternode::GetStatus() {
146
    switch (status) {
Alastair Clark's avatar
Alastair Clark committed
147
    case ACTIVE_MASTERNODE_INITIAL: return "Node just started, not yet activated";
Alastair Clark's avatar
Alastair Clark committed
148
149
    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);
Alastair Clark's avatar
Alastair Clark committed
150
    case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable throne: " + notCapableReason;
Alastair Clark's avatar
Alastair Clark committed
151
    case ACTIVE_MASTERNODE_STARTED: return "Masternode successfully started";
152
    default: return "unknown";
153
154
155
    }
}

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

Alastair Clark's avatar
Alastair Clark committed
162
163
    CPubKey pubKeyMasternode;
    CKey keyMasternode;
164

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

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

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

189
        pmn->lastPing = mnp;
Alastair Clark's avatar
Alastair Clark committed
190
        mnodeman.mapSeenMasternodePing.insert(make_pair(mnp.GetHash(), mnp));
191

Alastair Clark's avatar
Alastair Clark committed
192
193
        //mnodeman.mapSeenMasternodeBroadcast.lastPing is probably outdated, so we'll update it
        CMasternodeBroadcast mnb(*pmn);
194
        uint256 hash = mnb.GetHash();
Alastair Clark's avatar
Alastair Clark committed
195
        if(mnodeman.mapSeenMasternodeBroadcast.count(hash)) mnodeman.mapSeenMasternodeBroadcast[hash].lastPing = mnp;
196

197
        mnp.Relay();
198

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

}

Alastair Clark's avatar
Alastair Clark committed
212
213
// when starting a Masternode, this can enable to run as a hot wallet with no funds
bool CActiveMasternode::EnableHotColdMasterNode(CTxIn& newVin, CService& newService)
214
{
Alastair Clark's avatar
Alastair Clark committed
215
    if(!fMasterNode) return false;
216

Alastair Clark's avatar
Alastair Clark committed
217
    status = ACTIVE_MASTERNODE_STARTED;
218

Evan Duffield's avatar
Evan Duffield committed
219
    //The values below are needed for signing mnping messages going forward
UdjinM6's avatar
UdjinM6 committed
220
221
    vin = newVin;
    service = newService;
222

Alastair Clark's avatar
Alastair Clark committed
223
    LogPrintf("CActiveMasternode::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n");
224
225
226

    return true;
}