]>
Commit | Line | Data |
---|---|---|
8fc4030c MT |
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 | * | |
16ef4f1e | 7 | * This supports code to catch nothing at stake cheaters who stake |
8 | * on multiple forks. | |
8fc4030c MT |
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 | { | |
10214558 | 26 | uint32_t count = 0; |
8fc4030c MT |
27 | pair<multimap<const uint32_t, CTxHolder>::iterator, multimap<const uint32_t, CTxHolder>::iterator> range; |
28 | vector<CTxHolder *> toPrune; | |
29 | ||
10214558 | 30 | if (height > 0 && NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) |
8fc4030c MT |
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 | ||
1ca4abe4 | 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"); | |
56ac817f | 52 | return (range.first != orderedCheatCandidates.end() || range.second != orderedCheatCandidates.end()); |
1ca4abe4 | 53 | } |
54 | ||
8fc4030c MT |
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); | |
bb3d3ab7 | 73 | |
83a426bc | 74 | //printf("IsCheatInList - found candidates: %s\n", range.first == range.second ? "false" : "true"); |
bb3d3ab7 | 75 | |
8fc4030c MT |
76 | for (auto it = range.first; it != range.second; it++) |
77 | { | |
8fc4030c | 78 | CTransaction &cTx = it->second->tx; |
6c621e0e | 79 | //printf("cTx::opret : %s\n", cTx.vout[1].scriptPubKey.ToString().c_str()); |
8fc4030c MT |
80 | |
81 | // need both parameters to check | |
82 | if (GetStakeParams(cTx, s)) | |
83 | { | |
8c3a9bc7 | 84 | if (p.prevHash != s.prevHash && s.blkHeight >= p.blkHeight) |
8fc4030c | 85 | { |
3abeed2c | 86 | *cheatTx = cTx; |
8fc4030c MT |
87 | return true; |
88 | } | |
89 | } | |
90 | } | |
91 | } | |
92 | return false; | |
93 | } | |
94 | ||
43260416 | 95 | bool CCheatList::Add(const CTxHolder &txh) |
8fc4030c | 96 | { |
8fc4030c MT |
97 | if (NetworkUpgradeActive(txh.height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) |
98 | { | |
99 | LOCK(cs_cheat); | |
100 | auto it = orderedCheatCandidates.insert(pair<const uint32_t, CTxHolder>(txh.height, txh)); | |
101 | indexedCheatCandidates.insert(pair<const uint256, CTxHolder *>(txh.utxo, &it->second)); | |
ec8a120b | 102 | //printf("CCheatList::Add orderedCheatCandidates.size: %d, indexedCheatCandidates.size: %d\n", (int)orderedCheatCandidates.size(), (int)indexedCheatCandidates.size()); |
8fc4030c MT |
103 | } |
104 | } | |
105 | ||
106 | void CCheatList::Remove(const CTxHolder &txh) | |
107 | { | |
108 | // first narrow by source tx, then compare with tx hash | |
109 | uint32_t count; | |
110 | pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range; | |
111 | vector<multimap<const uint256, CTxHolder *>::iterator> utxoPrune; | |
112 | vector<multimap<const int32_t, CTxHolder>::iterator> heightPrune; | |
113 | ||
114 | { | |
115 | LOCK(cs_cheat); | |
116 | range = indexedCheatCandidates.equal_range(txh.utxo); | |
117 | for (auto it = range.first; it != range.second; it++) | |
118 | { | |
119 | uint256 hash = txh.tx.GetHash(); | |
120 | if (hash == it->second->tx.GetHash()) | |
121 | { | |
8fc4030c MT |
122 | auto hrange = orderedCheatCandidates.equal_range(it->second->height); |
123 | for (auto hit = hrange.first; hit != hrange.second; hit++) | |
124 | { | |
125 | if (hit->second.tx.GetHash() == hash) | |
126 | { | |
bb3d3ab7 | 127 | // add and remove them together |
128 | utxoPrune.push_back(it); | |
8fc4030c MT |
129 | heightPrune.push_back(hit); |
130 | } | |
131 | } | |
132 | } | |
133 | } | |
134 | for (auto it : utxoPrune) | |
135 | { | |
136 | indexedCheatCandidates.erase(it); | |
137 | } | |
138 | for (auto it : heightPrune) | |
139 | { | |
140 | orderedCheatCandidates.erase(it); | |
141 | } | |
142 | } | |
143 | } |