]> Git Repo - VerusCoin.git/blob - src/cheatcatcher.cpp
Avoid any potential double staking penalty that make occur during repeated reorgs
[VerusCoin.git] / src / cheatcatcher.cpp
1 /********************************************************************
2  * (C) 2018 Michael Toutonghi
3  * 
4  * Distributed under the MIT software license, see the accompanying
5  * file COPYING or http://www.opensource.org/licenses/mit-license.php.
6  * 
7  * This supports code to catch nothing at stake cheaters who stake
8  * on multiple forks.
9  * 
10  */
11
12 #include "cc/StakeGuard.h"
13 #include "script/script.h"
14 #include "main.h"
15 #include "hash.h"
16 #include "cheatcatcher.h"
17 #include "streams.h"
18
19 using namespace std;
20
21 CCheatList cheatList;
22 boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
23
24 uint32_t CCheatList::Prune(uint32_t height)
25 {
26     uint32_t count = 0;
27     pair<multimap<const uint32_t, CTxHolder>::iterator, multimap<const uint32_t, CTxHolder>::iterator> range;
28     vector<CTxHolder *> toPrune;
29
30     if (height > 0 && NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
31     {
32         LOCK(cs_cheat);
33         for (auto it = orderedCheatCandidates.begin(); it != orderedCheatCandidates.end() && it->second.height <= height; it--)
34         {
35             toPrune.push_back(&it->second);
36         }
37         count = toPrune.size();
38         for (auto ptxHolder : toPrune)
39         {
40             Remove(*ptxHolder);
41         }
42     }
43     return count;   // return how many removed
44 }
45
46 bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
47
48 bool CCheatList::IsHeightOrGreaterInList(uint32_t height)
49 {
50     auto range = orderedCheatCandidates.equal_range(height);
51     //printf("IsHeightOrGreaterInList: %s\n", range.second == orderedCheatCandidates.end() ? "false" : "true");
52     return (range.first != orderedCheatCandidates.end() || range.second != orderedCheatCandidates.end());
53 }
54
55 bool CCheatList::IsCheatInList(const CTransaction &tx, CTransaction *cheatTx)
56 {
57     // for a tx to be cheat, it needs to spend the same UTXO and be for a different prior block
58     // the list should be pruned before this call
59     // we return the first valid cheat we find
60     CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
61
62     hw << tx.vin[0].prevout.hash;
63     hw << tx.vin[0].prevout.n;
64     uint256 utxo = hw.GetHash();
65
66     pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
67     CStakeParams p, s;
68
69     if (GetStakeParams(tx, p))
70     {
71         LOCK(cs_cheat);
72         range = indexedCheatCandidates.equal_range(utxo);
73
74         //printf("IsCheatInList - found candidates: %s\n", range.first == range.second ? "false" : "true");
75
76         for (auto it = range.first; it != range.second; it++)
77         {
78             CTransaction &cTx = it->second->tx;
79             //printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
80
81             // need both parameters to check
82             if (GetStakeParams(cTx, s))
83             {
84                 if (p.prevHash != s.prevHash && s.blkHeight >= p.blkHeight)
85                 {
86                     *cheatTx = cTx;
87                     return true;
88                 }
89             }
90         }
91     }
92     return false;
93 }
94
95 bool CCheatList::IsUTXOInList(COutPoint _utxo, uint32_t height)
96 {
97     // for a tx to be cheat, it needs to spend the same UTXO and be for a different prior block
98     // the list should be pruned before this call
99     // we return the first valid cheat we find
100     CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION);
101
102     hw << _utxo.hash;
103     hw << _utxo.n;
104     uint256 utxo = hw.GetHash();
105
106     pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
107     CStakeParams p, s;
108
109     LOCK(cs_cheat);
110     range = indexedCheatCandidates.equal_range(utxo);
111
112     for (auto it = range.first; it != range.second; it++)
113     {
114         CTransaction &cTx = it->second->tx;
115         //printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
116
117         // need both parameters to check
118         if (GetStakeParams(cTx, s))
119         {
120             if (s.blkHeight >= height)
121             {
122                 return true;
123             }
124         }
125     }
126     return false;
127 }
128
129 bool CCheatList::Add(const CTxHolder &txh)
130 {
131     if (NetworkUpgradeActive(txh.height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
132     {
133         LOCK(cs_cheat);
134         auto it = orderedCheatCandidates.insert(pair<const uint32_t, CTxHolder>(txh.height, txh));
135         indexedCheatCandidates.insert(pair<const uint256, CTxHolder *>(txh.utxo, &it->second));
136         //printf("CCheatList::Add orderedCheatCandidates.size: %d, indexedCheatCandidates.size: %d\n", (int)orderedCheatCandidates.size(), (int)indexedCheatCandidates.size());
137     }
138 }
139
140 void CCheatList::Remove(const CTxHolder &txh)
141 {
142     // first narrow by source tx, then compare with tx hash
143     uint32_t count;
144     pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
145     vector<multimap<const uint256, CTxHolder *>::iterator> utxoPrune;
146     vector<multimap<const int32_t, CTxHolder>::iterator> heightPrune;
147
148     {
149         LOCK(cs_cheat);
150         range = indexedCheatCandidates.equal_range(txh.utxo);
151         for (auto it = range.first; it != range.second; it++)
152         {
153             uint256 hash = txh.tx.GetHash();
154             if (hash == it->second->tx.GetHash())
155             {
156                 auto hrange = orderedCheatCandidates.equal_range(it->second->height);
157                 for (auto hit = hrange.first; hit != hrange.second; hit++)
158                 {
159                     if (hit->second.tx.GetHash() == hash)
160                     {
161                         // add and remove them together
162                         utxoPrune.push_back(it);
163                         heightPrune.push_back(hit);
164                     }
165                 }
166             }
167         }
168         for (auto it : utxoPrune)
169         {
170             indexedCheatCandidates.erase(it);
171         }
172         for (auto it : heightPrune)
173         {
174             orderedCheatCandidates.erase(it);
175         }
176     }
177 }
This page took 0.033289 seconds and 4 git commands to generate.