2014-02-19 11:08:37 +00:00
/*
* libretroshare / src / services p3gxsreputation . cc
*
* Gxs Reputation Service for RetroShare .
*
* Copyright 2011 - 2014 by Robert Fernie .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2.1 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " retroshare@lunamutt.com " .
*
*/
2015-10-25 22:54:56 -04:00
# include <math.h>
2014-02-19 11:08:37 +00:00
# include "pqi/p3linkmgr.h"
# include "retroshare/rspeers.h"
# include "services/p3gxsreputation.h"
2017-04-24 22:47:08 +02:00
2017-04-22 21:36:39 +02:00
# include "rsitems/rsgxsreputationitems.h"
2017-04-24 22:47:08 +02:00
# include "rsitems/rsconfigitems.h"
2014-02-19 11:08:37 +00:00
# include <sys/time.h>
# include <set>
/****
* # define DEBUG_REPUTATION 1
* * * */
/************ IMPLEMENTATION NOTES *********************************
*
* p3GxsReputation shares opinions / reputations with peers .
* This is closely linked to p3IdService , receiving info , updating
* reputations as needed .
*
* It is designed as separate service as the exchange of peer opinions
* is not well suited to Gxs Groups / Messages . . .
*
* Instead we can broadcast opinions to all peers .
*
* To avoid too much traffic , changes are transmitted rather than whole lists .
* Peer A Peer B
* last update - - - - - - - - - - - >
* < - - - - - - - - - - - modified opinions .
*
2015-10-07 23:44:24 -04:00
* If not clever enough , this service will have to store a huge amount of data .
* To make things tractable we do this :
* - do not store reputations when no data is present , or when all friends are neutral
* - only send a neutral opinion when they are a true change over someone ' s opinion
* - only send a neutral opinion when it is a true change over someone ' s opinion
* - auto - clean reputations for default values
2014-02-19 11:08:37 +00:00
*
* std : : map < RsGxsId , Reputation > mReputations .
* std : : multimap < time_t , RsGxsId > mUpdated .
*
* std : : map < RsPeerId , ReputationConfig > mConfig ;
*
* Updates from p3GxsReputation - > p3IdService .
* Updates from p3IdService - > p3GxsReputation .
*
2015-10-06 23:56:39 -04:00
* Each peer locally stores reputations for all GXS ids . If not stored , a default value
* is used , corresponding to a neutral opinion . Peers also share their reputation level
* with their neighbor nodes .
*
* The calculation method is the following :
*
* Local values :
* Good : 2
* Neutral : 1
* Bad : 0
2014-02-19 11:08:37 +00:00
*
2015-10-06 23:56:39 -04:00
* Overall reputation score :
*
* if ( own_opinion = = 0 ) // means we dont' care
* r = average_of_friends_opinions
* else
* r = own_opinion
*
* Decisions based on reputation score :
*
* 0 x1 1 x2 2
* | < - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - > |
* - - - - - - - - - +
* Lobbies | Msgs dropped
* Forums | Msgs dropped
* Messages | Msgs dropped
* - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* We select x1 = 0.5
*
* = > to kill an identity , either you , or at least 50 % of your friends need to flag it
* as bad .
* Rules :
* * a single peer cannot drastically change the behavior of a given GXS id
* * it should be easy for many peers to globally kill a GXS id
*
* Typical examples :
*
* Friends | Friend average | Own | alpha | Score
* - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + - - - - - - - - - - - - + - - - - - - - - - - - - - -
* 10 | 0.5 | 1 | 0.25 | 0.375
* 10 | 1.0 | 1 | 0.25 | 1.0
* 10 | 1.0 | 0 | 0.25 | 1.0
*
* To check :
2016-07-03 18:59:30 -04:00
* [ X ] Opinions are saved / loaded accross restart
* [ X ] Opinions are transmitted to friends
* [ X ] Opinions are transmitted to friends when updated
2015-10-06 23:56:39 -04:00
*
* To do :
2016-07-03 18:59:30 -04:00
* [ X ] Add debug info
* [ X ] Test the whole thing
2015-10-08 18:39:50 -04:00
* [ X ] Implement a system to allow not storing info when we don ' t have it
2014-02-19 11:08:37 +00:00
*/
2015-10-08 23:54:18 -04:00
static const uint32_t LOWER_LIMIT = 0 ; // used to filter valid Opinion values from serialized data
static const uint32_t UPPER_LIMIT = 2 ; // used to filter valid Opinion values from serialized data
static const int kMaximumPeerAge = 180 ; // half a year.
static const int kMaximumSetSize = 100 ; // max set of updates to send at once.
2017-01-08 22:00:54 +01:00
static const int CLEANUP_PERIOD = 600 ; // 10 minutes
2015-10-08 23:54:18 -04:00
static const int ACTIVE_FRIENDS_ONLINE_DELAY = 86400 * 7 ; // 1 week.
2015-10-27 00:02:16 -04:00
static const int kReputationRequestPeriod = 600 ; // 10 mins
static const int kReputationStoreWait = 180 ; // 3 minutes.
2016-07-25 15:45:49 -04:00
static const float REPUTATION_ASSESSMENT_THRESHOLD_X1 = 0.5f ; // reputation under which the peer gets killed. Warning there's a 1 shift with what's shown in GUI. Be careful.
2016-04-02 14:04:08 -04:00
static const uint32_t PGP_AUTO_BAN_THRESHOLD_DEFAULT = 2 ; // above this, auto ban any GXS id signed by this node
static const uint32_t IDENTITY_FLAGS_UPDATE_DELAY = 100 ; //
2016-04-15 18:25:41 -04:00
static const uint32_t BANNED_NODES_UPDATE_DELAY = 313 ; // update approx every 5 mins. Chosen to not be a multiple of IDENTITY_FLAGS_UPDATE_DELAY
2017-01-12 20:39:49 +01:00
static const uint32_t REPUTATION_INFO_KEEP_DELAY_DEFAULT = 86400 * 35 ; // remove old reputation info 5 days after last usage limit, in case the ID would come back..
static const uint32_t BANNED_NODES_INACTIVITY_KEEP_DEFAULT = 86400 * 60 ; // remove all info about banned nodes after 2 months of inactivity
2014-02-19 11:08:37 +00:00
2016-12-28 18:58:49 +01:00
static const uint32_t REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_POSITIVE = 1 ; // min difference in votes that makes friends opinion globally positive
static const uint32_t REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_NEGATIVE = 1 ; // min difference in votes that makes friends opinion globally negative
2017-01-09 23:47:51 +01:00
static const uint32_t MIN_DELAY_BETWEEN_REPUTATION_CONFIG_SAVE = 61 ; // never save more often than once a minute.
2016-12-28 18:58:49 +01:00
2014-02-19 11:08:37 +00:00
p3GxsReputation : : p3GxsReputation ( p3LinkMgr * lm )
2014-03-29 05:20:57 +00:00
: p3Service ( ) , p3Config ( ) ,
2014-02-19 11:08:37 +00:00
mReputationMtx ( " p3GxsReputation " ) , mLinkMgr ( lm )
{
2015-10-08 23:54:18 -04:00
addSerialType ( new RsGxsReputationSerialiser ( ) ) ;
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
//mPgpAutoBanThreshold = PGP_AUTO_BAN_THRESHOLD_DEFAULT ;
2015-10-08 23:54:18 -04:00
mRequestTime = 0 ;
mStoreTime = 0 ;
mReputationsUpdated = false ;
2016-07-25 16:04:30 -04:00
mLastIdentityFlagsUpdate = time ( NULL ) - 3 ;
2016-04-02 14:04:08 -04:00
mLastBannedNodesUpdate = 0 ;
2016-08-04 11:43:35 +02:00
mBannedNodesProxyNeedsUpdate = false ;
2016-07-25 15:45:49 -04:00
mAutoSetPositiveOptionToContacts = true ; // default
2016-12-28 18:58:49 +01:00
mMinVotesForRemotelyPositive = REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_POSITIVE ;
mMinVotesForRemotelyNegative = REPUTATION_DEFAULT_MIN_VOTES_FOR_REMOTELY_NEGATIVE ;
2017-01-09 23:47:51 +01:00
mLastReputationConfigSaved = 0 ;
mChanged = false ;
2017-01-12 21:27:02 +01:00
mMaxPreventReloadBannedIds = 0 ; // default is "never"
2017-03-04 21:20:34 +01:00
mLastCleanUp = time ( NULL ) ;
2014-02-19 11:08:37 +00:00
}
2014-03-22 03:53:44 +00:00
const std : : string GXS_REPUTATION_APP_NAME = " gxsreputation " ;
const uint16_t GXS_REPUTATION_APP_MAJOR_VERSION = 1 ;
const uint16_t GXS_REPUTATION_APP_MINOR_VERSION = 0 ;
const uint16_t GXS_REPUTATION_MIN_MAJOR_VERSION = 1 ;
const uint16_t GXS_REPUTATION_MIN_MINOR_VERSION = 0 ;
RsServiceInfo p3GxsReputation : : getServiceInfo ( )
{
2014-03-29 15:34:37 +00:00
return RsServiceInfo ( RS_SERVICE_GXS_TYPE_REPUTATION ,
2014-03-22 03:53:44 +00:00
GXS_REPUTATION_APP_NAME ,
GXS_REPUTATION_APP_MAJOR_VERSION ,
GXS_REPUTATION_APP_MINOR_VERSION ,
GXS_REPUTATION_MIN_MAJOR_VERSION ,
GXS_REPUTATION_MIN_MINOR_VERSION ) ;
}
2014-02-19 11:08:37 +00:00
int p3GxsReputation : : tick ( )
{
processIncoming ( ) ;
sendPackets ( ) ;
2015-10-12 14:03:53 -04:00
time_t now = time ( NULL ) ;
2017-01-08 22:00:54 +01:00
if ( mLastCleanUp + CLEANUP_PERIOD < now )
2015-10-12 14:03:53 -04:00
{
2017-01-08 22:00:54 +01:00
cleanup ( ) ;
mLastCleanUp = now ;
2015-10-12 14:03:53 -04:00
}
2014-02-19 11:08:37 +00:00
2017-01-08 22:00:54 +01:00
// no more than once per 5 second chunk.
if ( now > IDENTITY_FLAGS_UPDATE_DELAY + mLastIdentityFlagsUpdate )
{
2017-01-09 23:47:51 +01:00
updateStaticIdentityFlags ( ) ;
2017-01-08 22:00:54 +01:00
mLastIdentityFlagsUpdate = now ;
}
if ( now > BANNED_NODES_UPDATE_DELAY + mLastBannedNodesUpdate ) // 613 is not a multiple of 100, to avoid piling up work
{
2017-01-09 23:47:51 +01:00
updateStaticIdentityFlags ( ) ; // needed before updateBannedNodesList!
2017-01-08 22:00:54 +01:00
updateBannedNodesProxy ( ) ;
mLastBannedNodesUpdate = now ;
}
if ( mBannedNodesProxyNeedsUpdate )
{
updateBannedNodesProxy ( ) ;
mBannedNodesProxyNeedsUpdate = false ;
}
2016-08-04 11:43:35 +02:00
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
2015-10-12 14:03:53 -04:00
static time_t last_debug_print = time ( NULL ) ;
if ( now > 10 + last_debug_print )
{
last_debug_print = now ;
debug_print ( ) ;
}
2015-10-08 18:39:50 -04:00
# endif
2017-01-09 23:47:51 +01:00
if ( mChanged & & now > mLastReputationConfigSaved + MIN_DELAY_BETWEEN_REPUTATION_CONFIG_SAVE )
{
IndicateConfigChanged ( ) ;
mLastReputationConfigSaved = now ;
mChanged = false ;
}
2014-02-19 11:08:37 +00:00
return 0 ;
}
2016-07-25 15:45:49 -04:00
void p3GxsReputation : : setNodeAutoPositiveOpinionForContacts ( bool b )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
if ( b ! = mAutoSetPositiveOptionToContacts )
{
2016-07-25 16:04:30 -04:00
mLastIdentityFlagsUpdate = 0 ;
2017-01-09 23:47:51 +01:00
mLastCleanUp = 0 ;
2016-07-25 15:45:49 -04:00
mAutoSetPositiveOptionToContacts = b ;
2017-01-09 23:47:51 +01:00
2016-07-25 15:45:49 -04:00
IndicateConfigChanged ( ) ;
}
}
bool p3GxsReputation : : nodeAutoPositiveOpinionForContacts ( )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
return mAutoSetPositiveOptionToContacts ;
}
2017-01-12 20:39:49 +01:00
void p3GxsReputation : : setRememberDeletedNodesThreshold ( uint32_t days )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2017-01-12 21:14:36 +01:00
if ( mMaxPreventReloadBannedIds ! = days * 86400 )
2017-01-12 20:39:49 +01:00
{
2017-01-12 21:14:36 +01:00
mMaxPreventReloadBannedIds = days * 86400 ;
2017-01-12 20:39:49 +01:00
IndicateConfigChanged ( ) ;
}
}
uint32_t p3GxsReputation : : rememberDeletedNodesThreshold ( )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
return mMaxPreventReloadBannedIds / 86400 ;
}
2014-02-19 11:08:37 +00:00
int p3GxsReputation : : status ( )
{
return 1 ;
}
2016-04-02 14:04:08 -04:00
class ZeroInitCnt
{
public :
ZeroInitCnt ( ) : cnt ( 0 ) { }
uint32_t cnt ;
operator uint32_t & ( ) { return cnt ; }
operator uint32_t ( ) const { return cnt ; }
} ;
2016-08-04 11:43:35 +02:00
void p3GxsReputation : : updateBannedNodesProxy ( )
2016-04-02 14:04:08 -04:00
{
2016-08-04 11:43:35 +02:00
// This function keeps the Banned GXS id proxy up to date.
//
2016-04-02 14:04:08 -04:00
2016-08-04 11:43:35 +02:00
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2016-04-02 14:04:08 -04:00
2016-08-04 11:43:35 +02:00
mPerNodeBannedIdsProxy . clear ( ) ;
2016-04-02 14:04:08 -04:00
2016-08-04 11:43:35 +02:00
for ( std : : map < RsPgpId , BannedNodeInfo > : : iterator rit = mBannedPgpIds . begin ( ) ; rit ! = mBannedPgpIds . end ( ) ; + + rit )
for ( std : : set < RsGxsId > : : const_iterator it ( rit - > second . known_identities . begin ( ) ) ; it ! = rit - > second . known_identities . end ( ) ; + + it )
mPerNodeBannedIdsProxy . insert ( * it ) ;
2016-04-02 14:04:08 -04:00
}
2014-02-19 11:08:37 +00:00
2017-01-09 23:47:51 +01:00
void p3GxsReputation : : updateStaticIdentityFlags ( )
2015-10-25 22:54:56 -04:00
{
2017-01-08 22:00:54 +01:00
// This function is the *only* place where rsIdentity is called. Normally the cross calls between p3IdService and p3GxsReputations should only
2017-01-09 23:47:51 +01:00
// happen one way: from rsIdentity to rsReputations. Still, reputations need to keep track of some identity flags. It's very important to make sure that
// rsIdentity is not called inside a mutex-protected zone, because normally calls happen in the other way.
2017-01-08 22:00:54 +01:00
2015-10-25 23:45:33 -04:00
std : : list < RsGxsId > to_update ;
// we need to gather the list to be used in a non locked frame
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2015-10-27 22:41:29 -04:00
# ifdef DEBUG_REPUTATION
2015-10-25 23:45:33 -04:00
std : : cerr < < " Updating reputation identity flags " < < std : : endl ;
2015-10-27 22:41:29 -04:00
# endif
2015-10-25 23:45:33 -04:00
for ( std : : map < RsGxsId , Reputation > : : iterator rit = mReputations . begin ( ) ; rit ! = mReputations . end ( ) ; + + rit )
2017-01-09 23:47:51 +01:00
{
2017-01-08 11:14:18 +01:00
if ( ( ! ( rit - > second . mIdentityFlags & REPUTATION_IDENTITY_FLAG_UP_TO_DATE ) ) & & ( mPerNodeBannedIdsProxy . find ( rit - > first ) = = mPerNodeBannedIdsProxy . end ( ) ) )
2015-10-25 23:45:33 -04:00
to_update . push_back ( rit - > first ) ;
2017-01-09 23:47:51 +01:00
}
2015-10-25 23:45:33 -04:00
}
for ( std : : list < RsGxsId > : : const_iterator rit ( to_update . begin ( ) ) ; rit ! = to_update . end ( ) ; + + rit )
{
RsIdentityDetails details ;
if ( ! rsIdentity - > getIdDetails ( * rit , details ) )
{
2015-10-27 22:41:29 -04:00
# ifdef DEBUG_REPUTATION
2015-10-25 23:45:33 -04:00
std : : cerr < < " cannot obtain info for " < < * rit < < " . Will do it later. " < < std : : endl ;
2015-10-27 22:41:29 -04:00
# endif
2015-10-25 23:45:33 -04:00
continue ;
}
2016-07-25 15:45:49 -04:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : map < RsGxsId , Reputation > : : iterator it = mReputations . find ( * rit ) ;
if ( it = = mReputations . end ( ) )
{
std : : cerr < < " Weird situation: item " < < * rit < < " has been deleted from the list?? " < < std : : endl ;
continue ;
}
2017-01-09 23:47:51 +01:00
it - > second . mIdentityFlags = REPUTATION_IDENTITY_FLAG_UP_TO_DATE ; // resets the NEEDS_UPDATE flag. All other flags set later on.
2016-07-25 15:45:49 -04:00
if ( details . mFlags & RS_IDENTITY_FLAGS_PGP_LINKED )
{
it - > second . mIdentityFlags | = REPUTATION_IDENTITY_FLAG_PGP_LINKED ;
it - > second . mOwnerNode = details . mPgpId ;
}
if ( details . mFlags & RS_IDENTITY_FLAGS_PGP_KNOWN ) it - > second . mIdentityFlags | = REPUTATION_IDENTITY_FLAG_PGP_KNOWN ;
2015-10-27 22:41:29 -04:00
# ifdef DEBUG_REPUTATION
2016-07-25 15:45:49 -04:00
std : : cerr < < " updated flags for " < < * rit < < " to " < < std : : hex < < it - > second . mIdentityFlags < < std : : dec < < std : : endl ;
2015-10-27 22:41:29 -04:00
# endif
2015-10-25 23:45:33 -04:00
2016-07-25 15:45:49 -04:00
it - > second . updateReputation ( ) ;
2017-01-09 23:47:51 +01:00
mChanged = true ;
2016-07-25 15:45:49 -04:00
}
2015-10-25 23:45:33 -04:00
}
2015-10-25 22:54:56 -04:00
}
2015-10-12 14:03:53 -04:00
void p3GxsReputation : : cleanup ( )
{
2016-07-10 22:46:37 -04:00
// remove opinions from friends that havn't been seen online for more than the specified delay
2016-07-03 18:06:01 -04:00
2015-10-12 14:03:53 -04:00
# ifdef DEBUG_REPUTATION
2016-07-10 22:46:37 -04:00
std : : cerr < < " p3GxsReputation::cleanup() " < < std : : endl ;
2017-01-12 22:14:41 +01:00
# endif
2017-01-08 22:00:54 +01:00
time_t now = time ( NULL ) ;
2016-07-03 18:06:01 -04:00
2017-01-08 22:00:54 +01:00
// We should keep opinions about identities that do not exist anymore, but only rely on the usage TS. That will in particular avoid asking p3idservice about deleted
2016-08-04 11:43:35 +02:00
// identities, which would cause an excess of hits to the database. We do it in two steps to avoid a deadlock when calling rsIdentity from here.
// Also, neutral opinions for banned PGP linked nodes are kept, so as to be able to not request them again.
2016-07-03 18:06:01 -04:00
2016-07-10 22:46:37 -04:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
for ( std : : map < RsGxsId , Reputation > : : iterator it ( mReputations . begin ( ) ) ; it ! = mReputations . end ( ) ; )
2017-01-08 22:00:54 +01:00
{
bool should_delete = false ;
2017-01-12 21:14:36 +01:00
if ( it - > second . mOwnOpinion = = RsReputations : : OPINION_NEGATIVE & & mMaxPreventReloadBannedIds ! = 0 & & it - > second . mOwnOpinionTs + mMaxPreventReloadBannedIds < now )
{
# ifdef DEBUG_REPUTATION
std : : cerr < < " ID " < < it - > first < < " : own is negative for more than " < < mMaxPreventReloadBannedIds / 86400 < < " days. Reseting it! " < < std : : endl ;
# endif
mChanged = true ;
}
2017-01-08 22:00:54 +01:00
// Delete slots with basically no information
2016-08-04 11:43:35 +02:00
if ( it - > second . mOpinions . empty ( ) & & it - > second . mOwnOpinion = = RsReputations : : OPINION_NEUTRAL & & ( it - > second . mOwnerNode . isNull ( ) ) )
2017-01-08 22:00:54 +01:00
{
2016-08-04 11:43:35 +02:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " ID " < < it - > first < < " : own is neutral and no opinions from friends => remove entry " < < std : : endl ;
# endif
2017-01-08 22:00:54 +01:00
should_delete = true ;
}
2017-01-09 23:47:51 +01:00
// Delete slots that havn't been used for a while. The else below is here for debug display purposes, and not harmful since both conditions lead the same effect.
2017-01-08 22:00:54 +01:00
2017-01-12 20:39:49 +01:00
else if ( it - > second . mLastUsedTS + REPUTATION_INFO_KEEP_DELAY_DEFAULT < now )
2017-01-08 22:00:54 +01:00
{
# ifdef DEBUG_REPUTATION
2017-01-12 20:39:49 +01:00
std : : cerr < < " ID " < < it - > first < < " : no request for reputation for more than " < < REPUTATION_INFO_KEEP_DELAY_DEFAULT / 86400 < < " days => deleting. " < < std : : endl ;
2017-01-08 22:00:54 +01:00
# endif
should_delete = true ;
}
2017-01-09 23:47:51 +01:00
# ifdef DEBUG_REPUTATION
else
std : : cerr < < " ID " < < it - > first < < " : flags= " < < std : : hex < < it - > second . mIdentityFlags < < std : : dec < < " . Last used: " < < ( now - it - > second . mLastUsedTS ) / 86400 < < " days ago: kept. " < < std : : endl ;
# endif
2017-01-08 22:00:54 +01:00
if ( should_delete )
{
2016-08-04 11:43:35 +02:00
std : : map < RsGxsId , Reputation > : : iterator tmp ( it ) ;
2016-07-10 22:46:37 -04:00
+ + tmp ;
mReputations . erase ( it ) ;
it = tmp ;
2017-01-09 23:47:51 +01:00
mChanged = true ;
2016-07-10 22:46:37 -04:00
}
else
+ + it ;
2017-01-08 22:00:54 +01:00
}
2016-07-10 22:46:37 -04:00
}
2017-01-08 22:00:54 +01:00
// Clean up of the banned PGP ids.
2016-07-10 22:46:37 -04:00
2016-08-04 11:43:35 +02:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
for ( std : : map < RsPgpId , BannedNodeInfo > : : iterator it ( mBannedPgpIds . begin ( ) ) ; it ! = mBannedPgpIds . end ( ) ; )
2017-01-12 20:39:49 +01:00
if ( it - > second . last_activity_TS + BANNED_NODES_INACTIVITY_KEEP_DEFAULT < now )
2016-08-04 11:43:35 +02:00
{
# ifdef DEBUG_REPUTATION
std : : cerr < < " Removing all info about banned node " < < it - > first < < " by lack of activity. " < < std : : endl ;
# endif
std : : map < RsPgpId , BannedNodeInfo > : : iterator tmp ( it ) ;
+ + tmp ;
mBannedPgpIds . erase ( it ) ;
it = tmp ;
2017-01-09 23:47:51 +01:00
mChanged = true ;
2016-08-04 11:43:35 +02:00
}
else
+ + it ;
}
2017-01-28 15:26:12 +01:00
// Update opinions based on flags and contact information.
// Note: the call to rsIdentity->isARegularContact() is done off-mutex, in order to avoid a cross-deadlock, as
// normally, p3GxsReputation gets called by p3dentity and not te reverse. That explains the weird implementation
// of these two loops.
2017-01-09 23:47:51 +01:00
{
2017-01-28 15:26:12 +01:00
std : : list < RsGxsId > should_set_to_positive_candidates ;
2017-01-09 23:47:51 +01:00
2017-01-28 15:26:12 +01:00
if ( mAutoSetPositiveOptionToContacts )
2017-01-09 23:47:51 +01:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
for ( std : : map < RsGxsId , Reputation > : : iterator it ( mReputations . begin ( ) ) ; it ! = mReputations . end ( ) ; + + it )
2017-01-28 15:26:12 +01:00
if ( it - > second . mOwnOpinion = = RsReputations : : OPINION_NEUTRAL )
should_set_to_positive_candidates . push_back ( it - > first ) ;
2017-01-09 23:47:51 +01:00
}
2017-01-28 15:26:12 +01:00
for ( std : : list < RsGxsId > : : const_iterator it ( should_set_to_positive_candidates . begin ( ) ) ; it ! = should_set_to_positive_candidates . end ( ) ; + + it )
if ( rsIdentity - > isARegularContact ( * it ) )
setOwnOpinion ( * it , RsReputations : : OPINION_POSITIVE ) ;
2017-01-09 23:47:51 +01:00
}
2015-10-12 14:03:53 -04:00
}
2016-03-29 21:22:14 +02:00
const float RsReputations : : REPUTATION_THRESHOLD_ANTI_SPAM = 1.4f ;
const float RsReputations : : REPUTATION_THRESHOLD_DEFAULT = 1.0f ;
2015-10-07 23:44:24 -04:00
static RsReputations : : Opinion safe_convert_uint32t_to_opinion ( uint32_t op )
{
return RsReputations : : Opinion ( std : : min ( ( uint32_t ) op , UPPER_LIMIT ) ) ;
}
2014-02-19 11:08:37 +00:00
/***** Implementation ******/
bool p3GxsReputation : : processIncoming ( )
{
/* for each packet - pass to specific handler */
RsItem * item = NULL ;
while ( NULL ! = ( item = recvItem ( ) ) )
{
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::processingIncoming() Received Item: " ;
std : : cerr < < std : : endl ;
item - > print ( std : : cerr ) ;
std : : cerr < < std : : endl ;
# endif
bool itemOk = true ;
switch ( item - > PacketSubType ( ) )
{
default :
2016-08-02 23:57:11 +02:00
case RS_PKT_SUBTYPE_GXS_REPUTATION_CONFIG_ITEM :
case RS_PKT_SUBTYPE_GXS_REPUTATION_SET_ITEM :
2014-02-19 11:08:37 +00:00
std : : cerr < < " p3GxsReputation::processingIncoming() Unknown Item " ;
std : : cerr < < std : : endl ;
itemOk = false ;
break ;
2015-10-06 00:11:18 -04:00
case RS_PKT_SUBTYPE_GXS_REPUTATION_REQUEST_ITEM :
2014-02-19 11:08:37 +00:00
{
2015-10-07 23:44:24 -04:00
RsGxsReputationRequestItem * requestItem = dynamic_cast < RsGxsReputationRequestItem * > ( item ) ;
2014-02-19 11:08:37 +00:00
if ( requestItem )
SendReputations ( requestItem ) ;
else
itemOk = false ;
}
break ;
2015-10-06 00:11:18 -04:00
case RS_PKT_SUBTYPE_GXS_REPUTATION_UPDATE_ITEM :
2014-02-19 11:08:37 +00:00
{
2015-10-07 23:44:24 -04:00
RsGxsReputationUpdateItem * updateItem = dynamic_cast < RsGxsReputationUpdateItem * > ( item ) ;
2014-02-19 11:08:37 +00:00
if ( updateItem )
RecvReputations ( updateItem ) ;
else
itemOk = false ;
}
break ;
}
if ( ! itemOk )
{
std : : cerr < < " p3GxsReputation::processingIncoming() Error with Item " ;
std : : cerr < < std : : endl ;
}
/* clean up */
delete item ;
}
return true ;
}
bool p3GxsReputation : : SendReputations ( RsGxsReputationRequestItem * request )
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::SendReputations() " < < std : : endl ;
# endif
2014-02-19 11:08:37 +00:00
RsPeerId peerId = request - > PeerId ( ) ;
time_t last_update = request - > mLastUpdate ;
time_t now = time ( NULL ) ;
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : multimap < time_t , RsGxsId > : : iterator tit ;
tit = mUpdated . upper_bound ( last_update ) ; // could skip some - (fixed below).
int count = 0 ;
int totalcount = 0 ;
RsGxsReputationUpdateItem * pkt = new RsGxsReputationUpdateItem ( ) ;
2015-10-08 23:54:18 -04:00
2014-02-19 11:08:37 +00:00
pkt - > PeerId ( peerId ) ;
2014-10-24 22:07:26 +00:00
for ( ; tit ! = mUpdated . end ( ) ; + + tit )
2014-02-19 11:08:37 +00:00
{
/* find */
2015-10-08 23:54:18 -04:00
std : : map < RsGxsId , Reputation > : : iterator rit = mReputations . find ( tit - > second ) ;
2014-02-19 11:08:37 +00:00
if ( rit = = mReputations . end ( ) )
{
std : : cerr < < " p3GxsReputation::SendReputations() ERROR Missing Reputation " ;
std : : cerr < < std : : endl ;
// error.
continue ;
}
if ( rit - > second . mOwnOpinionTs = = 0 )
{
std : : cerr < < " p3GxsReputation::SendReputations() ERROR OwnOpinionTS = 0 " ;
std : : cerr < < std : : endl ;
// error.
continue ;
}
2014-03-20 11:26:53 +00:00
RsGxsId gxsId = rit - > first ;
2015-10-06 23:56:39 -04:00
pkt - > mOpinions [ gxsId ] = rit - > second . mOwnOpinion ;
2014-02-19 11:08:37 +00:00
pkt - > mLatestUpdate = rit - > second . mOwnOpinionTs ;
2015-10-08 23:54:18 -04:00
2014-02-19 11:08:37 +00:00
if ( pkt - > mLatestUpdate = = ( uint32_t ) now )
{
// if we could possibly get another Update at this point (same second).
// then set Update back one second to ensure there are none missed.
pkt - > mLatestUpdate - - ;
}
count + + ;
totalcount + + ;
if ( count > kMaximumSetSize )
{
2015-10-12 14:03:53 -04:00
# ifdef DEBUG_REPUTATION
2014-02-19 11:08:37 +00:00
std : : cerr < < " p3GxsReputation::SendReputations() Sending Full Packet " ;
std : : cerr < < std : : endl ;
2015-10-12 14:03:53 -04:00
# endif
2014-02-19 11:08:37 +00:00
sendItem ( pkt ) ;
2015-10-08 23:54:18 -04:00
2014-02-19 11:08:37 +00:00
pkt = new RsGxsReputationUpdateItem ( ) ;
pkt - > PeerId ( peerId ) ;
count = 0 ;
}
}
if ( ! pkt - > mOpinions . empty ( ) )
{
2015-10-12 14:03:53 -04:00
# ifdef DEBUG_REPUTATION
2014-02-19 11:08:37 +00:00
std : : cerr < < " p3GxsReputation::SendReputations() Sending Final Packet " ;
std : : cerr < < std : : endl ;
2015-10-12 14:03:53 -04:00
# endif
2014-02-19 11:08:37 +00:00
sendItem ( pkt ) ;
}
else
{
delete pkt ;
}
2015-10-12 14:03:53 -04:00
# ifdef DEBUG_REPUTATION
2014-02-19 11:08:37 +00:00
std : : cerr < < " p3GxsReputation::SendReputations() Total Count: " < < totalcount ;
std : : cerr < < std : : endl ;
2015-10-12 14:03:53 -04:00
# endif
2014-02-19 11:08:37 +00:00
return true ;
}
2015-10-07 23:44:24 -04:00
void p3GxsReputation : : locked_updateOpinion ( const RsPeerId & from , const RsGxsId & about , RsReputations : : Opinion op )
{
/* find matching Reputation */
std : : map < RsGxsId , Reputation > : : iterator rit = mReputations . find ( about ) ;
RsReputations : : Opinion new_opinion = safe_convert_uint32t_to_opinion ( op ) ;
RsReputations : : Opinion old_opinion = RsReputations : : OPINION_NEUTRAL ; // default if not set
2015-10-08 18:39:50 -04:00
2015-10-07 23:44:24 -04:00
bool updated = false ;
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::update opinion of " < < about < < " from " < < from < < " to " < < op < < std : : endl ;
# endif
2015-10-07 23:44:24 -04:00
// now 4 cases;
// Opinion already stored
// New opinion is same: nothing to do
// New opinion is different: if neutral, remove entry
// Nothing stored
// New opinion is neutral: nothing to do
// New opinion is != 1: create entry and store
if ( rit = = mReputations . end ( ) )
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " no preview record " < < std : : endl ;
# endif
2015-10-07 23:44:24 -04:00
if ( new_opinion ! = RsReputations : : OPINION_NEUTRAL )
{
mReputations [ about ] = Reputation ( about ) ;
rit = mReputations . find ( about ) ;
}
else
2015-10-08 18:39:50 -04:00
{
# ifdef DEBUG_REPUTATION
std : : cerr < < " no changes! " < < std : : endl ;
# endif
2015-10-07 23:44:24 -04:00
return ; // nothing to do
2015-10-08 18:39:50 -04:00
}
2015-10-07 23:44:24 -04:00
}
Reputation & reputation = rit - > second ;
std : : map < RsPeerId , RsReputations : : Opinion > : : iterator it2 = reputation . mOpinions . find ( from ) ;
if ( it2 = = reputation . mOpinions . end ( ) )
{
if ( new_opinion ! = RsReputations : : OPINION_NEUTRAL )
{
reputation . mOpinions [ from ] = new_opinion ; // filters potentially tweaked reputation score sent by friend
updated = true ;
}
}
else
{
old_opinion = it2 - > second ;
if ( new_opinion = = RsReputations : : OPINION_NEUTRAL )
{
reputation . mOpinions . erase ( it2 ) ; // don't store when the opinion is neutral
updated = true ;
}
else if ( new_opinion ! = old_opinion )
{
it2 - > second = new_opinion ;
updated = true ;
}
}
if ( reputation . mOpinions . empty ( ) & & reputation . mOwnOpinion = = RsReputations : : OPINION_NEUTRAL )
2015-10-08 18:39:50 -04:00
{
2015-10-07 23:44:24 -04:00
mReputations . erase ( rit ) ;
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " own is neutral and no opinions from friends => remove entry " < < std : : endl ;
# endif
updated = true ;
}
2015-10-07 23:44:24 -04:00
else if ( updated )
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " reputation changed. re-calculating. " < < std : : endl ;
# endif
2015-10-25 23:45:33 -04:00
reputation . updateReputation ( ) ;
2015-10-07 23:44:24 -04:00
}
2015-10-08 18:39:50 -04:00
if ( updated )
IndicateConfigChanged ( ) ;
2015-10-07 23:44:24 -04:00
}
2014-02-19 11:08:37 +00:00
bool p3GxsReputation : : RecvReputations ( RsGxsReputationUpdateItem * item )
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::RecvReputations() from " < < item - > PeerId ( ) < < std : : endl ;
# endif
2014-02-19 11:08:37 +00:00
RsPeerId peerid = item - > PeerId ( ) ;
2015-10-08 18:39:50 -04:00
for ( std : : map < RsGxsId , uint32_t > : : iterator it = item - > mOpinions . begin ( ) ; it ! = item - > mOpinions . end ( ) ; + + it )
2014-02-19 11:08:37 +00:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2015-10-08 18:39:50 -04:00
locked_updateOpinion ( peerid , it - > first , safe_convert_uint32t_to_opinion ( it - > second ) ) ;
}
2014-02-19 11:08:37 +00:00
2015-10-09 17:51:10 -04:00
updateLatestUpdate ( peerid , item - > mLatestUpdate ) ;
2014-02-19 11:08:37 +00:00
return true ;
}
2015-10-09 17:51:10 -04:00
bool p3GxsReputation : : updateLatestUpdate ( RsPeerId peerid , time_t latest_update )
2014-02-19 11:08:37 +00:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2015-06-14 10:10:30 +00:00
std : : map < RsPeerId , ReputationConfig > : : iterator it = mConfig . find ( peerid ) ;
if ( it = = mConfig . end ( ) )
2014-02-19 11:08:37 +00:00
{
2015-06-14 10:10:30 +00:00
mConfig [ peerid ] = ReputationConfig ( peerid ) ;
it = mConfig . find ( peerid ) ;
2014-02-19 11:08:37 +00:00
}
2015-10-09 17:51:10 -04:00
it - > second . mLatestUpdate = latest_update ;
2014-02-19 11:08:37 +00:00
mReputationsUpdated = true ;
// Switched to periodic save due to scale of data.
2015-10-08 23:54:18 -04:00
IndicateConfigChanged ( ) ;
2014-02-19 11:08:37 +00:00
return true ;
}
/********************************************************************
* Opinion
* * * */
2017-02-06 23:46:01 +01:00
RsReputations : : ReputationLevel p3GxsReputation : : overallReputationLevel ( const RsGxsId & id , uint32_t * identity_flags )
2017-01-09 23:47:51 +01:00
{
ReputationInfo info ;
getReputationInfo ( id , RsPgpId ( ) , info ) ;
2017-02-06 23:46:01 +01:00
RsPgpId owner_id ;
if ( identity_flags )
getIdentityFlagsAndOwnerId ( id , * identity_flags , owner_id ) ;
2017-01-09 23:47:51 +01:00
return info . mOverallReputationLevel ;
}
2017-02-06 23:46:01 +01:00
bool p3GxsReputation : : getIdentityFlagsAndOwnerId ( const RsGxsId & gxsid , uint32_t & identity_flags , RsPgpId & owner_id )
{
if ( gxsid . isNull ( ) )
return false ;
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : map < RsGxsId , Reputation > : : iterator it = mReputations . find ( gxsid ) ;
if ( it = = mReputations . end ( ) )
return false ;
if ( ! ( it - > second . mIdentityFlags & REPUTATION_IDENTITY_FLAG_UP_TO_DATE ) )
return false ;
if ( it - > second . mIdentityFlags & REPUTATION_IDENTITY_FLAG_PGP_LINKED )
identity_flags | = RS_IDENTITY_FLAGS_PGP_LINKED ;
if ( it - > second . mIdentityFlags & REPUTATION_IDENTITY_FLAG_PGP_KNOWN )
identity_flags | = RS_IDENTITY_FLAGS_PGP_KNOWN ;
owner_id = it - > second . mOwnerNode ;
return true ;
}
2017-01-10 23:05:00 +01:00
bool p3GxsReputation : : getReputationInfo ( const RsGxsId & gxsid , const RsPgpId & ownerNode , RsReputations : : ReputationInfo & info , bool stamp )
2015-10-04 23:14:49 -04:00
{
2015-10-25 23:45:33 -04:00
if ( gxsid . isNull ( ) )
return false ;
2016-08-04 11:43:35 +02:00
time_t now = time ( NULL ) ;
2015-10-06 23:56:39 -04:00
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2016-08-04 11:43:35 +02:00
# ifdef DEBUG_REPUTATION2
2017-01-10 23:05:00 +01:00
std : : cerr < < " getReputationInfo() for " < < gxsid < < " , stamp = " < < stamp < < std : : endl ;
2015-10-08 18:39:50 -04:00
# endif
2016-08-04 11:43:35 +02:00
std : : map < RsGxsId , Reputation > : : iterator it = mReputations . find ( gxsid ) ;
RsPgpId owner_id ;
2015-10-06 23:56:39 -04:00
2016-07-03 18:06:01 -04:00
if ( it = = mReputations . end ( ) )
{
info . mOwnOpinion = RsReputations : : OPINION_NEUTRAL ;
2016-12-23 17:52:02 +01:00
info . mFriendAverageScore = REPUTATION_THRESHOLD_DEFAULT ;
info . mFriendsNegativeVotes = 0 ;
info . mFriendsPositiveVotes = 0 ;
2016-08-04 11:43:35 +02:00
owner_id = ownerNode ;
2016-07-03 18:06:01 -04:00
}
else
{
2016-08-04 11:43:35 +02:00
Reputation & rep ( it - > second ) ;
2015-10-25 23:45:33 -04:00
2016-07-03 18:59:30 -04:00
info . mOwnOpinion = RsReputations : : Opinion ( rep . mOwnOpinion ) ;
2016-12-23 17:52:02 +01:00
info . mFriendAverageScore = rep . mFriendAverage ;
info . mFriendsNegativeVotes = rep . mFriendsNegative ;
info . mFriendsPositiveVotes = rep . mFriendsPositive ;
2016-08-04 11:43:35 +02:00
2017-01-09 23:47:51 +01:00
if ( rep . mOwnerNode . isNull ( ) & & ! ownerNode . isNull ( ) )
2016-08-04 11:43:35 +02:00
rep . mOwnerNode = ownerNode ;
owner_id = rep . mOwnerNode ;
2017-01-10 23:05:00 +01:00
if ( stamp )
rep . mLastUsedTS = now ;
2017-01-09 23:47:51 +01:00
mChanged = true ;
2016-07-03 18:06:01 -04:00
}
2016-07-03 18:59:30 -04:00
2016-12-23 17:52:02 +01:00
// now compute overall score and reputation
// 0 - check for own opinion. If positive or negative, it decides on the result
if ( info . mOwnOpinion = = RsReputations : : OPINION_NEGATIVE )
{
// own opinion is always read in priority
info . mOverallReputationLevel = RsReputations : : REPUTATION_LOCALLY_NEGATIVE ;
return true ;
}
if ( info . mOwnOpinion = = RsReputations : : OPINION_POSITIVE )
{
// own opinion is always read in priority
info . mOverallReputationLevel = RsReputations : : REPUTATION_LOCALLY_POSITIVE ;
return true ;
}
// 1 - check for banned PGP ids.
2016-08-04 11:43:35 +02:00
std : : map < RsPgpId , BannedNodeInfo > : : iterator it2 ;
if ( ! owner_id . isNull ( ) & & ( it2 = mBannedPgpIds . find ( owner_id ) ) ! = mBannedPgpIds . end ( ) )
2016-04-02 14:04:08 -04:00
{
2016-12-23 17:52:02 +01:00
// Check if current identity is present in the list of known identities for this banned node.
2016-08-04 11:43:35 +02:00
if ( it2 - > second . known_identities . find ( gxsid ) = = it2 - > second . known_identities . end ( ) )
{
it2 - > second . known_identities . insert ( gxsid ) ;
it2 - > second . last_activity_TS = now ;
2016-12-23 17:52:02 +01:00
// if so, update
2016-08-04 11:43:35 +02:00
mBannedNodesProxyNeedsUpdate = true ;
}
# ifdef DEBUG_REPUTATION2
std : : cerr < < " p3GxsReputations: identity " < < gxsid < < " is banned because owner node ID " < < owner_id < < " is banned (found in banned nodes list). " < < std : : endl ;
# endif
2016-12-23 17:52:02 +01:00
info . mOverallReputationLevel = RsReputations : : REPUTATION_LOCALLY_NEGATIVE ;
return true ;
2016-08-04 11:43:35 +02:00
}
2016-12-23 17:52:02 +01:00
// also check the proxy
if ( mPerNodeBannedIdsProxy . find ( gxsid ) ! = mPerNodeBannedIdsProxy . end ( ) )
2016-08-04 11:43:35 +02:00
{
# ifdef DEBUG_REPUTATION2
std : : cerr < < " p3GxsReputations: identity " < < gxsid < < " is banned because owner node ID " < < owner_id < < " is banned (found in proxy). " < < std : : endl ;
2016-04-02 16:14:08 -04:00
# endif
2016-12-23 17:52:02 +01:00
info . mOverallReputationLevel = RsReputations : : REPUTATION_LOCALLY_NEGATIVE ;
return true ;
2016-04-02 14:04:08 -04:00
}
2016-12-23 17:52:02 +01:00
// 2 - now, our own opinion is neutral, which means we rely on what our friends tell
2016-12-28 18:58:49 +01:00
if ( info . mFriendsPositiveVotes > = info . mFriendsNegativeVotes + mMinVotesForRemotelyPositive )
2016-12-23 17:52:02 +01:00
info . mOverallReputationLevel = RsReputations : : REPUTATION_REMOTELY_POSITIVE ;
2016-12-28 18:58:49 +01:00
else if ( info . mFriendsPositiveVotes + mMinVotesForRemotelyNegative < = info . mFriendsNegativeVotes )
2016-12-23 17:52:02 +01:00
info . mOverallReputationLevel = RsReputations : : REPUTATION_REMOTELY_NEGATIVE ;
2016-07-03 18:06:01 -04:00
else
2016-12-23 17:52:02 +01:00
info . mOverallReputationLevel = RsReputations : : REPUTATION_NEUTRAL ;
2015-10-06 23:56:39 -04:00
2016-08-04 11:43:35 +02:00
# ifdef DEBUG_REPUTATION2
std : : cerr < < " information present. OwnOp = " < < info . mOwnOpinion < < " , owner node= " < < owner_id < < " , overall score= " < < info . mAssessment < < std : : endl ;
2015-10-08 18:39:50 -04:00
# endif
2015-10-06 23:56:39 -04:00
2015-10-04 23:14:49 -04:00
return true ;
}
2016-12-28 18:58:49 +01:00
uint32_t p3GxsReputation : : thresholdForRemotelyNegativeReputation ( )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
return mMinVotesForRemotelyNegative ;
}
uint32_t p3GxsReputation : : thresholdForRemotelyPositiveReputation ( )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
return mMinVotesForRemotelyPositive ;
}
void p3GxsReputation : : setThresholdForRemotelyPositiveReputation ( uint32_t thresh )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
if ( mMinVotesForRemotelyPositive = = thresh | | thresh = = 0 )
return ;
mMinVotesForRemotelyPositive = thresh ;
IndicateConfigChanged ( ) ;
}
void p3GxsReputation : : setThresholdForRemotelyNegativeReputation ( uint32_t thresh )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
if ( mMinVotesForRemotelyNegative = = thresh | | thresh = = 0 )
return ;
mMinVotesForRemotelyNegative = thresh ;
IndicateConfigChanged ( ) ;
}
2016-08-04 11:43:35 +02:00
void p3GxsReputation : : banNode ( const RsPgpId & id , bool b )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
if ( b )
{
if ( mBannedPgpIds . find ( id ) = = mBannedPgpIds . end ( ) )
{
mBannedPgpIds [ id ] = BannedNodeInfo ( ) ;
IndicateConfigChanged ( ) ;
}
}
else
{
if ( mBannedPgpIds . find ( id ) ! = mBannedPgpIds . end ( ) )
{
mBannedPgpIds . erase ( id ) ;
IndicateConfigChanged ( ) ;
}
}
}
bool p3GxsReputation : : isNodeBanned ( const RsPgpId & id )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
return mBannedPgpIds . find ( id ) ! = mBannedPgpIds . end ( ) ;
}
bool p3GxsReputation : : isIdentityBanned ( const RsGxsId & id )
2015-10-06 23:56:39 -04:00
{
RsReputations : : ReputationInfo info ;
2016-08-04 11:43:35 +02:00
if ( ! getReputationInfo ( id , RsPgpId ( ) , info ) )
2016-07-03 18:06:01 -04:00
return false ;
2016-07-03 18:59:30 -04:00
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
2017-01-08 11:14:18 +01:00
std : : cerr < < " isIdentityBanned(): returning " < < ( info . mOverallReputationLevel = = RsReputations : : REPUTATION_LOCALLY_NEGATIVE ) < < " for GXS id " < < id < < std : : endl ;
2015-10-08 18:39:50 -04:00
# endif
2016-12-23 17:52:02 +01:00
return info . mOverallReputationLevel = = RsReputations : : REPUTATION_LOCALLY_NEGATIVE ;
2015-10-06 23:56:39 -04:00
}
2017-01-13 18:31:50 +01:00
bool p3GxsReputation : : getOwnOpinion ( const RsGxsId & gxsid , RsReputations : : Opinion & opinion )
{
# ifdef DEBUG_REPUTATION
std : : cerr < < " setOwnOpinion(): for GXS id " < < gxsid < < " to " < < opinion < < std : : endl ;
# endif
if ( gxsid . isNull ( ) )
{
std : : cerr < < " ID " < < gxsid < < " is rejected. Look for a bug in calling method. " < < std : : endl ;
return false ;
}
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : map < RsGxsId , Reputation > : : iterator rit = mReputations . find ( gxsid ) ;
if ( rit ! = mReputations . end ( ) )
opinion = RsReputations : : Opinion ( rit - > second . mOwnOpinion ) ;
else
opinion = RsReputations : : OPINION_NEUTRAL ;
return true ;
}
2015-10-04 23:14:49 -04:00
bool p3GxsReputation : : setOwnOpinion ( const RsGxsId & gxsid , const RsReputations : : Opinion & opinion )
2014-02-19 11:08:37 +00:00
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " setOwnOpinion(): for GXS id " < < gxsid < < " to " < < opinion < < std : : endl ;
# endif
2015-10-10 18:27:15 -04:00
if ( gxsid . isNull ( ) )
{
std : : cerr < < " ID " < < gxsid < < " is rejected. Look for a bug in calling method. " < < std : : endl ;
return false ;
}
2014-02-19 11:08:37 +00:00
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : map < RsGxsId , Reputation > : : iterator rit ;
/* find matching Reputation */
rit = mReputations . find ( gxsid ) ;
2015-10-08 23:02:34 -04:00
2014-02-19 11:08:37 +00:00
if ( rit = = mReputations . end ( ) )
{
2017-01-05 23:07:59 +01:00
# warning we should set the owner node id here.
2014-02-19 11:08:37 +00:00
mReputations [ gxsid ] = Reputation ( gxsid ) ;
rit = mReputations . find ( gxsid ) ;
}
// we should remove previous entries from Updates...
Reputation & reputation = rit - > second ;
if ( reputation . mOwnOpinionTs ! = 0 )
{
if ( reputation . mOwnOpinion = = opinion )
{
// if opinion is accurate, don't update.
return false ;
}
std : : multimap < time_t , RsGxsId > : : iterator uit , euit ;
uit = mUpdated . lower_bound ( reputation . mOwnOpinionTs ) ;
euit = mUpdated . upper_bound ( reputation . mOwnOpinionTs ) ;
2014-10-24 22:07:26 +00:00
for ( ; uit ! = euit ; + + uit )
2014-02-19 11:08:37 +00:00
{
if ( uit - > second = = gxsid )
{
mUpdated . erase ( uit ) ;
break ;
}
}
}
time_t now = time ( NULL ) ;
reputation . mOwnOpinion = opinion ;
reputation . mOwnOpinionTs = now ;
2015-10-25 23:45:33 -04:00
reputation . updateReputation ( ) ;
2014-02-19 11:08:37 +00:00
mUpdated . insert ( std : : make_pair ( now , gxsid ) ) ;
mReputationsUpdated = true ;
2016-04-02 14:04:08 -04:00
mLastBannedNodesUpdate = 0 ; // for update of banned nodes
2015-10-08 23:02:34 -04:00
2014-02-19 11:08:37 +00:00
// Switched to periodic save due to scale of data.
2015-10-08 23:02:34 -04:00
IndicateConfigChanged ( ) ;
2014-02-19 11:08:37 +00:00
return true ;
}
/********************************************************************
* Configuration .
* * * */
RsSerialiser * p3GxsReputation : : setupSerialiser ( )
{
RsSerialiser * rss = new RsSerialiser ;
rss - > addSerialType ( new RsGxsReputationSerialiser ( ) ) ;
2016-04-02 14:04:08 -04:00
rss - > addSerialType ( new RsGeneralConfigSerialiser ( ) ) ;
2014-02-19 11:08:37 +00:00
return rss ;
}
bool p3GxsReputation : : saveList ( bool & cleanup , std : : list < RsItem * > & savelist )
{
cleanup = true ;
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2017-03-05 20:08:36 +01:00
# ifdef DEBUG_REPUTATION
2015-10-08 18:39:50 -04:00
std : : cerr < < " p3GxsReputation::saveList() " < < std : : endl ;
2017-03-05 20:08:36 +01:00
# endif
2017-01-31 21:51:16 +01:00
2014-02-19 11:08:37 +00:00
/* save */
std : : map < RsPeerId , ReputationConfig > : : iterator it ;
2014-10-24 22:07:26 +00:00
for ( it = mConfig . begin ( ) ; it ! = mConfig . end ( ) ; + + it )
2014-02-19 11:08:37 +00:00
{
if ( ! rsPeers - > isFriend ( it - > first ) )
{
// discard info from non-friends.
continue ;
}
RsGxsReputationConfigItem * item = new RsGxsReputationConfigItem ( ) ;
2015-10-06 00:11:18 -04:00
item - > mPeerId = it - > first ;
2014-02-19 11:08:37 +00:00
item - > mLatestUpdate = it - > second . mLatestUpdate ;
item - > mLastQuery = it - > second . mLastQuery ;
savelist . push_back ( item ) ;
}
int count = 0 ;
std : : map < RsGxsId , Reputation > : : iterator rit ;
2014-10-24 22:07:26 +00:00
for ( rit = mReputations . begin ( ) ; rit ! = mReputations . end ( ) ; + + rit , count + + )
2014-02-19 11:08:37 +00:00
{
RsGxsReputationSetItem * item = new RsGxsReputationSetItem ( ) ;
2015-10-06 00:11:18 -04:00
item - > mGxsId = rit - > first ;
2015-10-06 23:56:39 -04:00
item - > mOwnOpinion = rit - > second . mOwnOpinion ;
2015-10-06 00:11:18 -04:00
item - > mOwnOpinionTS = rit - > second . mOwnOpinionTs ;
2015-10-25 22:54:56 -04:00
item - > mIdentityFlags = rit - > second . mIdentityFlags ;
2016-08-02 23:57:11 +02:00
item - > mOwnerNodeId = rit - > second . mOwnerNode ;
2017-01-08 11:14:18 +01:00
item - > mLastUsedTS = rit - > second . mLastUsedTS ;
2014-02-19 11:08:37 +00:00
2015-10-07 23:44:24 -04:00
std : : map < RsPeerId , RsReputations : : Opinion > : : iterator oit ;
2014-02-19 11:08:37 +00:00
for ( oit = rit - > second . mOpinions . begin ( ) ; oit ! = rit - > second . mOpinions . end ( ) ; + + oit )
{
// should be already limited.
2015-10-07 23:44:24 -04:00
item - > mOpinions [ oit - > first ] = ( uint32_t ) oit - > second ;
2014-02-19 11:08:37 +00:00
}
savelist . push_back ( item ) ;
count + + ;
}
2016-08-04 11:43:35 +02:00
for ( std : : map < RsPgpId , BannedNodeInfo > : : const_iterator it ( mBannedPgpIds . begin ( ) ) ; it ! = mBannedPgpIds . end ( ) ; + + it )
{
RsGxsReputationBannedNodeSetItem * item = new RsGxsReputationBannedNodeSetItem ( ) ;
item - > mPgpId = it - > first ;
item - > mLastActivityTS = it - > second . last_activity_TS ;
item - > mKnownIdentities . ids = it - > second . known_identities ;
savelist . push_back ( item ) ;
}
2016-04-02 14:04:08 -04:00
RsConfigKeyValueSet * vitem = new RsConfigKeyValueSet ;
RsTlvKeyValue kv ;
2016-12-29 10:34:57 +01:00
kv . key = " AUTO_REMOTELY_POSITIVE_THRESHOLD " ;
rs_sprintf ( kv . value , " %d " , mMinVotesForRemotelyPositive ) ;
vitem - > tlvkvs . pairs . push_back ( kv ) ;
kv . key = " AUTO_REMOTELY_NEGATIVE_THRESHOLD " ;
rs_sprintf ( kv . value , " %d " , mMinVotesForRemotelyNegative ) ;
vitem - > tlvkvs . pairs . push_back ( kv ) ;
2016-04-02 14:04:08 -04:00
2016-07-25 15:45:49 -04:00
kv . key = " AUTO_POSITIVE_CONTACTS " ;
kv . value = mAutoSetPositiveOptionToContacts ? " YES " : " NO " ;
vitem - > tlvkvs . pairs . push_back ( kv ) ;
2017-01-12 20:39:49 +01:00
kv . key = " MAX_PREVENT_RELOAD_BANNED_IDS " ;
rs_sprintf ( kv . value , " %d " , mMaxPreventReloadBannedIds ) ;
vitem - > tlvkvs . pairs . push_back ( kv ) ;
2016-07-25 15:45:49 -04:00
savelist . push_back ( vitem ) ;
2016-04-02 14:04:08 -04:00
2014-02-19 11:08:37 +00:00
return true ;
}
void p3GxsReputation : : saveDone ( )
{
return ;
}
bool p3GxsReputation : : loadList ( std : : list < RsItem * > & loadList )
{
2015-10-08 18:39:50 -04:00
# ifdef DEBUG_REPUTATION
2016-08-04 11:43:35 +02:00
std : : cerr < < " p3GxsReputation::loadList() " < < std : : endl ;
2015-10-08 18:39:50 -04:00
# endif
2016-04-02 14:04:08 -04:00
std : : list < RsItem * > : : iterator it ;
std : : set < RsPeerId > peerSet ;
2015-10-25 22:54:56 -04:00
2016-04-02 14:04:08 -04:00
for ( it = loadList . begin ( ) ; it ! = loadList . end ( ) ; + + it )
{
RsGxsReputationConfigItem * item = dynamic_cast < RsGxsReputationConfigItem * > ( * it ) ;
2015-10-25 22:54:56 -04:00
2016-04-02 14:04:08 -04:00
// Configurations are loaded first. (to establish peerSet).
if ( item )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
RsPeerId peerId ( item - > mPeerId ) ;
ReputationConfig & config = mConfig [ peerId ] ;
config . mPeerId = peerId ;
config . mLatestUpdate = item - > mLatestUpdate ;
config . mLastQuery = 0 ;
2016-08-04 11:43:35 +02:00
peerSet . insert ( peerId ) ;
2016-04-02 14:04:08 -04:00
}
2015-10-25 22:54:56 -04:00
2016-04-02 14:04:08 -04:00
RsGxsReputationSetItem * set = dynamic_cast < RsGxsReputationSetItem * > ( * it ) ;
2016-08-04 11:43:35 +02:00
2016-04-02 14:04:08 -04:00
if ( set )
loadReputationSet ( set , peerSet ) ;
2017-04-22 21:10:55 +02:00
# ifdef TO_REMOVE
2017-01-08 11:14:18 +01:00
RsGxsReputationSetItem_deprecated3 * set2 = dynamic_cast < RsGxsReputationSetItem_deprecated3 * > ( * it ) ;
if ( set2 )
2017-01-08 22:00:54 +01:00
{
std : : cerr < < " (II) reading and converting old format ReputationSetItem. " < < std : : endl ;
2017-01-08 11:14:18 +01:00
loadReputationSet_deprecated3 ( set2 , peerSet ) ;
2017-01-08 22:00:54 +01:00
}
2017-04-22 21:10:55 +02:00
# endif
2016-08-04 11:43:35 +02:00
RsGxsReputationBannedNodeSetItem * itm2 = dynamic_cast < RsGxsReputationBannedNodeSetItem * > ( * it ) ;
if ( itm2 ! = NULL )
{
BannedNodeInfo & info ( mBannedPgpIds [ itm2 - > mPgpId ] ) ;
info . last_activity_TS = itm2 - > mLastActivityTS ;
info . known_identities = itm2 - > mKnownIdentities . ids ;
}
2016-04-02 14:04:08 -04:00
RsConfigKeyValueSet * vitem = dynamic_cast < RsConfigKeyValueSet * > ( * it ) ;
if ( vitem )
for ( std : : list < RsTlvKeyValue > : : const_iterator kit = vitem - > tlvkvs . pairs . begin ( ) ; kit ! = vitem - > tlvkvs . pairs . end ( ) ; + + kit )
{
2016-12-29 10:34:57 +01:00
if ( kit - > key = = " AUTO_REMOTELY_POSITIVE_THRESHOLD " )
{
int val ;
if ( sscanf ( kit - > value . c_str ( ) , " %d " , & val ) = = 1 )
{
mMinVotesForRemotelyPositive = val ;
std : : cerr < < " Setting mMinVotesForRemotelyPositive threshold to " < < val < < std : : endl ;
}
} ;
if ( kit - > key = = " AUTO_REMOTELY_NEGATIVE_THRESHOLD " )
{
int val ;
if ( sscanf ( kit - > value . c_str ( ) , " %d " , & val ) = = 1 )
{
mMinVotesForRemotelyNegative = val ;
std : : cerr < < " Setting mMinVotesForRemotelyNegative threshold to " < < val < < std : : endl ;
}
} ;
2016-07-25 15:45:49 -04:00
if ( kit - > key = = " AUTO_POSITIVE_CONTACTS " )
{
mAutoSetPositiveOptionToContacts = ( kit - > value = = " YES " ) ;
std : : cerr < < " Setting AutoPositiveContacts to " < < kit - > value < < std : : endl ;
mLastBannedNodesUpdate = 0 ; // force update
}
2017-01-12 20:39:49 +01:00
if ( kit - > key = = " MAX_PREVENT_RELOAD_BANNED_IDS " )
{
int val ;
if ( sscanf ( kit - > value . c_str ( ) , " %d " , & val ) = = 1 )
{
mMaxPreventReloadBannedIds = val ;
std : : cerr < < " Setting mMaxPreventReloadBannedIds threshold to " < < val < < std : : endl ;
}
}
2016-07-25 15:45:49 -04:00
}
2016-04-02 14:04:08 -04:00
delete ( * it ) ;
}
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
updateBannedNodesProxy ( ) ;
2015-12-30 18:20:09 -05:00
loadList . clear ( ) ;
2016-04-02 14:04:08 -04:00
return true ;
2014-02-19 11:08:37 +00:00
}
2017-04-22 21:10:55 +02:00
# ifdef TO_REMOVE
2017-01-08 11:14:18 +01:00
bool p3GxsReputation : : loadReputationSet_deprecated3 ( RsGxsReputationSetItem_deprecated3 * item , const std : : set < RsPeerId > & peerSet )
{
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
std : : map < RsGxsId , Reputation > : : iterator rit ;
if ( item - > mGxsId . isNull ( ) ) // just a protection against potential errors having put 00000 into ids.
return false ;
/* find matching Reputation */
RsGxsId gxsId ( item - > mGxsId ) ;
rit = mReputations . find ( gxsId ) ;
if ( rit ! = mReputations . end ( ) )
{
std : : cerr < < " ERROR " ;
std : : cerr < < std : : endl ;
}
Reputation & reputation = mReputations [ gxsId ] ;
// install opinions.
std : : map < RsPeerId , uint32_t > : : const_iterator oit ;
for ( oit = item - > mOpinions . begin ( ) ; oit ! = item - > mOpinions . end ( ) ; + + oit )
{
// expensive ... but necessary.
RsPeerId peerId ( oit - > first ) ;
if ( peerSet . end ( ) ! = peerSet . find ( peerId ) )
reputation . mOpinions [ peerId ] = safe_convert_uint32t_to_opinion ( oit - > second ) ;
}
reputation . mOwnOpinion = item - > mOwnOpinion ;
reputation . mOwnOpinionTs = item - > mOwnOpinionTS ;
reputation . mOwnerNode = item - > mOwnerNodeId ;
reputation . mIdentityFlags = item - > mIdentityFlags & ( ~ REPUTATION_IDENTITY_FLAG_UP_TO_DATE ) ;
reputation . mLastUsedTS = time ( NULL ) ;
// if dropping entries has changed the score -> must update.
reputation . updateReputation ( ) ;
mUpdated . insert ( std : : make_pair ( reputation . mOwnOpinionTs , gxsId ) ) ;
}
# ifdef DEBUG_REPUTATION
RsReputations : : ReputationInfo info ;
getReputationInfo ( item - > mGxsId , item - > mOwnerNodeId , info ) ;
std : : cerr < < item - > mGxsId < < " : own: " < < info . mOwnOpinion < < " , owner node: " < < item - > mOwnerNodeId < < " , overall level: " < < info . mOverallReputationLevel < < std : : endl ;
# endif
return true ;
}
2017-04-22 21:10:55 +02:00
# endif
2014-02-19 11:08:37 +00:00
2014-03-19 12:02:48 +00:00
bool p3GxsReputation : : loadReputationSet ( RsGxsReputationSetItem * item , const std : : set < RsPeerId > & peerSet )
2014-02-19 11:08:37 +00:00
{
2016-08-04 11:43:35 +02:00
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
std : : map < RsGxsId , Reputation > : : iterator rit ;
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
if ( item - > mGxsId . isNull ( ) ) // just a protection against potential errors having put 00000 into ids.
2015-10-12 00:28:21 -04:00
return false ;
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
/* find matching Reputation */
RsGxsId gxsId ( item - > mGxsId ) ;
rit = mReputations . find ( gxsId ) ;
if ( rit ! = mReputations . end ( ) )
{
std : : cerr < < " ERROR " ;
std : : cerr < < std : : endl ;
}
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
Reputation & reputation = mReputations [ gxsId ] ;
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
// install opinions.
std : : map < RsPeerId , uint32_t > : : const_iterator oit ;
for ( oit = item - > mOpinions . begin ( ) ; oit ! = item - > mOpinions . end ( ) ; + + oit )
{
// expensive ... but necessary.
RsPeerId peerId ( oit - > first ) ;
if ( peerSet . end ( ) ! = peerSet . find ( peerId ) )
reputation . mOpinions [ peerId ] = safe_convert_uint32t_to_opinion ( oit - > second ) ;
}
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
reputation . mOwnOpinion = item - > mOwnOpinion ;
reputation . mOwnOpinionTs = item - > mOwnOpinionTS ;
reputation . mOwnerNode = item - > mOwnerNodeId ;
2017-01-08 11:14:18 +01:00
reputation . mIdentityFlags = item - > mIdentityFlags ;
reputation . mLastUsedTS = item - > mLastUsedTS ;
2014-02-19 11:08:37 +00:00
2016-08-04 11:43:35 +02:00
// if dropping entries has changed the score -> must update.
reputation . updateReputation ( ) ;
mUpdated . insert ( std : : make_pair ( reputation . mOwnOpinionTs , gxsId ) ) ;
}
# ifdef DEBUG_REPUTATION
RsReputations : : ReputationInfo info ;
2017-01-10 23:05:00 +01:00
getReputationInfo ( item - > mGxsId , item - > mOwnerNodeId , info , false ) ;
2017-01-08 11:14:18 +01:00
std : : cerr < < item - > mGxsId < < " : own: " < < info . mOwnOpinion < < " , owner node: " < < item - > mOwnerNodeId < < " , level: " < < info . mOverallReputationLevel < < std : : endl ;
2016-08-04 11:43:35 +02:00
# endif
return true ;
2014-02-19 11:08:37 +00:00
}
/********************************************************************
* Send Requests .
* * * */
int p3GxsReputation : : sendPackets ( )
{
time_t now = time ( NULL ) ;
time_t requestTime , storeTime ;
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
requestTime = mRequestTime ;
storeTime = mStoreTime ;
}
2015-10-08 23:54:18 -04:00
if ( now > requestTime + kReputationRequestPeriod )
2014-02-19 11:08:37 +00:00
{
sendReputationRequests ( ) ;
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::sendPackets() Regular Broadcast " ;
std : : cerr < < std : : endl ;
# endif
mRequestTime = now ;
mStoreTime = now + kReputationStoreWait ;
}
if ( now > storeTime )
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
# ifdef DEBUG_REPUTATION
std : : cerr < < " p3GxsReputation::sendPackets() Regular Broadcast " ;
std : : cerr < < std : : endl ;
# endif
// push it into the future.
// store time will be reset when requests are send.
mStoreTime = now + kReputationRequestPeriod ;
if ( mReputationsUpdated )
{
IndicateConfigChanged ( ) ;
mReputationsUpdated = false ;
}
}
return true ;
}
void p3GxsReputation : : sendReputationRequests ( )
{
/* we ping our peers */
/* who is online? */
std : : list < RsPeerId > idList ;
mLinkMgr - > getOnlineList ( idList ) ;
/* prepare packets */
2014-03-19 12:02:48 +00:00
std : : list < RsPeerId > : : iterator it ;
2014-10-24 22:07:26 +00:00
for ( it = idList . begin ( ) ; it ! = idList . end ( ) ; + + it )
2014-02-19 11:08:37 +00:00
sendReputationRequest ( * it ) ;
}
int p3GxsReputation : : sendReputationRequest ( RsPeerId peerid )
{
2015-10-08 23:54:18 -04:00
# ifdef DEBUG_REPUTATION
2016-04-02 16:14:08 -04:00
time_t now = time ( NULL ) ;
2015-10-08 23:54:18 -04:00
std : : cerr < < " p3GxsReputation::sendReputationRequest( " < < peerid < < " ) " ;
# endif
2014-02-19 11:08:37 +00:00
/* */
2015-10-08 23:54:18 -04:00
RsGxsReputationRequestItem * requestItem = new RsGxsReputationRequestItem ( ) ;
2014-02-19 11:08:37 +00:00
requestItem - > PeerId ( peerid ) ;
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
/* find the last timestamp we have */
2015-10-08 23:54:18 -04:00
std : : map < RsPeerId , ReputationConfig > : : iterator it = mConfig . find ( peerid ) ;
2014-02-19 11:08:37 +00:00
if ( it ! = mConfig . end ( ) )
{
2015-10-08 23:54:18 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " lastUpdate = " < < now - it - > second . mLatestUpdate < < " secs ago. Requesting only more recent. " < < std : : endl ;
# endif
2014-02-19 11:08:37 +00:00
requestItem - > mLastUpdate = it - > second . mLatestUpdate ;
}
else
{
2015-10-08 23:54:18 -04:00
# ifdef DEBUG_REPUTATION
std : : cerr < < " lastUpdate = never. Requesting all! " < < std : : endl ;
# endif
2014-02-19 11:08:37 +00:00
// get whole list.
requestItem - > mLastUpdate = 0 ;
}
}
sendItem ( requestItem ) ;
return 1 ;
}
2015-10-25 23:45:33 -04:00
void Reputation : : updateReputation ( )
2015-10-06 22:39:14 -04:00
{
2015-10-09 18:55:07 -04:00
// the calculation of reputation makes the whole thing
int friend_total = 0 ;
2016-12-23 17:52:02 +01:00
mFriendsNegative = 0 ;
mFriendsPositive = 0 ;
2015-10-09 18:55:07 -04:00
// accounts for all friends. Neutral opinions count for 1-1=0
2015-10-13 21:54:52 -04:00
// because the average is performed over only accessible peers (not the total number) we need to shift to 1
2015-10-09 18:55:07 -04:00
for ( std : : map < RsPeerId , RsReputations : : Opinion > : : const_iterator it ( mOpinions . begin ( ) ) ; it ! = mOpinions . end ( ) ; + + it )
2016-12-23 17:52:02 +01:00
{
2016-12-31 15:17:51 +01:00
if ( it - > second = = RsReputations : : OPINION_NEGATIVE )
2016-12-23 17:52:02 +01:00
+ + mFriendsNegative ;
2016-12-31 15:17:51 +01:00
if ( it - > second = = RsReputations : : OPINION_POSITIVE )
2016-12-23 17:52:02 +01:00
+ + mFriendsPositive ;
2016-12-31 15:17:51 +01:00
friend_total + = it - > second - 1 ;
2016-12-23 17:52:02 +01:00
}
2015-10-09 18:55:07 -04:00
if ( mOpinions . empty ( ) ) // includes the case of no friends!
mFriendAverage = 1.0f ;
else
2015-10-25 22:54:56 -04:00
{
2015-10-26 23:38:10 -04:00
static const float REPUTATION_FRIEND_FACTOR_ANON = 2.0f ;
static const float REPUTATION_FRIEND_FACTOR_PGP_LINKED = 5.0f ;
static const float REPUTATION_FRIEND_FACTOR_PGP_KNOWN = 10.0f ;
// For positive votes, start from 1 and slowly tend to 2
// for negative votes, start from 1 and slowly tend to 0
// depending on signature state, the ID is harder (signed ids) or easier (anon ids) to ban or to promote.
//
// when REPUTATION_FRIEND_VARIANCE = 3, that gives the following values:
//
// total votes | mFriendAverage anon | mFriendAverage PgpLinked | mFriendAverage PgpKnown |
// | F=2.0 | F=5.0 | F=10.0 |
// -------------+----------------------+---------------------------+--------------------------+
// -10 | 0.00 Banned | 0.13 Banned | 0.36 Banned |
// -5 | 0.08 Banned | 0.36 Banned | 0.60 |
// -4 | 0.13 Banned | 0.44 Banned | 0.67 |
// -3 | 0.22 Banned | 0.54 | 0.74 |
// -2 | 0.36 Banned | 0.67 | 0.81 |
// -1 | 0.60 | 0.81 | 0.90 |
// 0 | 1.0 | 1.0 | 1.00 |
// 1 | 1.39 | 1.18 | 1.09 |
// 2 | 1.63 | 1.32 | 1.18 |
// 3 | 1.77 | 1.45 | 1.25 |
// 4 | 1.86 | 1.55 | 1.32 |
// 5 | 1.91 | 1.63 | 1.39 |
//
// Banning info is provided by the reputation system, and does not depend on PGP-sign state.
//
// However, each service might have its own rules for the different cases. For instance
// PGP-favoring forums might want a score > 1.4 for anon ids, and >= 1.0 for PGP-signed.
float reputation_bias ;
if ( mIdentityFlags & REPUTATION_IDENTITY_FLAG_PGP_KNOWN )
reputation_bias = REPUTATION_FRIEND_FACTOR_PGP_KNOWN ;
else if ( mIdentityFlags & REPUTATION_IDENTITY_FLAG_PGP_LINKED )
reputation_bias = REPUTATION_FRIEND_FACTOR_PGP_LINKED ;
else
reputation_bias = REPUTATION_FRIEND_FACTOR_ANON ;
if ( friend_total > 0 )
mFriendAverage = 2.0f - exp ( - friend_total / reputation_bias ) ;
else
mFriendAverage = exp ( friend_total / reputation_bias ) ;
2015-10-25 22:54:56 -04:00
}
2015-10-09 18:55:07 -04:00
2015-10-25 22:54:56 -04:00
// now compute a bias for PGP-signed ids.
2015-10-09 18:55:07 -04:00
if ( mOwnOpinion = = RsReputations : : OPINION_NEUTRAL )
2016-12-23 17:52:02 +01:00
mReputationScore = mFriendAverage ;
2015-10-09 18:55:07 -04:00
else
2016-12-23 17:52:02 +01:00
mReputationScore = ( float ) mOwnOpinion ;
2015-10-06 22:39:14 -04:00
}
2015-10-08 18:39:50 -04:00
void p3GxsReputation : : debug_print ( )
{
std : : cerr < < " Reputations database: " < < std : : endl ;
2016-08-04 11:43:35 +02:00
std : : cerr < < " GXS ID data: " < < std : : endl ;
2017-01-10 23:05:00 +01:00
std : : cerr < < std : : dec ;
2016-08-04 11:43:35 +02:00
2017-01-10 23:05:00 +01:00
std : : map < RsGxsId , Reputation > rep_copy ;
{
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
rep_copy = mReputations ;
}
2015-10-08 23:02:34 -04:00
time_t now = time ( NULL ) ;
2016-08-04 11:43:35 +02:00
2017-01-10 23:05:00 +01:00
for ( std : : map < RsGxsId , Reputation > : : const_iterator it ( rep_copy . begin ( ) ) ; it ! = rep_copy . end ( ) ; + + it )
2015-10-08 18:39:50 -04:00
{
2017-01-10 23:05:00 +01:00
RsReputations : : ReputationInfo info ;
getReputationInfo ( it - > first , RsPgpId ( ) , info , false ) ;
uint32_t lev = info . mOverallReputationLevel ;
std : : cerr < < " " < < it - > first < < " : own: " < < it - > second . mOwnOpinion
< < " , PGP id= " < < it - > second . mOwnerNode
< < " , flags= " < < std : : setfill ( ' 0 ' ) < < std : : setw ( 4 ) < < std : : hex < < it - > second . mIdentityFlags < < std : : dec
< < " , Friend pos/neg: " < < it - > second . mFriendsPositive < < " / " < < it - > second . mFriendsNegative
< < " , reputation lev: [ " < < lev
< < " ], last own update: " < < std : : setfill ( ' ' ) < < std : : setw ( 10 ) < < now - it - > second . mOwnOpinionTs < < " secs ago "
< < " , last needed: " < < std : : setfill ( ' ' ) < < std : : setw ( 10 ) < < now - it - > second . mLastUsedTS < < " secs ago, "
< < std : : endl ;
2016-08-04 11:43:35 +02:00
# ifdef DEBUG_REPUTATION2
for ( std : : map < RsPeerId , RsReputations : : Opinion > : : const_iterator it2 ( it - > second . mOpinions . begin ( ) ) ; it2 ! = it - > second . mOpinions . end ( ) ; + + it2 )
2015-10-08 23:02:34 -04:00
std : : cerr < < " " < < it2 - > first < < " : " < < it2 - > second < < std : : endl ;
2016-08-04 11:43:35 +02:00
# endif
2015-10-08 18:39:50 -04:00
}
2016-08-04 11:43:35 +02:00
2017-01-10 23:05:00 +01:00
RsStackMutex stack ( mReputationMtx ) ; /****** LOCKED MUTEX *******/
2016-08-04 11:43:35 +02:00
std : : cerr < < " Banned RS nodes by ID: " < < std : : endl ;
for ( std : : map < RsPgpId , BannedNodeInfo > : : const_iterator it ( mBannedPgpIds . begin ( ) ) ; it ! = mBannedPgpIds . end ( ) ; + + it )
{
std : : cerr < < " Node " < < it - > first < < " , last activity: " < < now - it - > second . last_activity_TS < < " secs ago. " < < std : : endl ;
for ( std : : set < RsGxsId > : : const_iterator it2 ( it - > second . known_identities . begin ( ) ) ; it2 ! = it - > second . known_identities . end ( ) ; + + it2 )
std : : cerr < < " " < < * it2 < < std : : endl ;
}
std : : cerr < < " Per node Banned GXSIds proxy: " < < std : : endl ;
for ( std : : set < RsGxsId > : : const_iterator it ( mPerNodeBannedIdsProxy . begin ( ) ) ; it ! = mPerNodeBannedIdsProxy . end ( ) ; + + it )
std : : cerr < < " " < < * it < < std : : endl ;
2015-10-08 18:39:50 -04:00
}
2014-02-19 11:08:37 +00:00