1 /********************************************************************
2 * (C) 2018 Michael Toutonghi
4 * Distributed under the MIT software license, see the accompanying
5 * file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 * This supports code to catch nothing at stake cheaters who stake
12 #include "cc/StakeGuard.h"
13 #include "script/script.h"
16 #include "cheatcatcher.h"
22 boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher;
24 uint32_t CCheatList::Prune(uint32_t height)
27 pair<multimap<const uint32_t, CTxHolder>::iterator, multimap<const uint32_t, CTxHolder>::iterator> range;
28 vector<CTxHolder *> toPrune;
30 if (height > 0 && NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
33 for (auto it = orderedCheatCandidates.begin(); it != orderedCheatCandidates.end() && it->second.height <= height; it--)
35 toPrune.push_back(&it->second);
37 count = toPrune.size();
38 for (auto ptxHolder : toPrune)
43 return count; // return how many removed
46 bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams);
48 bool CCheatList::IsHeightOrGreaterInList(uint32_t height)
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());
55 bool CCheatList::IsCheatInList(const CTransaction &tx, CTransaction *cheatTx)
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);
62 hw << tx.vin[0].prevout.hash;
63 hw << tx.vin[0].prevout.n;
64 uint256 utxo = hw.GetHash();
66 pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
69 if (GetStakeParams(tx, p))
72 range = indexedCheatCandidates.equal_range(utxo);
74 //printf("IsCheatInList - found candidates: %s\n", range.first == range.second ? "false" : "true");
76 for (auto it = range.first; it != range.second; it++)
78 CTransaction &cTx = it->second->tx;
79 //printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
81 // need both parameters to check
82 if (GetStakeParams(cTx, s))
84 if (p.prevHash != s.prevHash && s.blkHeight >= p.blkHeight)
95 bool CCheatList::IsUTXOInList(COutPoint _utxo, uint32_t height)
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);
104 uint256 utxo = hw.GetHash();
106 pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range;
110 range = indexedCheatCandidates.equal_range(utxo);
112 for (auto it = range.first; it != range.second; it++)
114 CTransaction &cTx = it->second->tx;
115 //printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str());
117 // need both parameters to check
118 if (GetStakeParams(cTx, s))
120 if (s.blkHeight >= height)
129 bool CCheatList::Add(const CTxHolder &txh)
131 if (NetworkUpgradeActive(txh.height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING))
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());
140 void CCheatList::Remove(const CTxHolder &txh)
142 // first narrow by source tx, then compare with tx hash
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;
150 range = indexedCheatCandidates.equal_range(txh.utxo);
151 for (auto it = range.first; it != range.second; it++)
153 uint256 hash = txh.tx.GetHash();
154 if (hash == it->second->tx.GetHash())
156 auto hrange = orderedCheatCandidates.equal_range(it->second->height);
157 for (auto hit = hrange.first; hit != hrange.second; hit++)
159 if (hit->second.tx.GetHash() == hash)
161 // add and remove them together
162 utxoPrune.push_back(it);
163 heightPrune.push_back(hit);
168 for (auto it : utxoPrune)
170 indexedCheatCandidates.erase(it);
172 for (auto it : heightPrune)
174 orderedCheatCandidates.erase(it);