spork.cpp 11.4 KB
Newer Older
Evan Duffield's avatar
Evan Duffield committed
1
2
3
4
5
6
7
8
9
10



#include "sync.h"
#include "net.h"
#include "key.h"
#include "util.h"
#include "base58.h"
#include "protocol.h"
#include "spork.h"
11
#include "main.h"
Alastair Clark's avatar
Alastair Clark committed
12
#include "masternode-budget.h"
Evan Duffield's avatar
Evan Duffield committed
13
14
15
16
17
18
19
20
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

class CSporkMessage;
class CSporkManager;

Evan Duffield's avatar
Evan Duffield committed
21
22
CSporkManager sporkManager;

Evan Duffield's avatar
Evan Duffield committed
23
24
std::map<uint256, CSporkMessage> mapSporks;
std::map<int, CSporkMessage> mapSporksActive;
Evan Duffield's avatar
Evan Duffield committed
25

Evan Duffield's avatar
Evan Duffield committed
26
27
28

void ProcessSpork(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
Alastair Clark's avatar
Alastair Clark committed
29
    if(fLiteMode) return; //disable all masternode related functionality
Evan Duffield's avatar
Evan Duffield committed
30
31
32
33
34
35
36
37
38
39
40

    if (strCommand == "spork")
    {
        //LogPrintf("ProcessSpork::spork\n");
        CDataStream vMsg(vRecv);
        CSporkMessage spork;
        vRecv >> spork;

        if(chainActive.Tip() == NULL) return;

        uint256 hash = spork.GetHash();
41
        if(mapSporksActive.count(spork.nSporkID)) {
Evan Duffield's avatar
Evan Duffield committed
42
            if(mapSporksActive[spork.nSporkID].nTimeSigned >= spork.nTimeSigned){
43
                if(fDebug) LogPrintf("spork - seen %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
Evan Duffield's avatar
Evan Duffield committed
44
45
                return;
            } else {
46
                if(fDebug) LogPrintf("spork - got updated spork %s block %d \n", hash.ToString(), chainActive.Tip()->nHeight);
Evan Duffield's avatar
Evan Duffield committed
47
48
49
            }
        }

50
        LogPrintf("spork - new %s ID %d Time %d bestHeight %d\n", hash.ToString(), spork.nSporkID, spork.nValue, chainActive.Tip()->nHeight);
Evan Duffield's avatar
Evan Duffield committed
51
52
53
54
55
56
57

        if(!sporkManager.CheckSignature(spork)){
            LogPrintf("spork - invalid signature\n");
            Misbehaving(pfrom->GetId(), 100);
            return;
        }

58
        mapSporks[hash] = spork;
Evan Duffield's avatar
Evan Duffield committed
59
60
61
        mapSporksActive[spork.nSporkID] = spork;
        sporkManager.Relay(spork);

62
63
        //does a task if needed
        ExecuteSpork(spork.nSporkID, spork.nValue);
Evan Duffield's avatar
Evan Duffield committed
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
    }
    if (strCommand == "getsporks")
    {
        std::map<int, CSporkMessage>::iterator it = mapSporksActive.begin();

        while(it != mapSporksActive.end()) {
            pfrom->PushMessage("spork", it->second);
            it++;
        }
    }

}

// grab the spork, otherwise say it's off
bool IsSporkActive(int nSporkID)
{
Evan Duffield's avatar
Evan Duffield committed
80
    int64_t r = -1;
Evan Duffield's avatar
Evan Duffield committed
81
82

    if(mapSporksActive.count(nSporkID)){
83
        r = mapSporksActive[nSporkID].nValue;
Evan Duffield's avatar
Evan Duffield committed
84
85
86
    } else {
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
87
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
Alastair Clark's avatar
Alastair Clark committed
88
89
90
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
91
        if(nSporkID == SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES) r = SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES_DEFAULT;
92
        if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
93
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
Evan Duffield's avatar
Evan Duffield committed
94
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
Infernoman's avatar
Infernoman committed
95
        if(nSporkID == SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT) r = SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT_DEFAULT;
96
97
        if(nSporkID == SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES) r = SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES_DEFAULT;
        if(nSporkID == SPORK_16_DISCONNECT_OLD_NODES) r = SPORK_16_DISCONNECT_OLD_NODES_DEFAULT;
Evan Duffield's avatar
Evan Duffield committed
98

Evan Duffield's avatar
Evan Duffield committed
99
        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
Evan Duffield's avatar
Evan Duffield committed
100
    }
Ashot Khachatryan's avatar
Ashot Khachatryan committed
101
    if(r == -1) r = 4070908800; //return 2099-1-1 by default
Evan Duffield's avatar
Evan Duffield committed
102
103
104
105

    return r < GetTime();
}

106
// grab the value of the spork on the network, or the default
Evan Duffield's avatar
Evan Duffield committed
107
int64_t GetSporkValue(int nSporkID)
108
{
UdjinM6's avatar
UdjinM6 committed
109
    int64_t r = -1;
110
111
112
113
114
115
116

    if(mapSporksActive.count(nSporkID)){
        r = mapSporksActive[nSporkID].nValue;
    } else {
        if(nSporkID == SPORK_2_INSTANTX) r = SPORK_2_INSTANTX_DEFAULT;
        if(nSporkID == SPORK_3_INSTANTX_BLOCK_FILTERING) r = SPORK_3_INSTANTX_BLOCK_FILTERING_DEFAULT;
        if(nSporkID == SPORK_5_MAX_VALUE) r = SPORK_5_MAX_VALUE_DEFAULT;
Alastair Clark's avatar
Alastair Clark committed
117
118
119
        if(nSporkID == SPORK_7_MASTERNODE_SCANNING) r = SPORK_7_MASTERNODE_SCANNING_DEFAULT;
        if(nSporkID == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) r = SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT_DEFAULT;
        if(nSporkID == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) r = SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT_DEFAULT;
120
        if(nSporkID == SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES) r = SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES_DEFAULT;
121
        if(nSporkID == SPORK_11_RESET_BUDGET) r = SPORK_11_RESET_BUDGET_DEFAULT;
122
        if(nSporkID == SPORK_12_RECONSIDER_BLOCKS) r = SPORK_12_RECONSIDER_BLOCKS_DEFAULT;
Evan Duffield's avatar
Evan Duffield committed
123
        if(nSporkID == SPORK_13_ENABLE_SUPERBLOCKS) r = SPORK_13_ENABLE_SUPERBLOCKS_DEFAULT;
Infernoman's avatar
Infernoman committed
124
        if(nSporkID == SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT) r = SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT_DEFAULT;
125
126
        if(nSporkID == SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES) r = SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES_DEFAULT;
        if(nSporkID == SPORK_16_DISCONNECT_OLD_NODES) r = SPORK_16_DISCONNECT_OLD_NODES_DEFAULT;
127

UdjinM6's avatar
UdjinM6 committed
128
        if(r == -1) LogPrintf("GetSpork::Unknown Spork %d\n", nSporkID);
129
130
131
132
133
    }

    return r;
}

134
135
void ExecuteSpork(int nSporkID, int nValue)
{
136
137
    if (nSporkID == SPORK_11_RESET_BUDGET && nValue == 1)
    {
138
        budget.Clear();
139
    }
140
141
142
    else if (nSporkID == SPORK_12_RECONSIDER_BLOCKS && nValue > 0)
    {
        //correct fork via spork technology
Evan Duffield's avatar
Evan Duffield committed
143
144
145
        LogPrintf("Spork::ExecuteSpork -- Reconsider Last %d Blocks\n", nValue);
        ReprocessBlocks(nValue);
    }
146
147
148
149
150
151
152
153
154
    else if (nSporkID == SPORK_16_DISCONNECT_OLD_NODES && nValue == 1)
    {
        LOCK(cs_vNodes);
        for (auto node: vNodes)
        {
            if (node->nVersion < MinPeerProtoVersion())
                node->fDisconnect = true;
        }
    }
Evan Duffield's avatar
Evan Duffield committed
155
}
156

Evan Duffield's avatar
Evan Duffield committed
157
void ReprocessBlocks(int nBlocks) 
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
{   
    std::map<uint256, int64_t>::iterator it = mapRejectedBlocks.begin();
    while(it != mapRejectedBlocks.end()){
        //use a window twice as large as is usual for the nBlocks we want to reset
        if((*it).second  > GetTime() - (nBlocks*60*5)) {   
            BlockMap::iterator mi = mapBlockIndex.find((*it).first);
            if (mi != mapBlockIndex.end() && (*mi).second) {
                LOCK(cs_main);
                
                CBlockIndex* pindex = (*mi).second;
                LogPrintf("ReprocessBlocks - %s\n", (*it).first.ToString());

                CValidationState state;
                ReconsiderBlock(state, pindex);
            }
173
        }
174
        ++it;
Evan Duffield's avatar
Evan Duffield committed
175
176
177
178
179
180
181
182
183
184
    }

    CValidationState state;
    {
        LOCK(cs_main);
        DisconnectBlocksAndReprocess(nBlocks);
    }

    if (state.IsValid()) {
        ActivateBestChain(state);
185
    }
186
187
}

Evan Duffield's avatar
Evan Duffield committed
188
189
190
191

bool CSporkManager::CheckSignature(CSporkMessage& spork)
{
    //note: need to investigate why this is failing
192
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
193
    CPubKey pubkey(ParseHex(Params().SporkKey()));
Evan Duffield's avatar
Evan Duffield committed
194
195

    std::string errorMessage = "";
Alastair Clark's avatar
renames    
Alastair Clark committed
196
    if(!legacySigner.VerifyMessage(pubkey, spork.vchSig, strMessage, errorMessage)){
Evan Duffield's avatar
Evan Duffield committed
197
198
199
200
201
202
203
204
        return false;
    }

    return true;
}

bool CSporkManager::Sign(CSporkMessage& spork)
{
205
    std::string strMessage = boost::lexical_cast<std::string>(spork.nSporkID) + boost::lexical_cast<std::string>(spork.nValue) + boost::lexical_cast<std::string>(spork.nTimeSigned);
Evan Duffield's avatar
Evan Duffield committed
206
207
208
209
210

    CKey key2;
    CPubKey pubkey2;
    std::string errorMessage = "";

Alastair Clark's avatar
renames    
Alastair Clark committed
211
    if(!legacySigner.SetKey(strMasterPrivKey, errorMessage, key2, pubkey2))
Evan Duffield's avatar
Evan Duffield committed
212
    {
Alastair Clark's avatar
Alastair Clark committed
213
        LogPrintf("CMasternodePayments::Sign - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage);
Evan Duffield's avatar
Evan Duffield committed
214
215
216
        return false;
    }

Alastair Clark's avatar
renames    
Alastair Clark committed
217
    if(!legacySigner.SignMessage(strMessage, errorMessage, spork.vchSig, key2)) {
Alastair Clark's avatar
Alastair Clark committed
218
        LogPrintf("CMasternodePayments::Sign - Sign message failed");
Evan Duffield's avatar
Evan Duffield committed
219
220
221
        return false;
    }

Alastair Clark's avatar
renames    
Alastair Clark committed
222
    if(!legacySigner.VerifyMessage(pubkey2, spork.vchSig, strMessage, errorMessage)) {
Alastair Clark's avatar
Alastair Clark committed
223
        LogPrintf("CMasternodePayments::Sign - Verify message failed");
Evan Duffield's avatar
Evan Duffield committed
224
225
226
227
228
229
        return false;
    }

    return true;
}

230
bool CSporkManager::UpdateSpork(int nSporkID, int64_t nValue)
Evan Duffield's avatar
Evan Duffield committed
231
232
233
234
{

    CSporkMessage msg;
    msg.nSporkID = nSporkID;
235
    msg.nValue = nValue;
Evan Duffield's avatar
Evan Duffield committed
236
237
238
239
240
    msg.nTimeSigned = GetTime();

    if(Sign(msg)){
        Relay(msg);
        mapSporks[msg.GetHash()] = msg;
241
        mapSporksActive[nSporkID] = msg;
Evan Duffield's avatar
Evan Duffield committed
242
243
244
245
246
247
248
249
250
        return true;
    }

    return false;
}

void CSporkManager::Relay(CSporkMessage& msg)
{
    CInv inv(MSG_SPORK, msg.GetHash());
251
    RelayInv(inv, MIN_PEER_PROTO_VERSION_PREV); // to make sure SPORK_16_DISCONNECT_OLD_NODES will be relayed
Evan Duffield's avatar
Evan Duffield committed
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
}

bool CSporkManager::SetPrivKey(std::string strPrivKey)
{
    CSporkMessage msg;

    // Test signing successful, proceed
    strMasterPrivKey = strPrivKey;

    Sign(msg);

    if(CheckSignature(msg)){
        LogPrintf("CSporkManager::SetPrivKey - Successfully initialized as spork signer\n");
        return true;
    } else {
        return false;
    }
}

int CSporkManager::GetSporkIDByName(std::string strName)
{
    if(strName == "SPORK_2_INSTANTX") return SPORK_2_INSTANTX;
    if(strName == "SPORK_3_INSTANTX_BLOCK_FILTERING") return SPORK_3_INSTANTX_BLOCK_FILTERING;
275
    if(strName == "SPORK_5_MAX_VALUE") return SPORK_5_MAX_VALUE;
Alastair Clark's avatar
Alastair Clark committed
276
277
278
    if(strName == "SPORK_7_MASTERNODE_SCANNING") return SPORK_7_MASTERNODE_SCANNING;
    if(strName == "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT") return SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT;
    if(strName == "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT") return SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT;
279
    if(strName == "SPORK_10_MASTERNODE_PAY_UPDATED_NODES") return SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES;
280
    if(strName == "SPORK_11_RESET_BUDGET") return SPORK_11_RESET_BUDGET;
281
    if(strName == "SPORK_12_RECONSIDER_BLOCKS") return SPORK_12_RECONSIDER_BLOCKS;
Evan Duffield's avatar
Evan Duffield committed
282
    if(strName == "SPORK_13_ENABLE_SUPERBLOCKS") return SPORK_13_ENABLE_SUPERBLOCKS;
Infernoman's avatar
Infernoman committed
283
    if(strName == "SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT") return SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT;
284
285
    if(strName == "SPORK_15_SYSTEMNODE_PAY_UPDATED_NODES") return SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES;
    if(strName == "SPORK_16_DISCONNECT_OLD_NODES") return SPORK_16_DISCONNECT_OLD_NODES;
Evan Duffield's avatar
Evan Duffield committed
286
287
288
289
290
291
292
293

    return -1;
}

std::string CSporkManager::GetSporkNameByID(int id)
{
    if(id == SPORK_2_INSTANTX) return "SPORK_2_INSTANTX";
    if(id == SPORK_3_INSTANTX_BLOCK_FILTERING) return "SPORK_3_INSTANTX_BLOCK_FILTERING";
294
    if(id == SPORK_5_MAX_VALUE) return "SPORK_5_MAX_VALUE";
Alastair Clark's avatar
Alastair Clark committed
295
296
297
    if(id == SPORK_7_MASTERNODE_SCANNING) return "SPORK_7_MASTERNODE_SCANNING";
    if(id == SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT) return "SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT";
    if(id == SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT) return "SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT";
298
    if(id == SPORK_10_MASTERNODE_DONT_PAY_OLD_NODES) return "SPORK_10_MASTERNODE_PAY_UPDATED_NODES";
299
    if(id == SPORK_11_RESET_BUDGET) return "SPORK_11_RESET_BUDGET";
300
    if(id == SPORK_12_RECONSIDER_BLOCKS) return "SPORK_12_RECONSIDER_BLOCKS";
Evan Duffield's avatar
Evan Duffield committed
301
    if(id == SPORK_13_ENABLE_SUPERBLOCKS) return "SPORK_13_ENABLE_SUPERBLOCKS";
Infernoman's avatar
Infernoman committed
302
    if(id == SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT) return "SPORK_14_SYSTEMNODE_PAYMENT_ENFORCEMENT";
303
304
    if(id == SPORK_15_SYSTEMNODE_DONT_PAY_OLD_NODES) return "SPORK_15_SYSTEMNODE_PAY_UPDATED_NODES";
    if(id == SPORK_16_DISCONNECT_OLD_NODES) return "SPORK_16_DISCONNECT_OLD_NODES";
Evan Duffield's avatar
Evan Duffield committed
305
306

    return "Unknown";
307
}