Michael Toutonghi
6 years ago
12 changed files with 234 additions and 183 deletions
@ -0,0 +1,133 @@ |
|||
/********************************************************************
|
|||
* (C) 2018 Michael Toutonghi |
|||
* |
|||
* Distributed under the MIT software license, see the accompanying |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
* |
|||
* This crypto-condition eval solves the problem of nothing-at-stake |
|||
* in a proof of stake consensus system. |
|||
* |
|||
*/ |
|||
|
|||
#include "cc/StakeGuard.h" |
|||
#include "script/script.h" |
|||
#include "main.h" |
|||
#include "hash.h" |
|||
#include "cheatcatcher.h" |
|||
#include "streams.h" |
|||
|
|||
using namespace std; |
|||
|
|||
CCheatList cheatList; |
|||
boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher; |
|||
|
|||
uint32_t CCheatList::Prune(uint32_t height) |
|||
{ |
|||
uint32_t count; |
|||
pair<multimap<const uint32_t, CTxHolder>::iterator, multimap<const uint32_t, CTxHolder>::iterator> range; |
|||
vector<CTxHolder *> toPrune; |
|||
|
|||
if (NetworkUpgradeActive(height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) |
|||
{ |
|||
LOCK(cs_cheat); |
|||
for (auto it = orderedCheatCandidates.begin(); it != orderedCheatCandidates.end() && it->second.height <= height; it--) |
|||
{ |
|||
toPrune.push_back(&it->second); |
|||
} |
|||
count = toPrune.size(); |
|||
for (auto ptxHolder : toPrune) |
|||
{ |
|||
Remove(*ptxHolder); |
|||
} |
|||
} |
|||
return count; // return how many removed
|
|||
} |
|||
|
|||
bool GetStakeParams(const CTransaction &stakeTx, CStakeParams &stakeParams); |
|||
|
|||
bool CCheatList::IsCheatInList(const CTransaction &tx, CTransaction *cheatTx) |
|||
{ |
|||
// for a tx to be cheat, it needs to spend the same UTXO and be for a different prior block
|
|||
// the list should be pruned before this call
|
|||
// we return the first valid cheat we find
|
|||
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); |
|||
|
|||
hw << tx.vin[0].prevout.hash; |
|||
hw << tx.vin[0].prevout.n; |
|||
uint256 utxo = hw.GetHash(); |
|||
|
|||
pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range; |
|||
CStakeParams p, s; |
|||
|
|||
if (GetStakeParams(tx, p)) |
|||
{ |
|||
LOCK(cs_cheat); |
|||
range = indexedCheatCandidates.equal_range(utxo); |
|||
for (auto it = range.first; it != range.second; it++) |
|||
{ |
|||
// we assume height is valid, as we should have pruned the list before checking. since the tx came out of a valid block,
|
|||
// what matters is if the prior hash matches
|
|||
CTransaction &cTx = it->second->tx; |
|||
|
|||
// need both parameters to check
|
|||
if (GetStakeParams(cTx, s)) |
|||
{ |
|||
if (p.prevHash != s.prevHash) |
|||
{ |
|||
cheatTx = &cTx; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
bool CCheatList::Add(CTxHolder &txh) |
|||
{ |
|||
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); |
|||
if (NetworkUpgradeActive(txh.height, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) |
|||
{ |
|||
LOCK(cs_cheat); |
|||
auto it = orderedCheatCandidates.insert(pair<const uint32_t, CTxHolder>(txh.height, txh)); |
|||
indexedCheatCandidates.insert(pair<const uint256, CTxHolder *>(txh.utxo, &it->second)); |
|||
} |
|||
} |
|||
|
|||
void CCheatList::Remove(const CTxHolder &txh) |
|||
{ |
|||
// first narrow by source tx, then compare with tx hash
|
|||
uint32_t count; |
|||
pair<multimap<const uint256, CTxHolder *>::iterator, multimap<const uint256, CTxHolder *>::iterator> range; |
|||
vector<multimap<const uint256, CTxHolder *>::iterator> utxoPrune; |
|||
vector<multimap<const int32_t, CTxHolder>::iterator> heightPrune; |
|||
|
|||
{ |
|||
LOCK(cs_cheat); |
|||
range = indexedCheatCandidates.equal_range(txh.utxo); |
|||
for (auto it = range.first; it != range.second; it++) |
|||
{ |
|||
uint256 hash = txh.tx.GetHash(); |
|||
if (hash == it->second->tx.GetHash()) |
|||
{ |
|||
utxoPrune.push_back(it); |
|||
auto hrange = orderedCheatCandidates.equal_range(it->second->height); |
|||
for (auto hit = hrange.first; hit != hrange.second; hit++) |
|||
{ |
|||
if (hit->second.tx.GetHash() == hash) |
|||
{ |
|||
heightPrune.push_back(hit); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
for (auto it : utxoPrune) |
|||
{ |
|||
indexedCheatCandidates.erase(it); |
|||
} |
|||
for (auto it : heightPrune) |
|||
{ |
|||
orderedCheatCandidates.erase(it); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,74 @@ |
|||
/********************************************************************
|
|||
* (C) 2018 Michael Toutonghi |
|||
* |
|||
* Distributed under the MIT software license, see the accompanying |
|||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|||
* |
|||
* This crypto-condition eval solves the problem of nothing-at-stake |
|||
* in a proof of stake consensus system. |
|||
* |
|||
*/ |
|||
|
|||
#ifndef CHEATCATCHER_H |
|||
#define CHEATCATCHER_H |
|||
|
|||
#include <vector> |
|||
|
|||
#include "streams.h" |
|||
#include "script/script.h" |
|||
#include "uint256.h" |
|||
|
|||
#include <vector> |
|||
#include <map> |
|||
|
|||
class CTxHolder |
|||
{ |
|||
public: |
|||
uint256 utxo; |
|||
uint32_t height; |
|||
CTransaction tx; |
|||
CTxHolder(const CTransaction &_tx, uint32_t _height) : height(_height), tx(_tx) { |
|||
CVerusHashWriter hw = CVerusHashWriter(SER_GETHASH, PROTOCOL_VERSION); |
|||
|
|||
hw << tx.vin[0].prevout.hash; |
|||
hw << tx.vin[0].prevout.n; |
|||
utxo = hw.GetHash(); |
|||
} |
|||
}; |
|||
|
|||
|
|||
class CCheatList |
|||
{ |
|||
private: |
|||
std::multimap<const int32_t, CTxHolder> orderedCheatCandidates; |
|||
std::multimap<const uint256, CTxHolder *> indexedCheatCandidates; |
|||
CCriticalSection cs_cheat; |
|||
|
|||
public: |
|||
CCheatList() {} |
|||
|
|||
// prune all transactions in the list below height
|
|||
uint32_t Prune(uint32_t height); |
|||
|
|||
// check to see if a transaction that could be a cheat for the passed transaction is in our list
|
|||
bool IsCheatInList(const CTransaction &tx, CTransaction *pcheatTx); |
|||
|
|||
// check to see if there are cheat candidates of the same or greater block height in list
|
|||
bool IsHeightOrGreaterInList(uint32_t height) |
|||
{ |
|||
auto range = orderedCheatCandidates.equal_range(height); |
|||
return (range.first == orderedCheatCandidates.end()); |
|||
} |
|||
|
|||
// add a potential cheat transaction to the list. we do this for all stake transactions from orphaned stakes
|
|||
bool Add(CTxHolder &txh); |
|||
|
|||
// remove a transaction from the the list
|
|||
void Remove(const CTxHolder &txh); |
|||
}; |
|||
|
|||
|
|||
extern CCheatList cheatList; |
|||
extern boost::optional<libzcash::SaplingPaymentAddress> cheatCatcher; |
|||
|
|||
#endif |
Loading…
Reference in new issue