New vote tallying implementation (#1135)
This commit is contained in:
parent
82ca5fdbb8
commit
c31ba8ba4c
@ -74,6 +74,8 @@ BITCOIN_CORE_H = \
|
|||||||
arith_uint256.h \
|
arith_uint256.h \
|
||||||
base58.h \
|
base58.h \
|
||||||
bloom.h \
|
bloom.h \
|
||||||
|
cachemap.h \
|
||||||
|
cachemultimap.h \
|
||||||
chain.h \
|
chain.h \
|
||||||
chainparams.h \
|
chainparams.h \
|
||||||
chainparamsbase.h \
|
chainparamsbase.h \
|
||||||
@ -99,7 +101,9 @@ BITCOIN_CORE_H = \
|
|||||||
darksend-relay.h \
|
darksend-relay.h \
|
||||||
governance.h \
|
governance.h \
|
||||||
governance-classes.h \
|
governance-classes.h \
|
||||||
|
governance-exceptions.h \
|
||||||
governance-vote.h \
|
governance-vote.h \
|
||||||
|
governance-votedb.h \
|
||||||
flat-database.h \
|
flat-database.h \
|
||||||
hash.h \
|
hash.h \
|
||||||
httprpc.h \
|
httprpc.h \
|
||||||
@ -202,6 +206,7 @@ libbitcoin_server_a_SOURCES = \
|
|||||||
governance.cpp \
|
governance.cpp \
|
||||||
governance-classes.cpp \
|
governance-classes.cpp \
|
||||||
governance-vote.cpp \
|
governance-vote.cpp \
|
||||||
|
governance-votedb.cpp \
|
||||||
main.cpp \
|
main.cpp \
|
||||||
merkleblock.cpp \
|
merkleblock.cpp \
|
||||||
miner.cpp \
|
miner.cpp \
|
||||||
|
@ -43,6 +43,8 @@ BITCOIN_TESTS =\
|
|||||||
test/base64_tests.cpp \
|
test/base64_tests.cpp \
|
||||||
test/bip32_tests.cpp \
|
test/bip32_tests.cpp \
|
||||||
test/bloom_tests.cpp \
|
test/bloom_tests.cpp \
|
||||||
|
test/cachemap_tests.cpp \
|
||||||
|
test/cachemultimap_tests.cpp \
|
||||||
test/checkblock_tests.cpp \
|
test/checkblock_tests.cpp \
|
||||||
test/Checkpoints_tests.cpp \
|
test/Checkpoints_tests.cpp \
|
||||||
test/coins_tests.cpp \
|
test/coins_tests.cpp \
|
||||||
|
@ -271,6 +271,7 @@ void CActiveMasternode::ManageStateLocal()
|
|||||||
//update to masternode list
|
//update to masternode list
|
||||||
LogPrintf("CActiveMasternode::ManageStateLocal -- Update Masternode List\n");
|
LogPrintf("CActiveMasternode::ManageStateLocal -- Update Masternode List\n");
|
||||||
mnodeman.UpdateMasternodeList(mnb);
|
mnodeman.UpdateMasternodeList(mnb);
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
|
|
||||||
//send to all peers
|
//send to all peers
|
||||||
LogPrintf("CActiveMasternode::ManageStateLocal -- Relay broadcast, vin=%s\n", vin.ToString());
|
LogPrintf("CActiveMasternode::ManageStateLocal -- Relay broadcast, vin=%s\n", vin.ToString());
|
||||||
|
202
src/cachemap.h
Normal file
202
src/cachemap.h
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef CACHEMAP_H_
|
||||||
|
#define CACHEMAP_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializable structure for key/value items
|
||||||
|
*/
|
||||||
|
template<typename K, typename V>
|
||||||
|
struct CacheItem
|
||||||
|
{
|
||||||
|
CacheItem()
|
||||||
|
{}
|
||||||
|
|
||||||
|
CacheItem(const K& keyIn, const V& valueIn)
|
||||||
|
: key(keyIn),
|
||||||
|
value(valueIn)
|
||||||
|
{}
|
||||||
|
|
||||||
|
K key;
|
||||||
|
V value;
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(key);
|
||||||
|
READWRITE(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map like container that keeps the N most recently added items
|
||||||
|
*/
|
||||||
|
template<typename K, typename V, typename Size = uint32_t>
|
||||||
|
class CacheMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Size size_type;
|
||||||
|
|
||||||
|
typedef CacheItem<K,V> item_t;
|
||||||
|
|
||||||
|
typedef std::list<item_t> list_t;
|
||||||
|
|
||||||
|
typedef typename list_t::iterator list_it;
|
||||||
|
|
||||||
|
typedef typename list_t::const_iterator list_cit;
|
||||||
|
|
||||||
|
typedef std::map<K, list_it> map_t;
|
||||||
|
|
||||||
|
typedef typename map_t::iterator map_it;
|
||||||
|
|
||||||
|
typedef typename map_t::const_iterator map_cit;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_type nMaxSize;
|
||||||
|
|
||||||
|
size_type nCurrentSize;
|
||||||
|
|
||||||
|
list_t listItems;
|
||||||
|
|
||||||
|
map_t mapIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CacheMap(size_type nMaxSizeIn = 0)
|
||||||
|
: nMaxSize(nMaxSizeIn),
|
||||||
|
nCurrentSize(0),
|
||||||
|
listItems(),
|
||||||
|
mapIndex()
|
||||||
|
{}
|
||||||
|
|
||||||
|
CacheMap(const CacheMap<K,V>& other)
|
||||||
|
: nMaxSize(other.nMaxSize),
|
||||||
|
nCurrentSize(other.nCurrentSize),
|
||||||
|
listItems(other.listItems),
|
||||||
|
mapIndex()
|
||||||
|
{
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
mapIndex.clear();
|
||||||
|
listItems.clear();
|
||||||
|
nCurrentSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMaxSize(size_type nMaxSizeIn)
|
||||||
|
{
|
||||||
|
nMaxSize = nMaxSizeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type GetMaxSize() const {
|
||||||
|
return nMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type GetSize() const {
|
||||||
|
return nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Insert(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
map_it it = mapIndex.find(key);
|
||||||
|
if(it != mapIndex.end()) {
|
||||||
|
item_t& item = *(it->second);
|
||||||
|
item.value = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(nCurrentSize == nMaxSize) {
|
||||||
|
PruneLast();
|
||||||
|
}
|
||||||
|
listItems.push_front(item_t(key, value));
|
||||||
|
mapIndex[key] = listItems.begin();
|
||||||
|
++nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasKey(const K& key) const
|
||||||
|
{
|
||||||
|
map_cit it = mapIndex.find(key);
|
||||||
|
return (it != mapIndex.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Get(const K& key, V& value) const
|
||||||
|
{
|
||||||
|
map_cit it = mapIndex.find(key);
|
||||||
|
if(it == mapIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
item_t& item = *(it->second);
|
||||||
|
value = item.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const K& key)
|
||||||
|
{
|
||||||
|
map_it it = mapIndex.find(key);
|
||||||
|
if(it == mapIndex.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
listItems.erase(it->second);
|
||||||
|
mapIndex.erase(it);
|
||||||
|
--nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const list_t& GetItemList() const {
|
||||||
|
return listItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheMap<K,V>& operator=(const CacheMap<K,V>& other)
|
||||||
|
{
|
||||||
|
nMaxSize = other.nMaxSize;
|
||||||
|
nCurrentSize = other.nCurrentSize;
|
||||||
|
listItems = other.listItems;
|
||||||
|
RebuildIndex();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(nMaxSize);
|
||||||
|
READWRITE(nCurrentSize);
|
||||||
|
READWRITE(listItems);
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PruneLast()
|
||||||
|
{
|
||||||
|
if(nCurrentSize < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item_t& item = listItems.back();
|
||||||
|
mapIndex.erase(item.key);
|
||||||
|
listItems.pop_back();
|
||||||
|
--nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RebuildIndex()
|
||||||
|
{
|
||||||
|
mapIndex.clear();
|
||||||
|
for(list_it it = listItems.begin(); it != listItems.end(); ++it) {
|
||||||
|
mapIndex[it->key] = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CACHEMAP_H_ */
|
254
src/cachemultimap.h
Normal file
254
src/cachemultimap.h
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef CACHEMULTIMAP_H_
|
||||||
|
#define CACHEMULTIMAP_H_
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "serialize.h"
|
||||||
|
|
||||||
|
#include "cachemap.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map like container that keeps the N most recently added items
|
||||||
|
*/
|
||||||
|
template<typename K, typename V, typename Size = uint32_t>
|
||||||
|
class CacheMultiMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Size size_type;
|
||||||
|
|
||||||
|
typedef CacheItem<K,V> item_t;
|
||||||
|
|
||||||
|
typedef std::list<item_t> list_t;
|
||||||
|
|
||||||
|
typedef typename list_t::iterator list_it;
|
||||||
|
|
||||||
|
typedef typename list_t::const_iterator list_cit;
|
||||||
|
|
||||||
|
typedef std::map<V,list_it> it_map_t;
|
||||||
|
|
||||||
|
typedef typename it_map_t::iterator it_map_it;
|
||||||
|
|
||||||
|
typedef typename it_map_t::const_iterator it_map_cit;
|
||||||
|
|
||||||
|
typedef std::map<K, it_map_t> map_t;
|
||||||
|
|
||||||
|
typedef typename map_t::iterator map_it;
|
||||||
|
|
||||||
|
typedef typename map_t::const_iterator map_cit;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_type nMaxSize;
|
||||||
|
|
||||||
|
size_type nCurrentSize;
|
||||||
|
|
||||||
|
list_t listItems;
|
||||||
|
|
||||||
|
map_t mapIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CacheMultiMap(size_type nMaxSizeIn = 0)
|
||||||
|
: nMaxSize(nMaxSizeIn),
|
||||||
|
nCurrentSize(0),
|
||||||
|
listItems(),
|
||||||
|
mapIndex()
|
||||||
|
{}
|
||||||
|
|
||||||
|
CacheMultiMap(const CacheMap<K,V>& other)
|
||||||
|
: nMaxSize(other.nMaxSize),
|
||||||
|
nCurrentSize(other.nCurrentSize),
|
||||||
|
listItems(other.listItems),
|
||||||
|
mapIndex()
|
||||||
|
{
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
mapIndex.clear();
|
||||||
|
listItems.clear();
|
||||||
|
nCurrentSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetMaxSize(size_type nMaxSizeIn)
|
||||||
|
{
|
||||||
|
nMaxSize = nMaxSizeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type GetMaxSize() const {
|
||||||
|
return nMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type GetSize() const {
|
||||||
|
return nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Insert(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
if(nCurrentSize == nMaxSize) {
|
||||||
|
PruneLast();
|
||||||
|
}
|
||||||
|
map_it mit = mapIndex.find(key);
|
||||||
|
if(mit == mapIndex.end()) {
|
||||||
|
mit = mapIndex.insert(std::pair<K,it_map_t>(key, it_map_t())).first;
|
||||||
|
}
|
||||||
|
it_map_t& mapIt = mit->second;
|
||||||
|
|
||||||
|
if(mapIt.count(value) > 0) {
|
||||||
|
// Don't insert duplicates
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listItems.push_front(item_t(key, value));
|
||||||
|
list_it lit = listItems.begin();
|
||||||
|
|
||||||
|
mapIt[value] = lit;
|
||||||
|
++nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasKey(const K& key) const
|
||||||
|
{
|
||||||
|
map_cit it = mapIndex.find(key);
|
||||||
|
return (it != mapIndex.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Get(const K& key, V& value) const
|
||||||
|
{
|
||||||
|
map_cit it = mapIndex.find(key);
|
||||||
|
if(it == mapIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const it_map_t& mapIt = it->second;
|
||||||
|
const item_t& item = *(mapIt.begin()->second);
|
||||||
|
value = item.value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetAll(const K& key, std::vector<V>& vecValues)
|
||||||
|
{
|
||||||
|
map_cit mit = mapIndex.find(key);
|
||||||
|
if(mit == mapIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const it_map_t& mapIt = mit->second;
|
||||||
|
|
||||||
|
for(it_map_cit it = mapIt.begin(); it != mapIt.end(); ++it) {
|
||||||
|
const item_t& item = *(it->second);
|
||||||
|
vecValues.push_back(item.value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const K& key)
|
||||||
|
{
|
||||||
|
map_it mit = mapIndex.find(key);
|
||||||
|
if(mit == mapIndex.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
it_map_t& mapIt = mit->second;
|
||||||
|
|
||||||
|
for(it_map_it it = mapIt.begin(); it != mapIt.end(); ++it) {
|
||||||
|
listItems.erase(it->second);
|
||||||
|
--nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapIndex.erase(mit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Erase(const K& key, const V& value)
|
||||||
|
{
|
||||||
|
map_it mit = mapIndex.find(key);
|
||||||
|
if(mit == mapIndex.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
it_map_t& mapIt = mit->second;
|
||||||
|
|
||||||
|
it_map_it it = mapIt.find(value);
|
||||||
|
if(it == mapIt.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listItems.erase(it->second);
|
||||||
|
--nCurrentSize;
|
||||||
|
mapIt.erase(it);
|
||||||
|
|
||||||
|
if(mapIt.size() < 1) {
|
||||||
|
mapIndex.erase(mit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const list_t& GetItemList() const {
|
||||||
|
return listItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
CacheMap<K,V>& operator=(const CacheMap<K,V>& other)
|
||||||
|
{
|
||||||
|
nMaxSize = other.nMaxSize;
|
||||||
|
nCurrentSize = other.nCurrentSize;
|
||||||
|
listItems = other.listItems;
|
||||||
|
RebuildIndex();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(nMaxSize);
|
||||||
|
READWRITE(nCurrentSize);
|
||||||
|
READWRITE(listItems);
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PruneLast()
|
||||||
|
{
|
||||||
|
if(nCurrentSize < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_it lit = listItems.end();
|
||||||
|
--lit;
|
||||||
|
item_t& item = *lit;
|
||||||
|
|
||||||
|
map_it mit = mapIndex.find(item.key);
|
||||||
|
|
||||||
|
if(mit != mapIndex.end()) {
|
||||||
|
it_map_t& mapIt = mit->second;
|
||||||
|
|
||||||
|
mapIt.erase(item.value);
|
||||||
|
|
||||||
|
if(mapIt.size() < 1) {
|
||||||
|
mapIndex.erase(item.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listItems.pop_back();
|
||||||
|
--nCurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RebuildIndex()
|
||||||
|
{
|
||||||
|
mapIndex.clear();
|
||||||
|
for(list_it lit = listItems.begin(); lit != listItems.end(); ++lit) {
|
||||||
|
item_t& item = *lit;
|
||||||
|
map_it mit = mapIndex.find(item.key);
|
||||||
|
if(mit == mapIndex.end()) {
|
||||||
|
mit = mapIndex.insert(std::pair<K,it_map_t>(item.key, it_map_t())).first;
|
||||||
|
}
|
||||||
|
it_map_t& mapIt = mit->second;
|
||||||
|
mapIt[item.value] = lit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* CACHEMULTIMAP_H_ */
|
@ -346,7 +346,7 @@ bool CSuperblockManager::IsSuperblockTriggered(int nBlockHeight)
|
|||||||
|
|
||||||
// MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG
|
// MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG
|
||||||
|
|
||||||
if(pObj->fCachedFunding) {
|
if(pObj->IsSetCachedFunding()) {
|
||||||
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = true, returning true\n");
|
LogPrint("gobject", "CSuperblockManager::IsSuperblockTriggered -- fCacheFunding = true, returning true\n");
|
||||||
DBG( cout << "IsSuperblockTriggered returning true" << endl; );
|
DBG( cout << "IsSuperblockTriggered returning true" << endl; );
|
||||||
return true;
|
return true;
|
||||||
@ -506,7 +506,7 @@ CSuperblock(uint256& nHash)
|
|||||||
|
|
||||||
DBG( cout << "CSuperblock Constructor pGovObj : "
|
DBG( cout << "CSuperblock Constructor pGovObj : "
|
||||||
<< pGovObj->GetDataAsString()
|
<< pGovObj->GetDataAsString()
|
||||||
<< ", nObjectType = " << pGovObj->nObjectType
|
<< ", nObjectType = " << pGovObj->GetObjectType()
|
||||||
<< endl; );
|
<< endl; );
|
||||||
|
|
||||||
if (pGovObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
|
if (pGovObj->GetObjectType() != GOVERNANCE_OBJECT_TRIGGER) {
|
||||||
@ -678,7 +678,7 @@ bool CSuperblock::IsValid(const CTransaction& txNew, int nBlockHeight, CAmount b
|
|||||||
int nMinerPayments = nOutputs - nPayments;
|
int nMinerPayments = nOutputs - nPayments;
|
||||||
|
|
||||||
LogPrint("gobject", "CSuperblock::IsValid nOutputs = %d, nPayments = %d, strData = %s\n",
|
LogPrint("gobject", "CSuperblock::IsValid nOutputs = %d, nPayments = %d, strData = %s\n",
|
||||||
nOutputs, nPayments, GetGovernanceObject()->strData);
|
nOutputs, nPayments, GetGovernanceObject()->GetDataAsHex());
|
||||||
|
|
||||||
// We require an exact match (including order) between the expected
|
// We require an exact match (including order) between the expected
|
||||||
// superblock payments and the payments actually in the block, after
|
// superblock payments and the payments actually in the block, after
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// Copyright (c) 2014-2016 The Dash Core developers
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
#ifndef GOVERANCE_CLASSES_H
|
#ifndef GOVERNANCE_CLASSES_H
|
||||||
#define GOVERANCE_CLASSES_H
|
#define GOVERNANCE_CLASSES_H
|
||||||
|
|
||||||
//#define ENABLE_DASH_DEBUG
|
//#define ENABLE_DASH_DEBUG
|
||||||
|
|
||||||
|
98
src/governance-exceptions.h
Normal file
98
src/governance-exceptions.h
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef GOVERNANCE_EXCEPTIONS_H
|
||||||
|
#define GOVERNANCE_EXCEPTIONS_H
|
||||||
|
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
enum governance_exception_type_enum_t {
|
||||||
|
/// Default value, normally indicates no exception condition occurred
|
||||||
|
GOVERNANCE_EXCEPTION_NONE = 0,
|
||||||
|
/// Unusual condition requiring no caller action
|
||||||
|
GOVERNANCE_EXCEPTION_WARNING = 1,
|
||||||
|
/// Requested operation cannot be performed
|
||||||
|
GOVERNANCE_EXCEPTION_PERMANENT_ERROR = 2,
|
||||||
|
/// Requested operation not currently possible, may resubmit later
|
||||||
|
GOVERNANCE_EXCEPTION_TEMPORARY_ERROR = 3,
|
||||||
|
/// Unexpected error (ie. should not happen unless there is a bug in the code)
|
||||||
|
GOVERNANCE_EXCEPTION_INTERNAL_ERROR = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, governance_exception_type_enum_t eType)
|
||||||
|
{
|
||||||
|
switch(eType) {
|
||||||
|
case GOVERNANCE_EXCEPTION_NONE:
|
||||||
|
os << "GOVERNANCE_EXCEPTION_NONE";
|
||||||
|
break;
|
||||||
|
case GOVERNANCE_EXCEPTION_WARNING:
|
||||||
|
os << "GOVERNANCE_EXCEPTION_WARNING";
|
||||||
|
break;
|
||||||
|
case GOVERNANCE_EXCEPTION_PERMANENT_ERROR:
|
||||||
|
os << "GOVERNANCE_EXCEPTION_PERMANENT_ERROR";
|
||||||
|
break;
|
||||||
|
case GOVERNANCE_EXCEPTION_TEMPORARY_ERROR:
|
||||||
|
os << "GOVERNANCE_EXCEPTION_TEMPORARY_ERROR";
|
||||||
|
break;
|
||||||
|
case GOVERNANCE_EXCEPTION_INTERNAL_ERROR:
|
||||||
|
os << "GOVERNANCE_EXCEPTION_INTERNAL_ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which encapsulates information about a governance exception condition
|
||||||
|
*
|
||||||
|
* Derives from std::exception so is suitable for throwing
|
||||||
|
* (ie. will be caught by a std::exception handler) but may also be used as a
|
||||||
|
* normal object.
|
||||||
|
*/
|
||||||
|
class CGovernanceException : public std::exception
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::string strMessage;
|
||||||
|
|
||||||
|
governance_exception_type_enum_t eType;
|
||||||
|
|
||||||
|
int nNodePenalty;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CGovernanceException(const std::string& strMessageIn = "",
|
||||||
|
governance_exception_type_enum_t eTypeIn = GOVERNANCE_EXCEPTION_NONE,
|
||||||
|
int nNodePenaltyIn = 0)
|
||||||
|
: strMessage(),
|
||||||
|
eType(eTypeIn),
|
||||||
|
nNodePenalty(nNodePenaltyIn)
|
||||||
|
{
|
||||||
|
std::ostringstream ostr;
|
||||||
|
ostr << eType << ":" << strMessageIn;
|
||||||
|
strMessage = ostr.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~CGovernanceException() throw() {}
|
||||||
|
|
||||||
|
virtual const char* what() const throw()
|
||||||
|
{
|
||||||
|
return strMessage.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& GetMessage() const
|
||||||
|
{
|
||||||
|
return strMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
governance_exception_type_enum_t GetType() const
|
||||||
|
{
|
||||||
|
return eType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetNodePenalty() const {
|
||||||
|
return nNodePenalty;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
#ifndef GOVERANCE_MISC_H
|
#ifndef GOVERNANCE_MISC_H
|
||||||
#define GOVERANCE_MISC_H
|
#define GOVERNANCE_MISC_H
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "governance.h"
|
#include "governance.h"
|
||||||
@ -51,4 +51,4 @@ class CGovernanceVote;
|
|||||||
// }
|
// }
|
||||||
// };
|
// };
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -233,7 +233,7 @@ CGovernanceVote::CGovernanceVote(CTxIn vinMasternodeIn, uint256 nParentHashIn, v
|
|||||||
vchSig()
|
vchSig()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void CGovernanceVote::Relay()
|
void CGovernanceVote::Relay() const
|
||||||
{
|
{
|
||||||
CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash());
|
CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash());
|
||||||
RelayInv(inv, PROTOCOL_VERSION);
|
RelayInv(inv, PROTOCOL_VERSION);
|
||||||
@ -262,15 +262,15 @@ bool CGovernanceVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGovernanceVote::IsValid(bool fSignatureCheck)
|
bool CGovernanceVote::IsValid(bool fSignatureCheck) const
|
||||||
{
|
{
|
||||||
if(nTime > GetTime() + (60*60)){
|
if(nTime > GetTime() + (60*60)) {
|
||||||
LogPrint("gobject", "CGovernanceVote::IsValid -- vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", GetHash().ToString(), nTime, GetTime() + (60*60));
|
LogPrint("gobject", "CGovernanceVote::IsValid -- vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", GetHash().ToString(), nTime, GetTime() + (60*60));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// support up to 50 actions (implemented in sentinel)
|
// support up to 50 actions (implemented in sentinel)
|
||||||
if(nVoteSignal > 50)
|
if(nVoteSignal > MAX_SUPPORTED_VOTE_SIGNAL)
|
||||||
{
|
{
|
||||||
LogPrint("gobject", "CGovernanceVote::IsValid -- Client attempted to vote on invalid signal(%d) - %s\n", nVoteSignal, GetHash().ToString());
|
LogPrint("gobject", "CGovernanceVote::IsValid -- Client attempted to vote on invalid signal(%d) - %s\n", nVoteSignal, GetHash().ToString());
|
||||||
return false;
|
return false;
|
||||||
@ -302,3 +302,44 @@ bool CGovernanceVote::IsValid(bool fSignatureCheck)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
|
||||||
|
{
|
||||||
|
bool fResult = ((vote1.vinMasternode == vote2.vinMasternode) &&
|
||||||
|
(vote1.nParentHash == vote2.nParentHash) &&
|
||||||
|
(vote1.nVoteOutcome == vote2.nVoteOutcome) &&
|
||||||
|
(vote1.nVoteSignal == vote2.nVoteSignal) &&
|
||||||
|
(vote1.nTime == vote2.nTime));
|
||||||
|
return fResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
|
||||||
|
{
|
||||||
|
bool fResult = (vote1.vinMasternode < vote2.vinMasternode);
|
||||||
|
if(!fResult) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fResult = (vote1.vinMasternode == vote2.vinMasternode);
|
||||||
|
|
||||||
|
fResult = fResult && (vote1.nParentHash < vote2.nParentHash);
|
||||||
|
if(!fResult) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fResult = fResult && (vote1.nParentHash == vote2.nParentHash);
|
||||||
|
|
||||||
|
fResult = fResult && (vote1.nVoteOutcome < vote2.nVoteOutcome);
|
||||||
|
if(!fResult) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fResult = fResult && (vote1.nVoteOutcome == vote2.nVoteOutcome);
|
||||||
|
|
||||||
|
fResult = fResult && (vote1.nVoteSignal == vote2.nVoteSignal);
|
||||||
|
if(!fResult) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fResult = fResult && (vote1.nVoteSignal == vote2.nVoteSignal);
|
||||||
|
|
||||||
|
fResult = fResult && (vote1.nTime < vote2.nTime);
|
||||||
|
|
||||||
|
return fResult;
|
||||||
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
#ifndef GOVERANCE_VOTE_H
|
#ifndef GOVERNANCE_VOTE_H
|
||||||
#define GOVERANCE_VOTE_H
|
#define GOVERNANCE_VOTE_H
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
@ -68,6 +68,8 @@ enum vote_signal_enum_t {
|
|||||||
VOTE_SIGNAL_CUSTOM20 = 35
|
VOTE_SIGNAL_CUSTOM20 = 35
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const int MAX_SUPPORTED_VOTE_SIGNAL = VOTE_SIGNAL_ENDORSED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Governance Voting
|
* Governance Voting
|
||||||
*
|
*
|
||||||
@ -89,6 +91,10 @@ public:
|
|||||||
|
|
||||||
class CGovernanceVote
|
class CGovernanceVote
|
||||||
{
|
{
|
||||||
|
friend bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2);
|
||||||
|
|
||||||
|
friend bool operator<(const CGovernanceVote& vote1, const CGovernanceVote& vote2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fValid; //if the vote is currently valid / counted
|
bool fValid; //if the vote is currently valid / counted
|
||||||
bool fSynced; //if we've sent this to our peers
|
bool fSynced; //if we've sent this to our peers
|
||||||
@ -120,8 +126,12 @@ public:
|
|||||||
void SetSignature(const std::vector<unsigned char>& vchSigIn) { vchSig = vchSigIn; }
|
void SetSignature(const std::vector<unsigned char>& vchSigIn) { vchSig = vchSigIn; }
|
||||||
|
|
||||||
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
bool Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode);
|
||||||
bool IsValid(bool fSignatureCheck);
|
bool IsValid(bool fSignatureCheck) const;
|
||||||
void Relay();
|
void Relay() const;
|
||||||
|
|
||||||
|
std::string GetVoteString() const {
|
||||||
|
return CGovernanceVoting::ConvertOutcomeToString(GetOutcome());
|
||||||
|
}
|
||||||
|
|
||||||
CTxIn& GetVinMasternode() { return vinMasternode; }
|
CTxIn& GetVinMasternode() { return vinMasternode; }
|
||||||
|
|
||||||
@ -144,7 +154,7 @@ public:
|
|||||||
return ss.GetHash();
|
return ss.GetHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ToString()
|
std::string ToString() const
|
||||||
{
|
{
|
||||||
std::ostringstream ostr;
|
std::ostringstream ostr;
|
||||||
ostr << vinMasternode.ToString() << ":"
|
ostr << vinMasternode.ToString() << ":"
|
||||||
@ -197,6 +207,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 12.1.1 - CGovernanceVoteManager
|
* 12.1.1 - CGovernanceVoteManager
|
||||||
* -------------------------------
|
* -------------------------------
|
||||||
|
84
src/governance-votedb.cpp
Normal file
84
src/governance-votedb.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "governance-votedb.h"
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile::CGovernanceObjectVoteFile()
|
||||||
|
: nMemoryVotes(0),
|
||||||
|
listVotes(),
|
||||||
|
mapVoteIndex()
|
||||||
|
{}
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile::CGovernanceObjectVoteFile(const CGovernanceObjectVoteFile& other)
|
||||||
|
: nMemoryVotes(other.nMemoryVotes),
|
||||||
|
listVotes(other.listVotes),
|
||||||
|
mapVoteIndex()
|
||||||
|
{
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGovernanceObjectVoteFile::AddVote(const CGovernanceVote& vote)
|
||||||
|
{
|
||||||
|
listVotes.push_front(vote);
|
||||||
|
mapVoteIndex[vote.GetHash()] = listVotes.begin();
|
||||||
|
++nMemoryVotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGovernanceObjectVoteFile::HasVote(const uint256& nHash) const
|
||||||
|
{
|
||||||
|
vote_m_cit it = mapVoteIndex.find(nHash);
|
||||||
|
if(it == mapVoteIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CGovernanceObjectVoteFile::GetVote(const uint256& nHash, CGovernanceVote& vote) const
|
||||||
|
{
|
||||||
|
vote_m_cit it = mapVoteIndex.find(nHash);
|
||||||
|
if(it == mapVoteIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vote = *(it->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CGovernanceVote> CGovernanceObjectVoteFile::GetVotes() const
|
||||||
|
{
|
||||||
|
std::vector<CGovernanceVote> vecResult;
|
||||||
|
for(vote_l_cit it = listVotes.begin(); it != listVotes.end(); ++it) {
|
||||||
|
vecResult.push_back(*it);
|
||||||
|
}
|
||||||
|
return vecResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGovernanceObjectVoteFile::RemoveVotesFromMasternode(const CTxIn& vinMasternode)
|
||||||
|
{
|
||||||
|
vote_l_it it = listVotes.begin();
|
||||||
|
while(it != listVotes.end()) {
|
||||||
|
if(it->GetVinMasternode() == vinMasternode) {
|
||||||
|
listVotes.erase(it++);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile& CGovernanceObjectVoteFile::operator=(const CGovernanceObjectVoteFile& other)
|
||||||
|
{
|
||||||
|
nMemoryVotes = other.nMemoryVotes;
|
||||||
|
listVotes = other.listVotes;
|
||||||
|
RebuildIndex();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CGovernanceObjectVoteFile::RebuildIndex()
|
||||||
|
{
|
||||||
|
mapVoteIndex.clear();
|
||||||
|
for(vote_l_it it = listVotes.begin(); it != listVotes.end(); ++it) {
|
||||||
|
CGovernanceVote& vote = *it;
|
||||||
|
mapVoteIndex[vote.GetHash()] = it;
|
||||||
|
}
|
||||||
|
}
|
93
src/governance-votedb.h
Normal file
93
src/governance-votedb.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef GOVERNANCE_VOTEDB_H
|
||||||
|
#define GOVERNANCE_VOTEDB_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "governance-vote.h"
|
||||||
|
#include "serialize.h"
|
||||||
|
#include "uint256.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the collection of votes associated with a given CGovernanceObject
|
||||||
|
* Recently received votes are held in memory until a maximum size is reached after
|
||||||
|
* which older votes a flushed to a disk file.
|
||||||
|
*
|
||||||
|
* Note: This is a stub implementation that doesn't limit the number of votes held
|
||||||
|
* in memory and doesn't flush to disk.
|
||||||
|
*/
|
||||||
|
class CGovernanceObjectVoteFile
|
||||||
|
{
|
||||||
|
public: // Types
|
||||||
|
typedef std::list<CGovernanceVote> vote_l_t;
|
||||||
|
|
||||||
|
typedef vote_l_t::iterator vote_l_it;
|
||||||
|
|
||||||
|
typedef vote_l_t::const_iterator vote_l_cit;
|
||||||
|
|
||||||
|
typedef std::map<uint256,vote_l_it> vote_m_t;
|
||||||
|
|
||||||
|
typedef vote_m_t::iterator vote_m_it;
|
||||||
|
|
||||||
|
typedef vote_m_t::const_iterator vote_m_cit;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int MAX_MEMORY_VOTES = -1;
|
||||||
|
|
||||||
|
int nMemoryVotes;
|
||||||
|
|
||||||
|
vote_l_t listVotes;
|
||||||
|
|
||||||
|
vote_m_t mapVoteIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CGovernanceObjectVoteFile();
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile(const CGovernanceObjectVoteFile& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a vote to the file
|
||||||
|
*/
|
||||||
|
void AddVote(const CGovernanceVote& vote);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the vote with this hash is currently cached in memory
|
||||||
|
*/
|
||||||
|
bool HasVote(const uint256& nHash) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a vote cached in memory
|
||||||
|
*/
|
||||||
|
bool GetVote(const uint256& nHash, CGovernanceVote& vote) const;
|
||||||
|
|
||||||
|
int GetVoteCount() {
|
||||||
|
return nMemoryVotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CGovernanceVote> GetVotes() const;
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile& operator=(const CGovernanceObjectVoteFile& other);
|
||||||
|
|
||||||
|
void RemoveVotesFromMasternode(const CTxIn& vinMasternode);
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(nMemoryVotes);
|
||||||
|
READWRITE(listVotes);
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void RebuildIndex();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
346
src/governance.h
346
src/governance.h
@ -2,8 +2,8 @@
|
|||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#ifndef GOVERANCE_H
|
#ifndef GOVERNANCE_H
|
||||||
#define GOVERANCE_H
|
#define GOVERNANCE_H
|
||||||
|
|
||||||
//#define ENABLE_DASH_DEBUG
|
//#define ENABLE_DASH_DEBUG
|
||||||
|
|
||||||
@ -15,17 +15,22 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "base58.h"
|
#include "base58.h"
|
||||||
#include "masternode.h"
|
#include "masternode.h"
|
||||||
|
#include "governance-exceptions.h"
|
||||||
#include "governance-vote.h"
|
#include "governance-vote.h"
|
||||||
|
#include "governance-votedb.h"
|
||||||
#include "masternodeman.h"
|
#include "masternodeman.h"
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include <univalue.h>
|
#include <univalue.h>
|
||||||
#include "utilstrencodings.h"
|
#include "utilstrencodings.h"
|
||||||
|
#include "cachemap.h"
|
||||||
|
#include "cachemultimap.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
class CGovernanceManager;
|
class CGovernanceManager;
|
||||||
|
class CGovernanceTriggerManager;
|
||||||
class CGovernanceObject;
|
class CGovernanceObject;
|
||||||
class CGovernanceVote;
|
class CGovernanceVote;
|
||||||
|
|
||||||
@ -57,6 +62,8 @@ extern CGovernanceManager governance;
|
|||||||
//
|
//
|
||||||
class CGovernanceManager
|
class CGovernanceManager
|
||||||
{
|
{
|
||||||
|
friend class CGovernanceObject;
|
||||||
|
|
||||||
public: // Types
|
public: // Types
|
||||||
|
|
||||||
typedef std::map<uint256, CGovernanceObject> object_m_t;
|
typedef std::map<uint256, CGovernanceObject> object_m_t;
|
||||||
@ -65,6 +72,8 @@ public: // Types
|
|||||||
|
|
||||||
typedef object_m_t::const_iterator object_m_cit;
|
typedef object_m_t::const_iterator object_m_cit;
|
||||||
|
|
||||||
|
typedef CacheMap<uint256, CGovernanceObject*> object_ref_cache_t;
|
||||||
|
|
||||||
typedef std::map<uint256, int> count_m_t;
|
typedef std::map<uint256, int> count_m_t;
|
||||||
|
|
||||||
typedef count_m_t::iterator count_m_it;
|
typedef count_m_t::iterator count_m_it;
|
||||||
@ -77,11 +86,9 @@ public: // Types
|
|||||||
|
|
||||||
typedef vote_m_t::const_iterator vote_m_cit;
|
typedef vote_m_t::const_iterator vote_m_cit;
|
||||||
|
|
||||||
typedef std::map<uint256, CTransaction> transaction_m_t;
|
typedef CacheMap<uint256, CGovernanceVote> vote_cache_t;
|
||||||
|
|
||||||
typedef transaction_m_t::iterator transaction_m_it;
|
typedef CacheMultiMap<uint256, CGovernanceVote> vote_mcache_t;
|
||||||
|
|
||||||
typedef transaction_m_t::const_iterator transaction_m_cit;
|
|
||||||
|
|
||||||
typedef object_m_t::size_type size_type;
|
typedef object_m_t::size_type size_type;
|
||||||
|
|
||||||
@ -91,10 +98,17 @@ public: // Types
|
|||||||
|
|
||||||
typedef txout_m_t::const_iterator txout_m_cit;
|
typedef txout_m_t::const_iterator txout_m_cit;
|
||||||
|
|
||||||
private:
|
typedef std::set<uint256> hash_s_t;
|
||||||
|
|
||||||
|
typedef hash_s_t::iterator hash_s_it;
|
||||||
|
|
||||||
|
typedef hash_s_t::const_iterator hash_s_cit;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int MAX_CACHE_SIZE = 1000000;
|
||||||
|
|
||||||
|
static const std::string SERIALIZATION_VERSION_STRING;
|
||||||
|
|
||||||
//hold txes until they mature enough to use
|
|
||||||
transaction_m_t mapCollateral;
|
|
||||||
// Keep track of current block index
|
// Keep track of current block index
|
||||||
const CBlockIndex *pCurrentBlockIndex;
|
const CBlockIndex *pCurrentBlockIndex;
|
||||||
|
|
||||||
@ -105,57 +119,68 @@ private:
|
|||||||
object_m_t mapObjects;
|
object_m_t mapObjects;
|
||||||
|
|
||||||
count_m_t mapSeenGovernanceObjects;
|
count_m_t mapSeenGovernanceObjects;
|
||||||
count_m_t mapSeenVotes;
|
|
||||||
vote_m_t mapOrphanVotes;
|
|
||||||
|
|
||||||
// todo: one of these should point to the other
|
object_ref_cache_t mapVoteToObject;
|
||||||
// -- must be carefully managed while adding/removing/updating
|
|
||||||
vote_m_t mapVotesByHash;
|
vote_cache_t mapInvalidVotes;
|
||||||
vote_m_t mapVotesByType;
|
|
||||||
|
vote_mcache_t mapOrphanVotes;
|
||||||
|
|
||||||
txout_m_t mapLastMasternodeTrigger;
|
txout_m_t mapLastMasternodeTrigger;
|
||||||
|
|
||||||
|
hash_s_t setRequestedObjects;
|
||||||
|
|
||||||
|
hash_s_t setRequestedVotes;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// critical section to protect the inner data structures
|
// critical section to protect the inner data structures
|
||||||
mutable CCriticalSection cs;
|
mutable CCriticalSection cs;
|
||||||
|
|
||||||
CGovernanceManager();
|
CGovernanceManager();
|
||||||
|
|
||||||
|
virtual ~CGovernanceManager() {}
|
||||||
|
|
||||||
void ClearSeen()
|
void ClearSeen()
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
mapSeenGovernanceObjects.clear();
|
mapSeenGovernanceObjects.clear();
|
||||||
mapSeenVotes.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CountProposalInventoryItems()
|
int CountProposalInventoryItems()
|
||||||
{
|
{
|
||||||
return mapSeenGovernanceObjects.size() + mapSeenVotes.size();
|
// TODO What is this for ?
|
||||||
|
return mapSeenGovernanceObjects.size();
|
||||||
|
//return mapSeenGovernanceObjects.size() + mapSeenVotes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called by AlreadyHave in main.cpp as part of the inventory
|
||||||
|
* retrieval process. Returns true if we want to retrieve the object, otherwise
|
||||||
|
* false. (Note logic is inverted in AlreadyHave).
|
||||||
|
*/
|
||||||
|
bool ConfirmInventoryRequest(const CInv& inv);
|
||||||
|
|
||||||
void Sync(CNode* node, uint256 nProp);
|
void Sync(CNode* node, uint256 nProp);
|
||||||
|
|
||||||
void SyncParentObjectByVote(CNode* pfrom, const CGovernanceVote& vote);
|
void SyncParentObjectByVote(CNode* pfrom, const CGovernanceVote& vote);
|
||||||
|
|
||||||
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
|
||||||
|
|
||||||
void NewBlock();
|
void NewBlock();
|
||||||
|
|
||||||
CGovernanceObject *FindGovernanceObject(const uint256& nHash);
|
CGovernanceObject *FindGovernanceObject(const uint256& nHash);
|
||||||
|
|
||||||
std::vector<CGovernanceVote*> GetMatchingVotes(const uint256& nParentHash);
|
std::vector<CGovernanceVote> GetMatchingVotes(const uint256& nParentHash);
|
||||||
std::vector<CGovernanceObject*> GetAllNewerThan(int64_t nMoreThanTime);
|
std::vector<CGovernanceObject*> GetAllNewerThan(int64_t nMoreThanTime);
|
||||||
|
|
||||||
int CountMatchingVotes(CGovernanceObject& govobj, vote_signal_enum_t nVoteSignalIn, vote_outcome_enum_t nVoteOutcomeIn);
|
|
||||||
|
|
||||||
bool IsBudgetPaymentBlock(int nBlockHeight);
|
bool IsBudgetPaymentBlock(int nBlockHeight);
|
||||||
bool AddGovernanceObject (CGovernanceObject& govobj);
|
bool AddGovernanceObject (CGovernanceObject& govobj);
|
||||||
bool AddOrUpdateVote(const CGovernanceVote& vote, CNode* pfrom, std::string& strError);
|
|
||||||
|
|
||||||
std::string GetRequiredPaymentsString(int nBlockHeight);
|
std::string GetRequiredPaymentsString(int nBlockHeight);
|
||||||
void CleanAndRemove(bool fSignatureCheck);
|
|
||||||
void UpdateCachesAndClean();
|
|
||||||
void CheckAndRemove() {UpdateCachesAndClean();}
|
|
||||||
|
|
||||||
void CheckOrphanVotes();
|
void UpdateCachesAndClean();
|
||||||
|
|
||||||
|
void CheckAndRemove() {UpdateCachesAndClean();}
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
@ -164,10 +189,9 @@ public:
|
|||||||
LogPrint("gobject", "Governance object manager was cleared\n");
|
LogPrint("gobject", "Governance object manager was cleared\n");
|
||||||
mapObjects.clear();
|
mapObjects.clear();
|
||||||
mapSeenGovernanceObjects.clear();
|
mapSeenGovernanceObjects.clear();
|
||||||
mapSeenVotes.clear();
|
mapVoteToObject.Clear();
|
||||||
mapOrphanVotes.clear();
|
mapInvalidVotes.Clear();
|
||||||
mapVotesByType.clear();
|
mapOrphanVotes.Clear();
|
||||||
mapVotesByHash.clear();
|
|
||||||
mapLastMasternodeTrigger.clear();
|
mapLastMasternodeTrigger.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,14 +202,25 @@ public:
|
|||||||
template <typename Stream, typename Operation>
|
template <typename Stream, typename Operation>
|
||||||
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
|
std::string strVersion;
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
READWRITE(strVersion);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strVersion = SERIALIZATION_VERSION_STRING;
|
||||||
|
READWRITE(strVersion);
|
||||||
|
}
|
||||||
READWRITE(mapSeenGovernanceObjects);
|
READWRITE(mapSeenGovernanceObjects);
|
||||||
READWRITE(mapSeenVotes);
|
READWRITE(mapInvalidVotes);
|
||||||
READWRITE(mapOrphanVotes);
|
READWRITE(mapOrphanVotes);
|
||||||
READWRITE(mapObjects);
|
READWRITE(mapObjects);
|
||||||
READWRITE(mapVotesByHash);
|
|
||||||
READWRITE(mapVotesByType);
|
|
||||||
READWRITE(mapLastMasternodeTrigger);
|
READWRITE(mapLastMasternodeTrigger);
|
||||||
|
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
|
||||||
|
Clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(ser_action.ForRead()) {
|
if(ser_action.ForRead()) {
|
||||||
|
RebuildIndexes();
|
||||||
AddCachedTriggers();
|
AddCachedTriggers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,11 +246,90 @@ public:
|
|||||||
|
|
||||||
bool MasternodeRateCheck(const CTxIn& vin, int nObjectType);
|
bool MasternodeRateCheck(const CTxIn& vin, int nObjectType);
|
||||||
|
|
||||||
|
bool ProcessVote(const CGovernanceVote& vote, CGovernanceException& exception) {
|
||||||
|
return ProcessVote(NULL, vote, exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckMasternodeOrphanVotes();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void RequestGovernanceObject(CNode* pfrom, const uint256& nHash);
|
||||||
|
|
||||||
|
void AddInvalidVote(const CGovernanceVote& vote)
|
||||||
|
{
|
||||||
|
mapInvalidVotes.Insert(vote.GetHash(), vote);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddOrphanVote(const CGovernanceVote& vote)
|
||||||
|
{
|
||||||
|
mapOrphanVotes.Insert(vote.GetHash(), vote);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProcessVote(CNode* pfrom, const CGovernanceVote& vote, CGovernanceException& exception);
|
||||||
|
|
||||||
|
/// Called to indicate a requested object has been received
|
||||||
|
bool AcceptObjectMessage(const uint256& nHash);
|
||||||
|
|
||||||
|
/// Called to indicate a requested vote has been received
|
||||||
|
bool AcceptVoteMessage(const uint256& nHash);
|
||||||
|
|
||||||
|
static bool AcceptMessage(const uint256& nHash, hash_s_t& setHash);
|
||||||
|
|
||||||
|
void CheckOrphanVotes(CNode* pfrom, CGovernanceObject& govobj, CGovernanceException& exception);
|
||||||
|
|
||||||
|
void RebuildIndexes();
|
||||||
|
|
||||||
|
/// Returns MN index, handling the case of index rebuilds
|
||||||
|
int GetMasternodeIndex(const CTxIn& masternodeVin);
|
||||||
|
|
||||||
|
void RebuildVoteMaps();
|
||||||
|
|
||||||
void AddCachedTriggers();
|
void AddCachedTriggers();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct vote_instance_t {
|
||||||
|
|
||||||
|
vote_outcome_enum_t eOutcome;
|
||||||
|
int64_t nTime;
|
||||||
|
|
||||||
|
vote_instance_t(vote_outcome_enum_t eOutcomeIn = VOTE_OUTCOME_NONE, int64_t nTimeIn = 0)
|
||||||
|
: eOutcome(eOutcomeIn),
|
||||||
|
nTime(nTimeIn)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
int nOutcome = int(eOutcome);
|
||||||
|
READWRITE(nOutcome);
|
||||||
|
READWRITE(nTime);
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
eOutcome = vote_outcome_enum_t(nOutcome);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<int,vote_instance_t> vote_instance_m_t;
|
||||||
|
|
||||||
|
typedef vote_instance_m_t::iterator vote_instance_m_it;
|
||||||
|
|
||||||
|
typedef vote_instance_m_t::const_iterator vote_instance_m_cit;
|
||||||
|
|
||||||
|
struct vote_rec_t {
|
||||||
|
vote_instance_m_t mapInstances;
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(mapInstances);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Governance Object
|
* Governance Object
|
||||||
*
|
*
|
||||||
@ -223,41 +337,140 @@ private:
|
|||||||
|
|
||||||
class CGovernanceObject
|
class CGovernanceObject
|
||||||
{
|
{
|
||||||
|
friend class CGovernanceManager;
|
||||||
|
|
||||||
|
friend class CGovernanceTriggerManager;
|
||||||
|
|
||||||
|
public: // Types
|
||||||
|
typedef std::map<int, vote_rec_t> vote_m_t;
|
||||||
|
|
||||||
|
typedef vote_m_t::iterator vote_m_it;
|
||||||
|
|
||||||
|
typedef vote_m_t::const_iterator vote_m_cit;
|
||||||
|
|
||||||
|
typedef CacheMultiMap<CTxIn, CGovernanceVote> vote_mcache_t;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// critical section to protect the inner data structures
|
/// critical section to protect the inner data structures
|
||||||
mutable CCriticalSection cs;
|
mutable CCriticalSection cs;
|
||||||
|
|
||||||
public:
|
/// Object typecode
|
||||||
|
|
||||||
uint256 nHashParent; //parent object, 0 is root
|
|
||||||
int nRevision; //object revision in the system
|
|
||||||
int64_t nTime; //time this object was created
|
|
||||||
uint256 nCollateralHash; //fee-tx
|
|
||||||
std::string strData; // Data field - can be used for anything
|
|
||||||
int nObjectType;
|
int nObjectType;
|
||||||
|
|
||||||
// Masternode info for signed objects
|
/// parent object, 0 is root
|
||||||
|
uint256 nHashParent;
|
||||||
|
|
||||||
|
/// object revision in the system
|
||||||
|
int nRevision;
|
||||||
|
|
||||||
|
/// time this object was created
|
||||||
|
int64_t nTime;
|
||||||
|
|
||||||
|
/// fee-tx
|
||||||
|
uint256 nCollateralHash;
|
||||||
|
|
||||||
|
/// Data field - can be used for anything
|
||||||
|
std::string strData;
|
||||||
|
|
||||||
|
/// Masternode info for signed objects
|
||||||
CTxIn vinMasternode;
|
CTxIn vinMasternode;
|
||||||
std::vector<unsigned char> vchSig;
|
std::vector<unsigned char> vchSig;
|
||||||
|
|
||||||
bool fCachedLocalValidity; // is valid by blockchain
|
/// is valid by blockchain
|
||||||
|
bool fCachedLocalValidity;
|
||||||
std::string strLocalValidityError;
|
std::string strLocalValidityError;
|
||||||
|
|
||||||
// VARIOUS FLAGS FOR OBJECT / SET VIA MASTERNODE VOTING
|
// VARIOUS FLAGS FOR OBJECT / SET VIA MASTERNODE VOTING
|
||||||
|
|
||||||
bool fCachedFunding; // true == minimum network support has been reached for this object to be funded (doesn't mean it will for sure though)
|
/// true == minimum network support has been reached for this object to be funded (doesn't mean it will for sure though)
|
||||||
bool fCachedValid; // true == minimum network has been reached flagging this object as a valid and understood goverance object (e.g, the serialized data is correct format, etc)
|
bool fCachedFunding;
|
||||||
bool fCachedDelete; // true == minimum network support has been reached saying this object should be deleted from the system entirely
|
|
||||||
bool fCachedEndorsed; // true == minimum network support has been reached flagging this object as endorsed by an elected representative body (e.g. business review board / technecial review board /etc)
|
|
||||||
bool fDirtyCache; // object was updated and cached values should be updated soon
|
|
||||||
bool fUnparsable; // data field was unparsible, object will be rejected
|
|
||||||
bool fExpired; // Object is no longer of interest
|
|
||||||
|
|
||||||
|
/// true == minimum network has been reached flagging this object as a valid and understood goverance object (e.g, the serialized data is correct format, etc)
|
||||||
|
bool fCachedValid;
|
||||||
|
|
||||||
|
/// true == minimum network support has been reached saying this object should be deleted from the system entirely
|
||||||
|
bool fCachedDelete;
|
||||||
|
|
||||||
|
/** true == minimum network support has been reached flagging this object as endorsed by an elected representative body
|
||||||
|
* (e.g. business review board / technecial review board /etc)
|
||||||
|
*/
|
||||||
|
bool fCachedEndorsed;
|
||||||
|
|
||||||
|
/// object was updated and cached values should be updated soon
|
||||||
|
bool fDirtyCache;
|
||||||
|
|
||||||
|
/// Object is no longer of interest
|
||||||
|
bool fExpired;
|
||||||
|
|
||||||
|
/// Failed to parse object data
|
||||||
|
bool fUnparsable;
|
||||||
|
|
||||||
|
vote_m_t mapCurrentMNVotes;
|
||||||
|
|
||||||
|
/// Limited map of votes orphaned by MN
|
||||||
|
vote_mcache_t mapOrphanVotes;
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile fileVotes;
|
||||||
|
|
||||||
|
public:
|
||||||
CGovernanceObject();
|
CGovernanceObject();
|
||||||
|
|
||||||
CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, int64_t nTime, uint256 nCollateralHashIn, std::string strDataIn);
|
CGovernanceObject(uint256 nHashParentIn, int nRevisionIn, int64_t nTime, uint256 nCollateralHashIn, std::string strDataIn);
|
||||||
|
|
||||||
CGovernanceObject(const CGovernanceObject& other);
|
CGovernanceObject(const CGovernanceObject& other);
|
||||||
|
|
||||||
void swap(CGovernanceObject& first, CGovernanceObject& second); // nothrow
|
void swap(CGovernanceObject& first, CGovernanceObject& second); // nothrow
|
||||||
|
|
||||||
|
// Public Getter methods
|
||||||
|
|
||||||
|
int64_t GetCreationTime() const {
|
||||||
|
return nTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetObjectType() const {
|
||||||
|
return nObjectType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint256& GetCollateralHash() const {
|
||||||
|
return nCollateralHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CTxIn& GetMasternodeVin() const {
|
||||||
|
return vinMasternode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetCachedFunding() const {
|
||||||
|
return fCachedFunding;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetCachedValid() const {
|
||||||
|
return fCachedValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetCachedDelete() const {
|
||||||
|
return fCachedDelete;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetCachedEndorsed() const {
|
||||||
|
return fCachedEndorsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetDirtyCache() const {
|
||||||
|
return fDirtyCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSetExpired() const {
|
||||||
|
return fExpired;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InvalidateVoteCache() {
|
||||||
|
fDirtyCache = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGovernanceObjectVoteFile& GetVoteFile() {
|
||||||
|
return fileVotes;
|
||||||
|
}
|
||||||
|
|
||||||
// Signature related functions
|
// Signature related functions
|
||||||
|
|
||||||
void SetMasternodeInfo(const CTxIn& vin);
|
void SetMasternodeInfo(const CTxIn& vin);
|
||||||
@ -272,8 +485,9 @@ public:
|
|||||||
bool IsCollateralValid(std::string& strError);
|
bool IsCollateralValid(std::string& strError);
|
||||||
|
|
||||||
void UpdateLocalValidity(const CBlockIndex *pCurrentBlockIndex);
|
void UpdateLocalValidity(const CBlockIndex *pCurrentBlockIndex);
|
||||||
|
|
||||||
void UpdateSentinelVariables(const CBlockIndex *pCurrentBlockIndex);
|
void UpdateSentinelVariables(const CBlockIndex *pCurrentBlockIndex);
|
||||||
int GetObjectType();
|
|
||||||
int GetObjectSubtype();
|
int GetObjectSubtype();
|
||||||
|
|
||||||
CAmount GetMinCollateralFee();
|
CAmount GetMinCollateralFee();
|
||||||
@ -281,15 +495,18 @@ public:
|
|||||||
UniValue GetJSONObject();
|
UniValue GetJSONObject();
|
||||||
|
|
||||||
void Relay();
|
void Relay();
|
||||||
|
|
||||||
uint256 GetHash();
|
uint256 GetHash();
|
||||||
|
|
||||||
// GET VOTE COUNT FOR SIGNAL
|
// GET VOTE COUNT FOR SIGNAL
|
||||||
|
|
||||||
int GetAbsoluteYesCount(vote_signal_enum_t eVoteSignalIn);
|
int CountMatchingVotes(vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) const;
|
||||||
int GetAbsoluteNoCount(vote_signal_enum_t eVoteSignalIn);
|
|
||||||
int GetYesCount(vote_signal_enum_t eVoteSignalIn);
|
int GetAbsoluteYesCount(vote_signal_enum_t eVoteSignalIn) const;
|
||||||
int GetNoCount(vote_signal_enum_t eVoteSignalIn);
|
int GetAbsoluteNoCount(vote_signal_enum_t eVoteSignalIn) const;
|
||||||
int GetAbstainCount(vote_signal_enum_t eVoteSignalIn);
|
int GetYesCount(vote_signal_enum_t eVoteSignalIn) const;
|
||||||
|
int GetNoCount(vote_signal_enum_t eVoteSignalIn) const;
|
||||||
|
int GetAbstainCount(vote_signal_enum_t eVoteSignalIn) const;
|
||||||
|
|
||||||
// FUNCTIONS FOR DEALING WITH DATA STRING
|
// FUNCTIONS FOR DEALING WITH DATA STRING
|
||||||
|
|
||||||
@ -313,16 +530,33 @@ public:
|
|||||||
READWRITE(nObjectType);
|
READWRITE(nObjectType);
|
||||||
READWRITE(vinMasternode);
|
READWRITE(vinMasternode);
|
||||||
READWRITE(vchSig);
|
READWRITE(vchSig);
|
||||||
|
if(nType & SER_DISK) {
|
||||||
|
// Only include these for the disk file format
|
||||||
|
LogPrint("gobject", "CGovernanceObject::SerializationOp Reading/writing votes from/to disk\n");
|
||||||
|
READWRITE(mapCurrentMNVotes);
|
||||||
|
READWRITE(fileVotes);
|
||||||
|
LogPrint("gobject", "CGovernanceObject::SerializationOp hash = %s, vote count = %d\n", GetHash().ToString(), fileVotes.GetVoteCount());
|
||||||
|
}
|
||||||
|
|
||||||
// AFTER DESERIALIZATION OCCURS, CACHED VARIABLES MUST BE CALCULATED MANUALLY
|
// AFTER DESERIALIZATION OCCURS, CACHED VARIABLES MUST BE CALCULATED MANUALLY
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// FUNCTIONS FOR DEALING WITH DATA STRING
|
// FUNCTIONS FOR DEALING WITH DATA STRING
|
||||||
|
|
||||||
void LoadData();
|
void LoadData();
|
||||||
void GetData(UniValue& objResult);
|
void GetData(UniValue& objResult);
|
||||||
|
|
||||||
|
bool ProcessVote(CNode* pfrom,
|
||||||
|
const CGovernanceVote& vote,
|
||||||
|
CGovernanceException& exception);
|
||||||
|
|
||||||
|
void RebuildVoteMap();
|
||||||
|
|
||||||
|
/// Called when MN's which have voted on this object have been removed
|
||||||
|
void ClearMasternodeVotes();
|
||||||
|
|
||||||
|
void CheckOrphanVotes();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
12
src/main.cpp
12
src/main.cpp
@ -4948,14 +4948,11 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
|
|||||||
return mapDarksendBroadcastTxes.count(inv.hash);
|
return mapDarksendBroadcastTxes.count(inv.hash);
|
||||||
|
|
||||||
case MSG_GOVERNANCE_OBJECT:
|
case MSG_GOVERNANCE_OBJECT:
|
||||||
return governance.HaveObjectForHash(inv.hash);
|
|
||||||
|
|
||||||
case MSG_GOVERNANCE_OBJECT_VOTE:
|
case MSG_GOVERNANCE_OBJECT_VOTE:
|
||||||
return governance.HaveVoteForHash(inv.hash);
|
return ! governance.ConfirmInventoryRequest(inv);
|
||||||
|
|
||||||
case MSG_MASTERNODE_VERIFY:
|
case MSG_MASTERNODE_VERIFY:
|
||||||
return mnodeman.mapSeenMasternodeVerification.count(inv.hash);
|
return mnodeman.mapSeenMasternodeVerification.count(inv.hash);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't know what it is, just say we already got one
|
// Don't know what it is, just say we already got one
|
||||||
@ -6720,9 +6717,15 @@ bool SendMessages(CNode* pto)
|
|||||||
//
|
//
|
||||||
// Message: getdata (non-blocks)
|
// Message: getdata (non-blocks)
|
||||||
//
|
//
|
||||||
|
int64_t nFirst = -1;
|
||||||
|
if(!pto->mapAskFor.empty()) {
|
||||||
|
nFirst = (*pto->mapAskFor.begin()).first;
|
||||||
|
}
|
||||||
|
LogPrint("net", "SendMessages (mapAskFor) -- before loop: nNow = %d, nFirst = %d\n", nNow, nFirst);
|
||||||
while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
|
while (!pto->fDisconnect && !pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
|
||||||
{
|
{
|
||||||
const CInv& inv = (*pto->mapAskFor.begin()).second;
|
const CInv& inv = (*pto->mapAskFor.begin()).second;
|
||||||
|
LogPrint("net", "SendMessages (mapAskFor) -- inv = %s peer=%d\n", inv.ToString(), pto->id);
|
||||||
if (!AlreadyHave(inv))
|
if (!AlreadyHave(inv))
|
||||||
{
|
{
|
||||||
if (fDebug)
|
if (fDebug)
|
||||||
@ -6735,6 +6738,7 @@ bool SendMessages(CNode* pto)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//If we're not going to ask, don't expect a response.
|
//If we're not going to ask, don't expect a response.
|
||||||
|
LogPrint("net", "SendMessages -- already have inv = %s peer=%d\n", inv.ToString(), pto->id);
|
||||||
pto->setAskFor.erase(inv.hash);
|
pto->setAskFor.erase(inv.hash);
|
||||||
}
|
}
|
||||||
pto->mapAskFor.erase(pto->mapAskFor.begin());
|
pto->mapAskFor.erase(pto->mapAskFor.begin());
|
||||||
|
@ -882,6 +882,14 @@ void CMasternode::UpdateWatchdogVoteTime()
|
|||||||
*/
|
*/
|
||||||
void CMasternode::FlagGovernanceItemsAsDirty()
|
void CMasternode::FlagGovernanceItemsAsDirty()
|
||||||
{
|
{
|
||||||
|
std::map<uint256, int>::iterator it = mapGovernanceObjectsVotedOn.begin();
|
||||||
|
while(it != mapGovernanceObjectsVotedOn.end()){
|
||||||
|
CGovernanceObject *pObj = governance.FindGovernanceObject((*it).first);
|
||||||
|
|
||||||
|
if(pObj) pObj->InvalidateVoteCache();
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint256> vecDirty;
|
std::vector<uint256> vecDirty;
|
||||||
{
|
{
|
||||||
std::map<uint256, int>::iterator it = mapGovernanceObjectsVotedOn.begin();
|
std::map<uint256, int>::iterator it = mapGovernanceObjectsVotedOn.begin();
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "masternodeman.h"
|
#include "masternodeman.h"
|
||||||
#include "activemasternode.h"
|
#include "activemasternode.h"
|
||||||
#include "darksend.h"
|
#include "darksend.h"
|
||||||
|
#include "governance.h"
|
||||||
#include "masternode.h"
|
#include "masternode.h"
|
||||||
#include "masternode-payments.h"
|
#include "masternode-payments.h"
|
||||||
#include "masternode-sync.h"
|
#include "masternode-sync.h"
|
||||||
@ -38,7 +39,51 @@ struct CompareScoreMN
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
CMasternodeIndex::CMasternodeIndex()
|
||||||
|
: nSize(0),
|
||||||
|
mapIndex(),
|
||||||
|
mapReverseIndex()
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool CMasternodeIndex::Get(int nIndex, CTxIn& vinMasternode) const
|
||||||
|
{
|
||||||
|
rindex_m_cit it = mapReverseIndex.find(nIndex);
|
||||||
|
if(it == mapReverseIndex.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vinMasternode = it->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CMasternodeIndex::GetMasternodeIndex(const CTxIn& vinMasternode) const
|
||||||
|
{
|
||||||
|
index_m_cit it = mapIndex.find(vinMasternode);
|
||||||
|
if(it == mapIndex.end()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMasternodeIndex::AddMasternodeVIN(const CTxIn& vinMasternode)
|
||||||
|
{
|
||||||
|
index_m_it it = mapIndex.find(vinMasternode);
|
||||||
|
if(it != mapIndex.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int nNextIndex = nSize;
|
||||||
|
mapIndex[vinMasternode] = nNextIndex;
|
||||||
|
mapReverseIndex[nNextIndex] = vinMasternode;
|
||||||
|
++nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMasternodeIndex::Clear()
|
||||||
|
{
|
||||||
|
mapIndex.clear();
|
||||||
|
mapReverseIndex.clear();
|
||||||
|
nSize = 0;
|
||||||
|
}
|
||||||
struct CompareByAddr
|
struct CompareByAddr
|
||||||
|
|
||||||
{
|
{
|
||||||
bool operator()(const CMasternode* t1,
|
bool operator()(const CMasternode* t1,
|
||||||
const CMasternode* t2) const
|
const CMasternode* t2) const
|
||||||
@ -47,6 +92,33 @@ struct CompareByAddr
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void CMasternodeIndex::RebuildIndex()
|
||||||
|
{
|
||||||
|
nSize = mapIndex.size();
|
||||||
|
for(index_m_it it = mapIndex.begin(); it != mapIndex.end(); ++it) {
|
||||||
|
mapReverseIndex[it->second] = it->first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CMasternodeMan::CMasternodeMan()
|
||||||
|
: cs(),
|
||||||
|
vMasternodes(),
|
||||||
|
mAskedUsForMasternodeList(),
|
||||||
|
mWeAskedForMasternodeList(),
|
||||||
|
mWeAskedForMasternodeListEntry(),
|
||||||
|
nLastIndexRebuildTime(0),
|
||||||
|
indexMasternodes(),
|
||||||
|
indexMasternodesOld(),
|
||||||
|
fIndexRebuilt(false),
|
||||||
|
fMasternodesAdded(false),
|
||||||
|
fMasternodesRemoved(false),
|
||||||
|
vecDirtyGovernanceObjectHashes(),
|
||||||
|
nLastWatchdogVoteTime(0),
|
||||||
|
mapSeenMasternodeBroadcast(),
|
||||||
|
mapSeenMasternodePing(),
|
||||||
|
nDsqCount(0)
|
||||||
|
{}
|
||||||
|
|
||||||
bool CMasternodeMan::Add(CMasternode &mn)
|
bool CMasternodeMan::Add(CMasternode &mn)
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -59,13 +131,15 @@ bool CMasternodeMan::Add(CMasternode &mn)
|
|||||||
LogPrint("masternode", "CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now\n", mn.addr.ToString(), size() + 1);
|
LogPrint("masternode", "CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now\n", mn.addr.ToString(), size() + 1);
|
||||||
mn.nTimeLastWatchdogVote = mn.sigTime;
|
mn.nTimeLastWatchdogVote = mn.sigTime;
|
||||||
vMasternodes.push_back(mn);
|
vMasternodes.push_back(mn);
|
||||||
|
indexMasternodes.AddMasternodeVIN(mn.vin);
|
||||||
|
fMasternodesAdded = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMasternodeMan::AskForMN(CNode* pnode, CTxIn &vin)
|
void CMasternodeMan::AskForMN(CNode* pnode, const CTxIn &vin)
|
||||||
{
|
{
|
||||||
if(!pnode) return;
|
if(!pnode) return;
|
||||||
|
|
||||||
@ -99,106 +173,117 @@ void CMasternodeMan::CheckAndRemove(bool fForceExpiredRemoval)
|
|||||||
|
|
||||||
Check();
|
Check();
|
||||||
|
|
||||||
LOCK(cs);
|
{
|
||||||
|
LOCK(cs);
|
||||||
|
|
||||||
// Remove inactive and outdated masternodes
|
// Remove inactive and outdated masternodes
|
||||||
std::vector<CMasternode>::iterator it = vMasternodes.begin();
|
std::vector<CMasternode>::iterator it = vMasternodes.begin();
|
||||||
while(it != vMasternodes.end()) {
|
while(it != vMasternodes.end()) {
|
||||||
bool fRemove = // If it's marked to be removed from the list by CMasternode::Check for whatever reason ...
|
bool fRemove = // If it's marked to be removed from the list by CMasternode::Check for whatever reason ...
|
||||||
(*it).nActiveState == CMasternode::MASTERNODE_REMOVE ||
|
(*it).nActiveState == CMasternode::MASTERNODE_REMOVE ||
|
||||||
// or collateral was spent ...
|
// or collateral was spent ...
|
||||||
(*it).nActiveState == CMasternode::MASTERNODE_OUTPOINT_SPENT ||
|
(*it).nActiveState == CMasternode::MASTERNODE_OUTPOINT_SPENT ||
|
||||||
// or we were asked to remove exired entries ...
|
// or we were asked to remove exired entries ...
|
||||||
(fForceExpiredRemoval && (*it).nActiveState == CMasternode::MASTERNODE_EXPIRED);
|
(fForceExpiredRemoval && (*it).nActiveState == CMasternode::MASTERNODE_EXPIRED);
|
||||||
|
|
||||||
if (fRemove) {
|
if (fRemove) {
|
||||||
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now\n", (*it).GetStatus(), (*it).addr.ToString(), size() - 1);
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now\n", (*it).GetStatus(), (*it).addr.ToString(), size() - 1);
|
||||||
|
|
||||||
// erase all of the broadcasts we've seen from this txin, ...
|
// erase all of the broadcasts we've seen from this txin, ...
|
||||||
mapSeenMasternodeBroadcast.erase(CMasternodeBroadcast(*it).GetHash());
|
mapSeenMasternodeBroadcast.erase(CMasternodeBroadcast(*it).GetHash());
|
||||||
// allow us to ask for this masternode again if we see another ping ...
|
// allow us to ask for this masternode again if we see another ping ...
|
||||||
mWeAskedForMasternodeListEntry.erase((*it).vin.prevout);
|
mWeAskedForMasternodeListEntry.erase((*it).vin.prevout);
|
||||||
|
|
||||||
// and finally remove it from the list
|
// and finally remove it from the list
|
||||||
it = vMasternodes.erase(it);
|
it = vMasternodes.erase(it);
|
||||||
} else {
|
fMasternodesRemoved = true;
|
||||||
++it;
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check who's asked for the Masternode list
|
||||||
|
std::map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
|
||||||
|
while(it1 != mAskedUsForMasternodeList.end()){
|
||||||
|
if((*it1).second < GetTime()) {
|
||||||
|
mAskedUsForMasternodeList.erase(it1++);
|
||||||
|
} else {
|
||||||
|
++it1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check who we asked for the Masternode list
|
||||||
|
it1 = mWeAskedForMasternodeList.begin();
|
||||||
|
while(it1 != mWeAskedForMasternodeList.end()){
|
||||||
|
if((*it1).second < GetTime()){
|
||||||
|
mWeAskedForMasternodeList.erase(it1++);
|
||||||
|
} else {
|
||||||
|
++it1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check which Masternodes we've asked for
|
||||||
|
std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
|
||||||
|
while(it2 != mWeAskedForMasternodeListEntry.end()){
|
||||||
|
if((*it2).second < GetTime()){
|
||||||
|
mWeAskedForMasternodeListEntry.erase(it2++);
|
||||||
|
} else {
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<CNetAddr, CMasternodeVerification>::iterator itv1 = mWeAskedForVerification.begin();
|
||||||
|
while(itv1 != mWeAskedForVerification.end()){
|
||||||
|
if(itv1->second.nBlockHeight < pCurrentBlockIndex->nHeight - MAX_POSE_BLOCKS) {
|
||||||
|
mWeAskedForVerification.erase(itv1++);
|
||||||
|
} else {
|
||||||
|
++itv1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove expired mapSeenMasternodeBroadcast
|
||||||
|
std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
|
||||||
|
while(it3 != mapSeenMasternodeBroadcast.end()){
|
||||||
|
if((*it3).second.lastPing.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
||||||
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode broadcast: hash=%s\n", (*it3).second.GetHash().ToString());
|
||||||
|
mapSeenMasternodeBroadcast.erase(it3++);
|
||||||
|
} else {
|
||||||
|
++it3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove expired mapSeenMasternodePing
|
||||||
|
std::map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
|
||||||
|
while(it4 != mapSeenMasternodePing.end()){
|
||||||
|
if((*it4).second.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
||||||
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode ping: hash=%s\n", (*it4).second.GetHash().ToString());
|
||||||
|
mapSeenMasternodePing.erase(it4++);
|
||||||
|
} else {
|
||||||
|
++it4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove expired mapSeenMasternodeVerification
|
||||||
|
std::map<uint256, CMasternodeVerification>::iterator itv2 = mapSeenMasternodeVerification.begin();
|
||||||
|
while(itv2 != mapSeenMasternodeVerification.end()){
|
||||||
|
if((*itv2).second.nBlockHeight < pCurrentBlockIndex->nHeight - MAX_POSE_BLOCKS){
|
||||||
|
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode verification: hash=%s\n", (*itv2).first.ToString());
|
||||||
|
mapSeenMasternodeVerification.erase(itv2++);
|
||||||
|
} else {
|
||||||
|
++itv2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogPrintf("CMasternodeMan::CheckAndRemove -- %s\n", ToString());
|
||||||
|
|
||||||
|
if(fMasternodesRemoved) {
|
||||||
|
CheckAndRebuildMasternodeIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check who's asked for the Masternode list
|
if(fMasternodesRemoved) {
|
||||||
std::map<CNetAddr, int64_t>::iterator it1 = mAskedUsForMasternodeList.begin();
|
NotifyMasternodeUpdates();
|
||||||
while(it1 != mAskedUsForMasternodeList.end()){
|
|
||||||
if((*it1).second < GetTime()) {
|
|
||||||
mAskedUsForMasternodeList.erase(it1++);
|
|
||||||
} else {
|
|
||||||
++it1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check who we asked for the Masternode list
|
|
||||||
it1 = mWeAskedForMasternodeList.begin();
|
|
||||||
while(it1 != mWeAskedForMasternodeList.end()){
|
|
||||||
if((*it1).second < GetTime()){
|
|
||||||
mWeAskedForMasternodeList.erase(it1++);
|
|
||||||
} else {
|
|
||||||
++it1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check which Masternodes we've asked for
|
|
||||||
std::map<COutPoint, int64_t>::iterator it2 = mWeAskedForMasternodeListEntry.begin();
|
|
||||||
while(it2 != mWeAskedForMasternodeListEntry.end()){
|
|
||||||
if((*it2).second < GetTime()){
|
|
||||||
mWeAskedForMasternodeListEntry.erase(it2++);
|
|
||||||
} else {
|
|
||||||
++it2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<CNetAddr, CMasternodeVerification>::iterator itv1 = mWeAskedForVerification.begin();
|
|
||||||
while(itv1 != mWeAskedForVerification.end()){
|
|
||||||
if(itv1->second.nBlockHeight < pCurrentBlockIndex->nHeight - MAX_POSE_BLOCKS) {
|
|
||||||
mWeAskedForVerification.erase(itv1++);
|
|
||||||
} else {
|
|
||||||
++itv1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove expired mapSeenMasternodeBroadcast
|
|
||||||
std::map<uint256, CMasternodeBroadcast>::iterator it3 = mapSeenMasternodeBroadcast.begin();
|
|
||||||
while(it3 != mapSeenMasternodeBroadcast.end()){
|
|
||||||
if((*it3).second.lastPing.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
|
||||||
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode broadcast: hash=%s\n", (*it3).second.GetHash().ToString());
|
|
||||||
mapSeenMasternodeBroadcast.erase(it3++);
|
|
||||||
} else {
|
|
||||||
++it3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove expired mapSeenMasternodePing
|
|
||||||
std::map<uint256, CMasternodePing>::iterator it4 = mapSeenMasternodePing.begin();
|
|
||||||
while(it4 != mapSeenMasternodePing.end()){
|
|
||||||
if((*it4).second.sigTime < GetTime() - MASTERNODE_REMOVAL_SECONDS*2){
|
|
||||||
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode ping: hash=%s\n", (*it4).second.GetHash().ToString());
|
|
||||||
mapSeenMasternodePing.erase(it4++);
|
|
||||||
} else {
|
|
||||||
++it4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove expired mapSeenMasternodeVerification
|
|
||||||
std::map<uint256, CMasternodeVerification>::iterator itv2 = mapSeenMasternodeVerification.begin();
|
|
||||||
while(itv2 != mapSeenMasternodeVerification.end()){
|
|
||||||
if((*itv2).second.nBlockHeight < pCurrentBlockIndex->nHeight - MAX_POSE_BLOCKS){
|
|
||||||
LogPrint("masternode", "CMasternodeMan::CheckAndRemove -- Removing expired Masternode verification: hash=%s\n", (*itv2).first.ToString());
|
|
||||||
mapSeenMasternodeVerification.erase(itv2++);
|
|
||||||
} else {
|
|
||||||
++itv2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LogPrintf("CMasternodeMan::CheckAndRemove -- %s\n", ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMasternodeMan::Clear()
|
void CMasternodeMan::Clear()
|
||||||
@ -610,20 +695,25 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
|||||||
|
|
||||||
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
|
if (strCommand == NetMsgType::MNANNOUNCE) { //Masternode Broadcast
|
||||||
|
|
||||||
CMasternodeBroadcast mnb;
|
{
|
||||||
vRecv >> mnb;
|
LOCK(cs);
|
||||||
|
|
||||||
int nDos = 0;
|
CMasternodeBroadcast mnb;
|
||||||
|
vRecv >> mnb;
|
||||||
|
|
||||||
if (CheckMnbAndUpdateMasternodeList(mnb, nDos)) {
|
int nDos = 0;
|
||||||
// use announced Masternode as a peer
|
|
||||||
addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60);
|
if (CheckMnbAndUpdateMasternodeList(mnb, nDos)) {
|
||||||
} else if(nDos > 0) {
|
// use announced Masternode as a peer
|
||||||
Misbehaving(pfrom->GetId(), nDos);
|
addrman.Add(CAddress(mnb.addr), pfrom->addr, 2*60*60);
|
||||||
|
} else if(nDos > 0) {
|
||||||
|
Misbehaving(pfrom->GetId(), nDos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fMasternodesAdded) {
|
||||||
|
NotifyMasternodeUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (strCommand == NetMsgType::MNPING) { //Masternode Ping
|
} else if (strCommand == NetMsgType::MNPING) { //Masternode Ping
|
||||||
|
|
||||||
// ignore masternode pings until masternode list is synced
|
// ignore masternode pings until masternode list is synced
|
||||||
if (!masternodeSync.IsMasternodeListSynced()) return;
|
if (!masternodeSync.IsMasternodeListSynced()) return;
|
||||||
|
|
||||||
@ -657,7 +747,6 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
|||||||
AskForMN(pfrom, mnp.vin);
|
AskForMN(pfrom, mnp.vin);
|
||||||
|
|
||||||
} else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry
|
} else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry
|
||||||
|
|
||||||
// Ignore such requests until we are fully synced.
|
// Ignore such requests until we are fully synced.
|
||||||
// We could start processing this after masternode list is synced
|
// We could start processing this after masternode list is synced
|
||||||
// but this is a heavy one so it's better to finish sync first.
|
// but this is a heavy one so it's better to finish sync first.
|
||||||
@ -722,6 +811,8 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData
|
|||||||
|
|
||||||
} else if (strCommand == NetMsgType::MNVERIFY) { // Masternode Verify
|
} else if (strCommand == NetMsgType::MNVERIFY) { // Masternode Verify
|
||||||
|
|
||||||
|
LOCK(cs);
|
||||||
|
|
||||||
CMasternodeVerification mnv;
|
CMasternodeVerification mnv;
|
||||||
vRecv >> mnv;
|
vRecv >> mnv;
|
||||||
|
|
||||||
@ -1290,6 +1381,32 @@ void CMasternodeMan::UpdateLastPaid(const CBlockIndex *pindex)
|
|||||||
IsFirstRun = !masternodeSync.IsWinnersListSynced();
|
IsFirstRun = !masternodeSync.IsWinnersListSynced();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMasternodeMan::CheckAndRebuildMasternodeIndex()
|
||||||
|
{
|
||||||
|
LOCK(cs);
|
||||||
|
|
||||||
|
if(GetTime() - nLastIndexRebuildTime < MIN_INDEX_REBUILD_TIME) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(indexMasternodes.GetSize() <= MAX_EXPECTED_INDEX_SIZE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(indexMasternodes.GetSize() <= int(vMasternodes.size())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexMasternodesOld = indexMasternodes;
|
||||||
|
indexMasternodes.Clear();
|
||||||
|
for(size_t i = 0; i < vMasternodes.size(); ++i) {
|
||||||
|
indexMasternodes.AddMasternodeVIN(vMasternodes[i].vin);
|
||||||
|
}
|
||||||
|
|
||||||
|
fIndexRebuilt = true;
|
||||||
|
nLastIndexRebuildTime = GetTime();
|
||||||
|
}
|
||||||
|
|
||||||
void CMasternodeMan::UpdateWatchdogVoteTime(const CTxIn& vin)
|
void CMasternodeMan::UpdateWatchdogVoteTime(const CTxIn& vin)
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -1406,3 +1523,26 @@ void CMasternodeMan::UpdatedBlockTip(const CBlockIndex *pindex)
|
|||||||
UpdateLastPaid(pindex);
|
UpdateLastPaid(pindex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CMasternodeMan::NotifyMasternodeUpdates()
|
||||||
|
{
|
||||||
|
// Avoid double locking
|
||||||
|
bool fMasternodesAddedLocal = false;
|
||||||
|
bool fMasternodesRemovedLocal = false;
|
||||||
|
{
|
||||||
|
LOCK(cs);
|
||||||
|
fMasternodesAddedLocal = fMasternodesAdded;
|
||||||
|
fMasternodesRemovedLocal = fMasternodesRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fMasternodesAddedLocal) {
|
||||||
|
governance.CheckMasternodeOrphanVotes();
|
||||||
|
}
|
||||||
|
if(fMasternodesRemovedLocal) {
|
||||||
|
governance.UpdateCachesAndClean();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOCK(cs);
|
||||||
|
fMasternodesAdded = false;
|
||||||
|
fMasternodesRemoved = false;
|
||||||
|
}
|
||||||
|
@ -14,9 +14,85 @@ class CMasternodeMan;
|
|||||||
|
|
||||||
extern CMasternodeMan mnodeman;
|
extern CMasternodeMan mnodeman;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a forward and reverse index between MN vin's and integers.
|
||||||
|
*
|
||||||
|
* This mapping is normally add-only and is expected to be permanent
|
||||||
|
* It is only rebuilt if the size of the index exceeds the expected maximum number
|
||||||
|
* of MN's and the current number of known MN's.
|
||||||
|
*
|
||||||
|
* The external interface to this index is provided via delegation by CMasternodeMan
|
||||||
|
*/
|
||||||
|
class CMasternodeIndex
|
||||||
|
{
|
||||||
|
public: // Types
|
||||||
|
typedef std::map<CTxIn,int> index_m_t;
|
||||||
|
|
||||||
|
typedef index_m_t::iterator index_m_it;
|
||||||
|
|
||||||
|
typedef index_m_t::const_iterator index_m_cit;
|
||||||
|
|
||||||
|
typedef std::map<int,CTxIn> rindex_m_t;
|
||||||
|
|
||||||
|
typedef rindex_m_t::iterator rindex_m_it;
|
||||||
|
|
||||||
|
typedef rindex_m_t::const_iterator rindex_m_cit;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int nSize;
|
||||||
|
|
||||||
|
index_m_t mapIndex;
|
||||||
|
|
||||||
|
rindex_m_t mapReverseIndex;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CMasternodeIndex();
|
||||||
|
|
||||||
|
int GetSize() const {
|
||||||
|
return nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve masternode vin by index
|
||||||
|
bool Get(int nIndex, CTxIn& vinMasternode) const;
|
||||||
|
|
||||||
|
/// Get index of a masternode vin
|
||||||
|
int GetMasternodeIndex(const CTxIn& vinMasternode) const;
|
||||||
|
|
||||||
|
void AddMasternodeVIN(const CTxIn& vinMasternode);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
|
template <typename Stream, typename Operation>
|
||||||
|
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
READWRITE(mapIndex);
|
||||||
|
if(ser_action.ForRead()) {
|
||||||
|
RebuildIndex();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void RebuildIndex();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class CMasternodeMan
|
class CMasternodeMan
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
typedef std::map<CTxIn,int> index_m_t;
|
||||||
|
|
||||||
|
typedef index_m_t::iterator index_m_it;
|
||||||
|
|
||||||
|
typedef index_m_t::const_iterator index_m_cit;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const int MAX_EXPECTED_INDEX_SIZE = 30000;
|
||||||
|
|
||||||
|
/// Only allow 1 index rebuild per hour
|
||||||
|
static const int64_t MIN_INDEX_REBUILD_TIME = 3600;
|
||||||
|
|
||||||
static const std::string SERIALIZATION_VERSION_STRING;
|
static const std::string SERIALIZATION_VERSION_STRING;
|
||||||
|
|
||||||
static const int DSEG_UPDATE_SECONDS = 3 * 60 * 60;
|
static const int DSEG_UPDATE_SECONDS = 3 * 60 * 60;
|
||||||
@ -45,6 +121,21 @@ private:
|
|||||||
// who we asked for the masternode verification
|
// who we asked for the masternode verification
|
||||||
std::map<CNetAddr, CMasternodeVerification> mWeAskedForVerification;
|
std::map<CNetAddr, CMasternodeVerification> mWeAskedForVerification;
|
||||||
|
|
||||||
|
int64_t nLastIndexRebuildTime;
|
||||||
|
|
||||||
|
CMasternodeIndex indexMasternodes;
|
||||||
|
|
||||||
|
CMasternodeIndex indexMasternodesOld;
|
||||||
|
|
||||||
|
/// Set when index has been rebuilt, clear when read
|
||||||
|
bool fIndexRebuilt;
|
||||||
|
|
||||||
|
/// Set when masternodes are added, cleared when CGovernanceManager is notified
|
||||||
|
bool fMasternodesAdded;
|
||||||
|
|
||||||
|
/// Set when masternodes are removed, cleared when CGovernanceManager is notified
|
||||||
|
bool fMasternodesRemoved;
|
||||||
|
|
||||||
std::vector<uint256> vecDirtyGovernanceObjectHashes;
|
std::vector<uint256> vecDirtyGovernanceObjectHashes;
|
||||||
|
|
||||||
int64_t nLastWatchdogVoteTime;
|
int64_t nLastWatchdogVoteTime;
|
||||||
@ -62,8 +153,6 @@ public:
|
|||||||
int64_t nDsqCount;
|
int64_t nDsqCount;
|
||||||
|
|
||||||
|
|
||||||
CMasternodeMan() : nLastWatchdogVoteTime(0), nDsqCount(0) {}
|
|
||||||
|
|
||||||
ADD_SERIALIZE_METHODS;
|
ADD_SERIALIZE_METHODS;
|
||||||
|
|
||||||
template <typename Stream, typename Operation>
|
template <typename Stream, typename Operation>
|
||||||
@ -87,16 +176,19 @@ public:
|
|||||||
|
|
||||||
READWRITE(mapSeenMasternodeBroadcast);
|
READWRITE(mapSeenMasternodeBroadcast);
|
||||||
READWRITE(mapSeenMasternodePing);
|
READWRITE(mapSeenMasternodePing);
|
||||||
|
READWRITE(indexMasternodes);
|
||||||
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
|
if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) {
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CMasternodeMan();
|
||||||
|
|
||||||
/// Add an entry
|
/// Add an entry
|
||||||
bool Add(CMasternode &mn);
|
bool Add(CMasternode &mn);
|
||||||
|
|
||||||
/// Ask (source) node for mnb
|
/// Ask (source) node for mnb
|
||||||
void AskForMN(CNode *pnode, CTxIn &vin);
|
void AskForMN(CNode *pnode, const CTxIn &vin);
|
||||||
|
|
||||||
/// Check all Masternodes
|
/// Check all Masternodes
|
||||||
void Check();
|
void Check();
|
||||||
@ -128,6 +220,49 @@ public:
|
|||||||
bool Get(const CPubKey& pubKeyMasternode, CMasternode& masternode);
|
bool Get(const CPubKey& pubKeyMasternode, CMasternode& masternode);
|
||||||
bool Get(const CTxIn& vin, CMasternode& masternode);
|
bool Get(const CTxIn& vin, CMasternode& masternode);
|
||||||
|
|
||||||
|
/// Retrieve masternode vin by index
|
||||||
|
bool Get(int nIndex, CTxIn& vinMasternode, bool& fIndexRebuiltOut) {
|
||||||
|
LOCK(cs);
|
||||||
|
fIndexRebuiltOut = fIndexRebuilt;
|
||||||
|
return indexMasternodes.Get(nIndex, vinMasternode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetIndexRebuiltFlag() {
|
||||||
|
LOCK(cs);
|
||||||
|
return fIndexRebuilt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get index of a masternode vin
|
||||||
|
int GetMasternodeIndex(const CTxIn& vinMasternode) {
|
||||||
|
LOCK(cs);
|
||||||
|
return indexMasternodes.GetMasternodeIndex(vinMasternode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get old index of a masternode vin
|
||||||
|
int GetMasternodeIndexOld(const CTxIn& vinMasternode) {
|
||||||
|
LOCK(cs);
|
||||||
|
return indexMasternodesOld.GetMasternodeIndex(vinMasternode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get masternode VIN for an old index value
|
||||||
|
bool GetMasternodeVinForIndexOld(int nMasternodeIndex, CTxIn& vinMasternodeOut) {
|
||||||
|
LOCK(cs);
|
||||||
|
return indexMasternodesOld.Get(nMasternodeIndex, vinMasternodeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get index of a masternode vin, returning rebuild flag
|
||||||
|
int GetMasternodeIndex(const CTxIn& vinMasternode, bool& fIndexRebuiltOut) {
|
||||||
|
LOCK(cs);
|
||||||
|
fIndexRebuiltOut = fIndexRebuilt;
|
||||||
|
return indexMasternodes.GetMasternodeIndex(vinMasternode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearOldMasternodeIndex() {
|
||||||
|
LOCK(cs);
|
||||||
|
indexMasternodesOld.Clear();
|
||||||
|
fIndexRebuilt = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Has(const CTxIn& vin);
|
bool Has(const CTxIn& vin);
|
||||||
|
|
||||||
masternode_info_t GetMasternodeInfo(const CTxIn& vin);
|
masternode_info_t GetMasternodeInfo(const CTxIn& vin);
|
||||||
@ -173,6 +308,8 @@ public:
|
|||||||
|
|
||||||
void UpdateLastPaid(const CBlockIndex *pindex);
|
void UpdateLastPaid(const CBlockIndex *pindex);
|
||||||
|
|
||||||
|
void CheckAndRebuildMasternodeIndex();
|
||||||
|
|
||||||
void AddDirtyGovernanceObjectHash(const uint256& nHash)
|
void AddDirtyGovernanceObjectHash(const uint256& nHash)
|
||||||
{
|
{
|
||||||
LOCK(cs);
|
LOCK(cs);
|
||||||
@ -202,6 +339,13 @@ public:
|
|||||||
void SetMasternodeLastPing(const CTxIn& vin, const CMasternodePing& mnp);
|
void SetMasternodeLastPing(const CTxIn& vin, const CMasternodePing& mnp);
|
||||||
|
|
||||||
void UpdatedBlockTip(const CBlockIndex *pindex);
|
void UpdatedBlockTip(const CBlockIndex *pindex);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to notify CGovernanceManager that the masternode index has been updated.
|
||||||
|
* Must be called while not holding the CMasternodeMan::cs mutex
|
||||||
|
*/
|
||||||
|
void NotifyMasternodeUpdates();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -106,6 +106,7 @@ void MasternodeList::StartAlias(std::string strAlias)
|
|||||||
strStatusHtml += "<br>Successfully started masternode.";
|
strStatusHtml += "<br>Successfully started masternode.";
|
||||||
mnodeman.UpdateMasternodeList(mnb);
|
mnodeman.UpdateMasternodeList(mnb);
|
||||||
mnb.Relay();
|
mnb.Relay();
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
} else {
|
} else {
|
||||||
strStatusHtml += "<br>Failed to start masternode.<br>Error: " + strError;
|
strStatusHtml += "<br>Failed to start masternode.<br>Error: " + strError;
|
||||||
}
|
}
|
||||||
@ -142,6 +143,7 @@ void MasternodeList::StartAll(std::string strCommand)
|
|||||||
nCountSuccessful++;
|
nCountSuccessful++;
|
||||||
mnodeman.UpdateMasternodeList(mnb);
|
mnodeman.UpdateMasternodeList(mnb);
|
||||||
mnb.Relay();
|
mnb.Relay();
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
} else {
|
} else {
|
||||||
nCountFailed++;
|
nCountFailed++;
|
||||||
strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
|
strFailedHtml += "\nFailed to start " + mne.getAlias() + ". Error: " + strError;
|
||||||
|
@ -283,16 +283,15 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
return returnObj;
|
return returnObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strError = "";
|
CGovernanceException exception;
|
||||||
if(governance.AddOrUpdateVote(vote, NULL, strError)) {
|
if(governance.ProcessVote(vote, exception)) {
|
||||||
governance.AddSeenVote(vote.GetHash(), SEEN_OBJECT_IS_VALID);
|
|
||||||
vote.Relay();
|
|
||||||
success++;
|
success++;
|
||||||
statusObj.push_back(Pair("result", "success"));
|
statusObj.push_back(Pair("result", "success"));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
failed++;
|
failed++;
|
||||||
statusObj.push_back(Pair("result", "failed"));
|
statusObj.push_back(Pair("result", "failed"));
|
||||||
statusObj.push_back(Pair("errorMessage", strError.c_str()));
|
statusObj.push_back(Pair("errorMessage", exception.GetMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
resultsObj.push_back(Pair("dash.conf", statusObj));
|
resultsObj.push_back(Pair("dash.conf", statusObj));
|
||||||
@ -386,15 +385,15 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(governance.AddOrUpdateVote(vote, NULL, strError)) {
|
CGovernanceException exception;
|
||||||
governance.AddSeenVote(vote.GetHash(), SEEN_OBJECT_IS_VALID);
|
if(governance.ProcessVote(vote, exception)) {
|
||||||
vote.Relay();
|
|
||||||
success++;
|
success++;
|
||||||
statusObj.push_back(Pair("result", "success"));
|
statusObj.push_back(Pair("result", "success"));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
failed++;
|
failed++;
|
||||||
statusObj.push_back(Pair("result", "failed"));
|
statusObj.push_back(Pair("result", "failed"));
|
||||||
statusObj.push_back(Pair("errorMessage", strError.c_str()));
|
statusObj.push_back(Pair("errorMessage", exception.GetMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
|
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
|
||||||
@ -511,15 +510,15 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
// UPDATE LOCAL DATABASE WITH NEW OBJECT SETTINGS
|
// UPDATE LOCAL DATABASE WITH NEW OBJECT SETTINGS
|
||||||
|
|
||||||
if(governance.AddOrUpdateVote(vote, NULL, strError)) {
|
CGovernanceException exception;
|
||||||
governance.AddSeenVote(vote.GetHash(), SEEN_OBJECT_IS_VALID);
|
if(governance.ProcessVote(vote, exception)) {
|
||||||
vote.Relay();
|
|
||||||
success++;
|
success++;
|
||||||
statusObj.push_back(Pair("result", "success"));
|
statusObj.push_back(Pair("result", "success"));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
failed++;
|
failed++;
|
||||||
statusObj.push_back(Pair("result", "failed"));
|
statusObj.push_back(Pair("result", "failed"));
|
||||||
statusObj.push_back(Pair("errorMessage", strError.c_str()));
|
statusObj.push_back(Pair("errorMessage", exception.GetMessage()));
|
||||||
}
|
}
|
||||||
|
|
||||||
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
|
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
|
||||||
@ -573,13 +572,13 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
BOOST_FOREACH(CGovernanceObject* pGovObj, objs)
|
BOOST_FOREACH(CGovernanceObject* pGovObj, objs)
|
||||||
{
|
{
|
||||||
// IF WE HAVE A SPECIFIC NODE REQUESTED TO VOTE, DO THAT
|
// IF WE HAVE A SPECIFIC NODE REQUESTED TO VOTE, DO THAT
|
||||||
if(strShow == "valid" && !pGovObj->fCachedValid) continue;
|
if(strShow == "valid" && !pGovObj->IsSetCachedValid()) continue;
|
||||||
|
|
||||||
UniValue bObj(UniValue::VOBJ);
|
UniValue bObj(UniValue::VOBJ);
|
||||||
bObj.push_back(Pair("DataHex", pGovObj->GetDataAsHex()));
|
bObj.push_back(Pair("DataHex", pGovObj->GetDataAsHex()));
|
||||||
bObj.push_back(Pair("DataString", pGovObj->GetDataAsString()));
|
bObj.push_back(Pair("DataString", pGovObj->GetDataAsString()));
|
||||||
bObj.push_back(Pair("Hash", pGovObj->GetHash().ToString()));
|
bObj.push_back(Pair("Hash", pGovObj->GetHash().ToString()));
|
||||||
bObj.push_back(Pair("CollateralHash", pGovObj->nCollateralHash.ToString()));
|
bObj.push_back(Pair("CollateralHash", pGovObj->GetCollateralHash().ToString()));
|
||||||
|
|
||||||
// REPORT STATUS FOR FUNDING VOTES SPECIFICALLY
|
// REPORT STATUS FOR FUNDING VOTES SPECIFICALLY
|
||||||
bObj.push_back(Pair("AbsoluteYesCount", pGovObj->GetAbsoluteYesCount(VOTE_SIGNAL_FUNDING)));
|
bObj.push_back(Pair("AbsoluteYesCount", pGovObj->GetAbsoluteYesCount(VOTE_SIGNAL_FUNDING)));
|
||||||
@ -591,10 +590,10 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
std::string strError = "";
|
std::string strError = "";
|
||||||
bObj.push_back(Pair("fBlockchainValidity", pGovObj->IsValidLocally(pindex , strError, false)));
|
bObj.push_back(Pair("fBlockchainValidity", pGovObj->IsValidLocally(pindex , strError, false)));
|
||||||
bObj.push_back(Pair("IsValidReason", strError.c_str()));
|
bObj.push_back(Pair("IsValidReason", strError.c_str()));
|
||||||
bObj.push_back(Pair("fCachedValid", pGovObj->fCachedValid));
|
bObj.push_back(Pair("fCachedValid", pGovObj->IsSetCachedValid()));
|
||||||
bObj.push_back(Pair("fCachedFunding", pGovObj->fCachedFunding));
|
bObj.push_back(Pair("fCachedFunding", pGovObj->IsSetCachedFunding()));
|
||||||
bObj.push_back(Pair("fCachedDelete", pGovObj->fCachedDelete));
|
bObj.push_back(Pair("fCachedDelete", pGovObj->IsSetCachedDelete()));
|
||||||
bObj.push_back(Pair("fCachedEndorsed", pGovObj->fCachedEndorsed));
|
bObj.push_back(Pair("fCachedEndorsed", pGovObj->IsSetCachedEndorsed()));
|
||||||
|
|
||||||
objResult.push_back(Pair(pGovObj->GetHash().ToString(), bObj));
|
objResult.push_back(Pair(pGovObj->GetHash().ToString(), bObj));
|
||||||
}
|
}
|
||||||
@ -625,7 +624,7 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
objResult.push_back(Pair("DataHex", pGovObj->GetDataAsHex()));
|
objResult.push_back(Pair("DataHex", pGovObj->GetDataAsHex()));
|
||||||
objResult.push_back(Pair("DataString", pGovObj->GetDataAsString()));
|
objResult.push_back(Pair("DataString", pGovObj->GetDataAsString()));
|
||||||
objResult.push_back(Pair("Hash", pGovObj->GetHash().ToString()));
|
objResult.push_back(Pair("Hash", pGovObj->GetHash().ToString()));
|
||||||
objResult.push_back(Pair("CollateralHash", pGovObj->nCollateralHash.ToString()));
|
objResult.push_back(Pair("CollateralHash", pGovObj->GetCollateralHash().ToString()));
|
||||||
|
|
||||||
// SHOW (MUCH MORE) INFORMATION ABOUT VOTES FOR GOVERNANCE OBJECT (THAN LIST/DIFF ABOVE)
|
// SHOW (MUCH MORE) INFORMATION ABOUT VOTES FOR GOVERNANCE OBJECT (THAN LIST/DIFF ABOVE)
|
||||||
// -- FUNDING VOTING RESULTS
|
// -- FUNDING VOTING RESULTS
|
||||||
@ -665,11 +664,10 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
std::string strError = "";
|
std::string strError = "";
|
||||||
objResult.push_back(Pair("fLocalValidity", pGovObj->IsValidLocally(chainActive.Tip(), strError, false)));
|
objResult.push_back(Pair("fLocalValidity", pGovObj->IsValidLocally(chainActive.Tip(), strError, false)));
|
||||||
objResult.push_back(Pair("IsValidReason", strError.c_str()));
|
objResult.push_back(Pair("IsValidReason", strError.c_str()));
|
||||||
objResult.push_back(Pair("fCachedValid", pGovObj->fCachedValid));
|
objResult.push_back(Pair("fCachedValid", pGovObj->IsSetCachedValid()));
|
||||||
objResult.push_back(Pair("fCachedFunding", pGovObj->fCachedFunding));
|
objResult.push_back(Pair("fCachedFunding", pGovObj->IsSetCachedFunding()));
|
||||||
objResult.push_back(Pair("fCachedDelete", pGovObj->fCachedDelete));
|
objResult.push_back(Pair("fCachedDelete", pGovObj->IsSetCachedDelete()));
|
||||||
objResult.push_back(Pair("fCachedEndorsed", pGovObj->fCachedEndorsed));
|
objResult.push_back(Pair("fCachedEndorsed", pGovObj->IsSetCachedEndorsed()));
|
||||||
|
|
||||||
return objResult;
|
return objResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,9 +699,9 @@ UniValue gobject(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
// GET MATCHING VOTES BY HASH, THEN SHOW USERS VOTE INFORMATION
|
// GET MATCHING VOTES BY HASH, THEN SHOW USERS VOTE INFORMATION
|
||||||
|
|
||||||
std::vector<CGovernanceVote*> vecVotes = governance.GetMatchingVotes(hash);
|
std::vector<CGovernanceVote> vecVotes = governance.GetMatchingVotes(hash);
|
||||||
BOOST_FOREACH(CGovernanceVote* pVote, vecVotes) {
|
BOOST_FOREACH(CGovernanceVote vote, vecVotes) {
|
||||||
bResult.push_back(Pair(pVote->GetHash().ToString(), pVote->ToString()));
|
bResult.push_back(Pair(vote.GetHash().ToString(), vote.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return bResult;
|
return bResult;
|
||||||
@ -764,13 +762,12 @@ UniValue voteraw(const UniValue& params, bool fHelp)
|
|||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to verify vote.");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to verify vote.");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string strError = "";
|
CGovernanceException exception;
|
||||||
if(governance.AddOrUpdateVote(vote, NULL, strError)) {
|
if(governance.ProcessVote(vote, exception)) {
|
||||||
governance.AddSeenVote(vote.GetHash(), SEEN_OBJECT_IS_VALID);
|
|
||||||
vote.Relay();
|
|
||||||
return "Voted successfully";
|
return "Voted successfully";
|
||||||
} else {
|
}
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error voting : " + strError);
|
else {
|
||||||
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error voting : " + exception.GetMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +272,7 @@ UniValue masternode(const UniValue& params, bool fHelp)
|
|||||||
} else {
|
} else {
|
||||||
statusObj.push_back(Pair("errorMessage", strError));
|
statusObj.push_back(Pair("errorMessage", strError));
|
||||||
}
|
}
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -328,6 +329,7 @@ UniValue masternode(const UniValue& params, bool fHelp)
|
|||||||
|
|
||||||
resultsObj.push_back(Pair("status", statusObj));
|
resultsObj.push_back(Pair("status", statusObj));
|
||||||
}
|
}
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
|
|
||||||
UniValue returnObj(UniValue::VOBJ);
|
UniValue returnObj(UniValue::VOBJ);
|
||||||
returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed)));
|
returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", nSuccessful, nFailed, nSuccessful + nFailed)));
|
||||||
@ -781,6 +783,7 @@ UniValue masternodebroadcast(const UniValue& params, bool fHelp)
|
|||||||
mnb.Relay();
|
mnb.Relay();
|
||||||
fResult = true;
|
fResult = true;
|
||||||
}
|
}
|
||||||
|
mnodeman.NotifyMasternodeUpdates();
|
||||||
} else fResult = false;
|
} else fResult = false;
|
||||||
|
|
||||||
if(fResult) {
|
if(fResult) {
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -886,6 +887,39 @@ void Unserialize(Stream& is, std::set<K, Pred, A>& m, int nType, int nVersion)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list
|
||||||
|
*/
|
||||||
|
template<typename T, typename A>
|
||||||
|
unsigned int GetSerializeSize(const std::list<T, A>& l, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
unsigned int nSize = GetSizeOfCompactSize(l.size());
|
||||||
|
for (typename std::list<T, A>::const_iterator it = l.begin(); it != l.end(); ++it)
|
||||||
|
nSize += GetSerializeSize((*it), nType, nVersion);
|
||||||
|
return nSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Stream, typename T, typename A>
|
||||||
|
void Serialize(Stream& os, const std::list<T, A>& l, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
WriteCompactSize(os, l.size());
|
||||||
|
for (typename std::list<T, A>::const_iterator it = l.begin(); it != l.end(); ++it)
|
||||||
|
Serialize(os, (*it), nType, nVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Stream, typename T, typename A>
|
||||||
|
void Unserialize(Stream& is, std::list<T, A>& l, int nType, int nVersion)
|
||||||
|
{
|
||||||
|
l.clear();
|
||||||
|
unsigned int nSize = ReadCompactSize(is);
|
||||||
|
for (unsigned int i = 0; i < nSize; i++)
|
||||||
|
{
|
||||||
|
T val;
|
||||||
|
Unserialize(is, val, nType, nVersion);
|
||||||
|
l.push_back(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
127
src/test/cachemap_tests.cpp
Normal file
127
src/test/cachemap_tests.cpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
|
||||||
|
#include "cachemap.h"
|
||||||
|
|
||||||
|
#include "test/test_dash.h"
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(cachemap_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
bool Compare(const CacheMap<int,int>& map1, const CacheMap<int,int>& map2 )
|
||||||
|
{
|
||||||
|
if(map1.GetMaxSize() != map2.GetMaxSize()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map1.GetSize() != map2.GetSize()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CacheMap<int,int>::list_t& items1 = map1.GetItemList();
|
||||||
|
for(CacheMap<int,int>::list_cit it = items1.begin(); it != items1.end(); ++it) {
|
||||||
|
if(!map2.HasKey(it->key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int val = 0;
|
||||||
|
if(!map2.Get(it->key, val)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(it->value != val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CacheMap<int,int>::list_t& items2 = map2.GetItemList();
|
||||||
|
for(CacheMap<int,int>::list_cit it = items2.begin(); it != items2.end(); ++it) {
|
||||||
|
if(!map1.HasKey(it->key)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int val = 0;
|
||||||
|
if(!map1.Get(it->key, val)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(it->value != val) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(cachemap_test)
|
||||||
|
{
|
||||||
|
// create a CacheMap limited to 10 items
|
||||||
|
CacheMap<int,int> mapTest1(10);
|
||||||
|
|
||||||
|
// check that the max size is 10
|
||||||
|
BOOST_CHECK(mapTest1.GetMaxSize() == 10);
|
||||||
|
|
||||||
|
// check that the size is 0
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 0);
|
||||||
|
|
||||||
|
// insert (-1, -1)
|
||||||
|
mapTest1.Insert(-1, -1);
|
||||||
|
|
||||||
|
// make sure that the size is updated
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 1);
|
||||||
|
|
||||||
|
// make sure the map contains the key
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(-1) == true);
|
||||||
|
|
||||||
|
// add 10 items
|
||||||
|
for(int i = 0; i < 10; ++i) {
|
||||||
|
mapTest1.Insert(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the size is 10
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 10);
|
||||||
|
|
||||||
|
// check that the map contains the expected items
|
||||||
|
for(int i = 0; i < 10; ++i) {
|
||||||
|
int nVal = 0;
|
||||||
|
BOOST_CHECK(mapTest1.Get(i, nVal) == true);
|
||||||
|
BOOST_CHECK(nVal == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the map no longer contains the first item
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(-1) == false);
|
||||||
|
|
||||||
|
// erase an item
|
||||||
|
mapTest1.Erase(5);
|
||||||
|
|
||||||
|
// check the size
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 9);
|
||||||
|
|
||||||
|
// check that the map no longer contains the item
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(5) == false);
|
||||||
|
|
||||||
|
// check that the map contains the expected items
|
||||||
|
int expected[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9 };
|
||||||
|
for(size_t i = 0; i < 9; ++i) {
|
||||||
|
int nVal = 0;
|
||||||
|
int eVal = expected[i];
|
||||||
|
BOOST_CHECK(mapTest1.Get(eVal, nVal) == true);
|
||||||
|
BOOST_CHECK(nVal == eVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test serialization
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << mapTest1;
|
||||||
|
|
||||||
|
CacheMap<int,int> mapTest2;
|
||||||
|
ss >> mapTest2;
|
||||||
|
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest2));
|
||||||
|
|
||||||
|
// test copy constructor
|
||||||
|
CacheMap<int,int> mapTest3(mapTest1);
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest3));
|
||||||
|
|
||||||
|
// test assignment operator
|
||||||
|
CacheMap<int,int> mapTest4;
|
||||||
|
mapTest4 = mapTest1;
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest4));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
176
src/test/cachemultimap_tests.cpp
Normal file
176
src/test/cachemultimap_tests.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
// Copyright (c) 2014-2016 The Dash Core developers
|
||||||
|
|
||||||
|
#include "cachemultimap.h"
|
||||||
|
|
||||||
|
#include "test/test_dash.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(cachemultimap_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
void DumpMap(const CacheMultiMap<int,int>& map)
|
||||||
|
{
|
||||||
|
const CacheMultiMap<int,int>::list_t& listItems = map.GetItemList();
|
||||||
|
for(CacheMultiMap<int,int>::list_cit it = listItems.begin(); it != listItems.end(); ++it) {
|
||||||
|
const CacheItem<int,int>& item = *it;
|
||||||
|
std::cout << item.key << " : " << item.value << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Compare(const CacheMultiMap<int,int>& map1, const CacheMultiMap<int,int>& map2 )
|
||||||
|
{
|
||||||
|
if(map1.GetMaxSize() != map2.GetMaxSize()) {
|
||||||
|
std::cout << "Compare returning false: max size mismatch" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(map1.GetSize() != map2.GetSize()) {
|
||||||
|
std::cout << "Compare returning false: size mismatch" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CacheMultiMap<int,int>::list_t& items1 = map1.GetItemList();
|
||||||
|
const CacheMultiMap<int,int>::list_t& items2 = map2.GetItemList();
|
||||||
|
CacheMultiMap<int,int>::list_cit it2 = items2.begin();
|
||||||
|
for(CacheMultiMap<int,int>::list_cit it1 = items1.begin(); it1 != items1.end(); ++it1) {
|
||||||
|
const CacheItem<int,int>& item1 = *it1;
|
||||||
|
const CacheItem<int,int>& item2 = *it2;
|
||||||
|
if(item1.key != item2.key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(item1.value != item2.value) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CheckExpected(const CacheMultiMap<int,int>& map, int* expected, CacheMultiMap<int,int>::size_type nSize)
|
||||||
|
{
|
||||||
|
if(map.GetSize() != nSize) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(CacheMultiMap<int,int>::size_type i = 0; i < nSize; ++i) {
|
||||||
|
int nVal = 0;
|
||||||
|
int eVal = expected[i];
|
||||||
|
if(!map.Get(eVal, nVal)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(nVal != eVal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(cachemultimap_test)
|
||||||
|
{
|
||||||
|
// create a CacheMultiMap limited to 10 items
|
||||||
|
CacheMultiMap<int,int> mapTest1(10);
|
||||||
|
|
||||||
|
// check that the max size is 10
|
||||||
|
BOOST_CHECK(mapTest1.GetMaxSize() == 10);
|
||||||
|
|
||||||
|
// check that the size is 0
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 0);
|
||||||
|
|
||||||
|
// insert (-1, -1)
|
||||||
|
mapTest1.Insert(-1, -1);
|
||||||
|
|
||||||
|
// make sure that the size is updated
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 1);
|
||||||
|
|
||||||
|
// make sure the map contains the key
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(-1) == true);
|
||||||
|
|
||||||
|
// add 10 items
|
||||||
|
for(int i = 0; i < 10; ++i) {
|
||||||
|
mapTest1.Insert(i, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the size is 10
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 10);
|
||||||
|
|
||||||
|
// check that the map contains the expected items
|
||||||
|
for(int i = 0; i < 10; ++i) {
|
||||||
|
int nVal = 0;
|
||||||
|
BOOST_CHECK(mapTest1.Get(i, nVal) == true);
|
||||||
|
BOOST_CHECK(nVal == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the map no longer contains the first item
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(-1) == false);
|
||||||
|
|
||||||
|
// erase an item
|
||||||
|
mapTest1.Erase(5);
|
||||||
|
|
||||||
|
// check the size
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 9);
|
||||||
|
|
||||||
|
// check that the map no longer contains the item
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(5) == false);
|
||||||
|
|
||||||
|
// check that the map contains the expected items
|
||||||
|
int expected[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9 };
|
||||||
|
BOOST_CHECK(CheckExpected(mapTest1, expected, 9 ) == true);
|
||||||
|
|
||||||
|
// add multiple items for the same key
|
||||||
|
mapTest1.Insert(5, 2);
|
||||||
|
mapTest1.Insert(5, 1);
|
||||||
|
mapTest1.Insert(5, 4);
|
||||||
|
|
||||||
|
// check the size
|
||||||
|
BOOST_CHECK(mapTest1.GetSize() == 10);
|
||||||
|
|
||||||
|
// check that 2 keys have been removed
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(0) == false);
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(1) == false);
|
||||||
|
BOOST_CHECK(mapTest1.HasKey(2) == true);
|
||||||
|
|
||||||
|
// check multiple values
|
||||||
|
std::vector<int> vecVals;
|
||||||
|
BOOST_CHECK(mapTest1.GetAll(5, vecVals) == true);
|
||||||
|
BOOST_CHECK(vecVals.size() == 3);
|
||||||
|
BOOST_CHECK(vecVals[0] == 1);
|
||||||
|
BOOST_CHECK(vecVals[1] == 2);
|
||||||
|
BOOST_CHECK(vecVals[2] == 4);
|
||||||
|
|
||||||
|
// std::cout << "mapTest1 dump:" << std::endl;
|
||||||
|
// DumpMap(mapTest1);
|
||||||
|
|
||||||
|
// test serialization
|
||||||
|
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
ss << mapTest1;
|
||||||
|
|
||||||
|
CacheMultiMap<int,int> mapTest2;
|
||||||
|
ss >> mapTest2;
|
||||||
|
|
||||||
|
// std::cout << "mapTest2 dump:" << std::endl;
|
||||||
|
// DumpMap(mapTest2);
|
||||||
|
|
||||||
|
// check multiple values
|
||||||
|
std::vector<int> vecVals2;
|
||||||
|
BOOST_CHECK(mapTest2.GetAll(5, vecVals2) == true);
|
||||||
|
BOOST_CHECK(vecVals2.size() == 3);
|
||||||
|
BOOST_CHECK(vecVals2[0] == 1);
|
||||||
|
BOOST_CHECK(vecVals2[1] == 2);
|
||||||
|
BOOST_CHECK(vecVals2[2] == 4);
|
||||||
|
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest2));
|
||||||
|
|
||||||
|
// test copy constructor
|
||||||
|
CacheMultiMap<int,int> mapTest3(mapTest1);
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest3));
|
||||||
|
|
||||||
|
// test assignment operator
|
||||||
|
CacheMultiMap<int,int> mapTest4;
|
||||||
|
mapTest4 = mapTest1;
|
||||||
|
BOOST_CHECK(Compare(mapTest1, mapTest4));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user