activemasternode.cpp 8.08 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

//
infernoman's avatar
infernoman committed
10
// Bootup the Throne, look for a 10000 CRW input and register on the network
11
12
//
void CActiveThrone::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
18
19

    if (fDebug) LogPrintf("CActiveThrone::ManageStatus() - Begin\n");

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;
infernoman's avatar
infernoman committed
23
        LogPrintf("CActiveThrone::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) {
infernoman's avatar
infernoman committed
30
31
        CThrone *pmn;
        pmn = mnodeman.Find(pubKeyThrone);
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.";
infernoman's avatar
infernoman committed
46
            LogPrintf("CActiveThrone::ManageStatus() - not capable: %s\n", notCapableReason);
47
48
49
50
51
            return;
        }

        if(pwalletMain->GetBalance() == 0){
            notCapableReason = "Hot node, waiting for remote activation.";
infernoman's avatar
infernoman committed
52
            LogPrintf("CActiveThrone::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.";
infernoman's avatar
infernoman committed
59
                LogPrintf("CActiveThrone::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());
infernoman's avatar
infernoman committed
69
                LogPrintf("CActiveThrone::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());
infernoman's avatar
infernoman committed
74
            LogPrintf("CActiveThrone::ManageStatus() - not capable: %s\n", notCapableReason);
75
76
77
            return;
        }

infernoman's avatar
infernoman committed
78
        LogPrintf("CActiveThrone::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();
infernoman's avatar
infernoman committed
82
            LogPrintf("CActiveThrone::ManageStatus() - not capable: %s\n", notCapableReason);
83
84
85
86
87
88
89
            return;
        }

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

90
        if(pwalletMain->GetThroneVinAndKeys(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));
infernoman's avatar
infernoman committed
95
                LogPrintf("CActiveThrone::ManageStatus() - %s\n", notCapableReason);
96
97
98
                return;
            }

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

            // send to all nodes
            CPubKey pubKeyThrone;
            CKey keyThrone;

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

infernoman's avatar
infernoman committed
113
            CThroneBroadcast mnb;
114
            if(!CThroneBroadcast::Create(vin, service, keyCollateralAddress, pubKeyCollateralAddress, keyThrone, pubKeyThrone, 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
121
122
123
            //update to masternode list
            LogPrintf("CActiveThrone::ManageStatus() - Update Throne List\n");
            mnodeman.UpdateThroneList(mnb);

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

infernoman's avatar
infernoman committed
128
            LogPrintf("CActiveThrone::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!";
infernoman's avatar
infernoman committed
134
            LogPrintf("CActiveThrone::ManageStatus() - %s\n", notCapableReason);
135
            return;
136
137
138
139
        }
    }

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

infernoman's avatar
infernoman committed
145
std::string CActiveThrone::GetStatus() {
146
    switch (status) {
Alastair Clark's avatar
Alastair Clark committed
147
148
149
150
151
    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 Throne";
    case ACTIVE_MASTERNODE_INPUT_TOO_NEW: return strprintf("Throne input must have at least %d confirmations", MASTERNODE_MIN_CONFIRMATIONS);
    case ACTIVE_MASTERNODE_NOT_CAPABLE: return "Not capable throne: " + notCapableReason;
    case ACTIVE_MASTERNODE_STARTED: return "Throne successfully started";
152
    default: return "unknown";
153
154
155
    }
}

infernoman's avatar
infernoman committed
156
bool CActiveThrone::SendThronePing(std::string& errorMessage) {
Alastair Clark's avatar
Alastair Clark committed
157
    if(status != ACTIVE_MASTERNODE_STARTED) {
158
159
160
161
162
163
164
        errorMessage = "Throne is not in a running status";
        return false;
    }

    CPubKey pubKeyThrone;
    CKey keyThrone;

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

infernoman's avatar
infernoman committed
171
    LogPrintf("CActiveThrone::SendThronePing() - Relay Throne Ping vin = %s\n", vin.ToString());
Evan Duffield's avatar
Evan Duffield committed
172
    
infernoman's avatar
infernoman committed
173
174
    CThronePing mnp(vin);
    if(!mnp.Sign(keyThrone, pubKeyThrone))
175
    {
infernoman's avatar
infernoman committed
176
        errorMessage = "Couldn't sign Throne Ping";
177
178
179
        return false;
    }

infernoman's avatar
infernoman committed
180
    // Update lastPing for our throne in Throne list
infernoman's avatar
infernoman committed
181
    CThrone* 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)){
infernoman's avatar
infernoman committed
185
            errorMessage = "Too early to send Throne Ping";
186
187
            return false;
        }
188

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

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

197
        mnp.Relay();
198

199
        return true;
200
201
202
203
    }
    else
    {
        // Seems like we are trying to send a ping while the Throne is not registered in the network
Alastair Clark's avatar
Alastair Clark committed
204
        errorMessage = "Throne List doesn't include our Throne, shutting down Throne 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
212
        return false;
    }

}

// when starting a Throne, this can enable to run as a hot wallet with no funds
Alastair Clark's avatar
Alastair Clark committed
213
bool CActiveThrone::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("CActiveThrone::EnableHotColdMasterNode() - Enabled! You may shut down the cold daemon.\n");
224
225
226

    return true;
}