thread safe rand (#1157)

* thread safe InsecureRand class

* remove GetInsecureRand, use GetRandInt for performance non-critical parts
This commit is contained in:
UdjinM6 2016-11-20 10:52:45 +04:00 committed by GitHub
parent e121829e40
commit c2ec99ba8e
5 changed files with 56 additions and 15 deletions

View File

@ -664,7 +664,7 @@ void CDarksendPool::ChargeFees()
if(!fMasterNode) return; if(!fMasterNode) return;
//we don't need to charge collateral for every offence. //we don't need to charge collateral for every offence.
if(GetInsecureRand(100) > 33) return; if(GetRandInt(100) > 33) return;
std::vector<CTransaction> vecOffendersCollaterals; std::vector<CTransaction> vecOffendersCollaterals;
@ -699,7 +699,7 @@ void CDarksendPool::ChargeFees()
if(vecOffendersCollaterals.empty()) return; if(vecOffendersCollaterals.empty()) return;
//mostly offending? Charge sometimes //mostly offending? Charge sometimes
if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions() - 1 && GetInsecureRand(100) > 33) return; if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions() - 1 && GetRandInt(100) > 33) return;
//everyone is an offender? That's not right //everyone is an offender? That's not right
if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions()) return; if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions()) return;
@ -740,7 +740,7 @@ void CDarksendPool::ChargeRandomFees()
BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) { BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) {
if(GetInsecureRand(100) > 10) return; if(GetRandInt(100) > 10) return;
LogPrintf("CDarksendPool::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral.ToString()); LogPrintf("CDarksendPool::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral.ToString());
@ -1480,7 +1480,7 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun)
LogPrint("privatesend", " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high); LogPrint("privatesend", " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high);
} }
bool fUseQueue = insecure_rand()%100 > 33; bool fUseQueue = GetRandInt(100) > 33;
// don't use the queues all of the time for mixing unless we are a liquidity provider // don't use the queues all of the time for mixing unless we are a liquidity provider
if(nLiquidityProvider || fUseQueue) { if(nLiquidityProvider || fUseQueue) {
@ -2014,7 +2014,7 @@ bool CDarksendPool::CreateNewSession(int nDenom, CTransaction txCollateral, Pool
// start new session // start new session
nMessageIDRet = MSG_NOERR; nMessageIDRet = MSG_NOERR;
nSessionID = GetInsecureRand(999999)+1; nSessionID = GetRandInt(999999)+1;
nSessionDenom = nDenom; nSessionDenom = nDenom;
SetState(POOL_STATE_QUEUE); SetState(POOL_STATE_QUEUE);
@ -2145,7 +2145,7 @@ int CDarksendPool::GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fS
int c = 0; int c = 0;
// if the denomination is used, shift the bit on // if the denomination is used, shift the bit on
BOOST_FOREACH (PAIRTYPE(CAmount, int)& s, vecDenomUsed) { BOOST_FOREACH (PAIRTYPE(CAmount, int)& s, vecDenomUsed) {
int bit = (fSingleRandomDenom ? insecure_rand()%2 : 1) & s.second; int bit = (fSingleRandomDenom ? GetRandInt(2) : 1) & s.second;
nDenom |= bit << c++; nDenom |= bit << c++;
if(fSingleRandomDenom && bit) break; // use just one random denomination if(fSingleRandomDenom && bit) break; // use just one random denomination
} }
@ -2462,7 +2462,7 @@ void ThreadCheckDarkSendPool()
if(nDoAutoNextRun == nTick) { if(nDoAutoNextRun == nTick) {
darkSendPool.DoAutomaticDenominating(); darkSendPool.DoAutomaticDenominating();
nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN + GetInsecureRand(PRIVATESEND_AUTO_TIMEOUT_MAX - PRIVATESEND_AUTO_TIMEOUT_MIN); nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN + GetRandInt(PRIVATESEND_AUTO_TIMEOUT_MAX - PRIVATESEND_AUTO_TIMEOUT_MIN);
} }
} }
} }

View File

@ -543,8 +543,9 @@ CMasternode* CMasternodeMan::FindRandomNotInVec(const std::vector<CTxIn> &vecToE
vpMasternodesShuffled.push_back(&mn); vpMasternodesShuffled.push_back(&mn);
} }
InsecureRand insecureRand;
// shuffle pointers // shuffle pointers
std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), GetInsecureRand); std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecureRand);
bool fExclude; bool fExclude;
// loop through // loop through
@ -969,7 +970,7 @@ bool CMasternodeMan::SendVerifyRequest(const CAddress& addr, const std::vector<C
if(pnode != NULL) { if(pnode != NULL) {
netfulfilledman.AddFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request"); netfulfilledman.AddFulfilledRequest(addr, strprintf("%s", NetMsgType::MNVERIFY)+"-request");
// use random nonce, store it and require node to reply with correct one later // use random nonce, store it and require node to reply with correct one later
CMasternodeVerification mnv(addr, GetInsecureRand(999999), pCurrentBlockIndex->nHeight - 1); CMasternodeVerification mnv(addr, GetRandInt(999999), pCurrentBlockIndex->nHeight - 1);
mWeAskedForVerification[addr] = mnv; mWeAskedForVerification[addr] = mnv;
LogPrintf("CMasternodeMan::SendVerifyRequest -- verifying using nonce %d addr=%s\n", mnv.nonce, addr.ToString()); LogPrintf("CMasternodeMan::SendVerifyRequest -- verifying using nonce %d addr=%s\n", mnv.nonce, addr.ToString());
pnode->PushMessage(NetMsgType::MNVERIFY, mnv); pnode->PushMessage(NetMsgType::MNVERIFY, mnv);

View File

@ -137,3 +137,21 @@ void seed_insecure_rand(bool fDeterministic)
insecure_rand_Rw = tmp; insecure_rand_Rw = tmp;
} }
} }
InsecureRand::InsecureRand(bool _fDeterministic)
: nRz(11),
nRw(11),
fDeterministic(_fDeterministic)
{
// The seed values have some unlikely fixed points which we avoid.
if(fDeterministic) return;
uint32_t nTmp;
do {
GetRandBytes((unsigned char*)&nTmp, 4);
} while (nTmp == 0 || nTmp == 0x9068ffffU);
nRz = nTmp;
do {
GetRandBytes((unsigned char*)&nTmp, 4);
} while (nTmp == 0 || nTmp == 0x464fffffU);
nRw = nTmp;
}

View File

@ -47,10 +47,31 @@ static inline uint32_t insecure_rand(void)
} }
/** /**
* Function for std::random_shuffle * PRNG initialized from secure entropy based RNG
*/ */
static inline uint32_t GetInsecureRand(uint32_t i){ class InsecureRand
return insecure_rand() % i; {
} private:
uint32_t nRz;
uint32_t nRw;
bool fDeterministic;
public:
InsecureRand(bool _fDeterministic = false);
/**
* MWC RNG of George Marsaglia
* This is intended to be fast. It has a period of 2^59.3, though the
* least significant 16 bits only have a period of about 2^30.1.
*
* @return random value < nMax
*/
int64_t operator()(int64_t nMax)
{
nRz = 36969 * (nRz & 65535) + (nRz >> 16);
nRw = 18000 * (nRw & 65535) + (nRw >> 16);
return ((nRw << 16) + nRz) % nMax;
}
};
#endif // BITCOIN_RANDOM_H #endif // BITCOIN_RANDOM_H

View File

@ -2501,6 +2501,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
int nDenomResult = 0; int nDenomResult = 0;
InsecureRand insecureRand;
BOOST_FOREACH(const COutput& out, vCoins) BOOST_FOREACH(const COutput& out, vCoins)
{ {
// masternode-like input should not be selected by AvailableCoins now anyway // masternode-like input should not be selected by AvailableCoins now anyway
@ -2517,9 +2518,9 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
if(out.tx->vout[out.i].nValue == vecPrivateSendDenominations[nBit]) { if(out.tx->vout[out.i].nValue == vecPrivateSendDenominations[nBit]) {
if(nValueRet >= nValueMin) { if(nValueRet >= nValueMin) {
//randomly reduce the max amount we'll submit (for anonymity) //randomly reduce the max amount we'll submit (for anonymity)
nValueMax -= (GetInsecureRand(nValueMax/5)); nValueMax -= insecureRand(nValueMax/5);
//on average use 50% of the inputs or less //on average use 50% of the inputs or less
int r = GetInsecureRand((int)vCoins.size()); int r = insecureRand(vCoins.size());
if((int)vecTxInRet.size() > r) return true; if((int)vecTxInRet.size() > r) return true;
} }
txin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey txin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey