From 198f7d44b40b75d55cb96a0b8f04585a28552ae2 Mon Sep 17 00:00:00 2001 From: Kokary Date: Sat, 27 Apr 2019 09:41:09 +0200 Subject: [PATCH] Update bet winnings calculation for better overflow handling --- src/bet.cpp | 51 +++++++++++++++++++++++++---------------------- src/chainparams.h | 28 +++++++++++++------------- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/bet.cpp b/src/bet.cpp index efaa1b858..fcbab7ae0 100644 --- a/src/bet.cpp +++ b/src/bet.cpp @@ -88,8 +88,8 @@ int64_t GetBlockPayouts(std::vector& vexpectedPayouts, CAmount& nMNBetRe if (vexpectedPayouts.size() > 0) { // Calculate the OMNO reward and the Dev reward. - CAmount nOMNOReward = (CAmount)((profitAcc / (1000.0 - Params().BetXPermille()) * Params().OMNORewardPermille())); - CAmount nDevReward = (CAmount)((profitAcc / (1000.0 - Params().BetXPermille()) * Params().DevRewardPermille())); + CAmount nOMNOReward = (CAmount)(profitAcc * Params().OMNORewardPermille() / (1000.0 - Params().BetXPermille())); + CAmount nDevReward = (CAmount)(profitAcc * Params().DevRewardPermille() / (1000.0 - Params().BetXPermille())); // Add both reward payouts to the payout vector. vexpectedPayouts.emplace_back(nDevReward, GetScriptForDestination(CBitcoinAddress(devPayoutAddr).Get())); @@ -940,8 +940,8 @@ void SetEventAccummulators (CPeerlessBet plBet, CAmount betAmount) { eventIndex_t eventsIndex; edb.GetEvents(eventsIndex); - unsigned int oddsDivisor = Params().OddsDivisor(); - unsigned int betXPermille = Params().BetXPermille(); + uint64_t oddsDivisor = Params().OddsDivisor(); + uint64_t betXPermille = Params().BetXPermille(); // Check the events index actually has events if (eventsIndex.size() > 0) { @@ -954,28 +954,31 @@ void SetEventAccummulators (CPeerlessBet plBet, CAmount betAmount) { // Check which outcome the bet was placed on and add to accumulators if (plBet.nOutcome == moneyLineWin){ winnings = betAmount * pe.nHomeOdds; - burn = (winnings - betAmount * oddsDivisor) * betXPermille / 2000; + // To avoid internal overflow issues, first divide and then multiply. + // This will not cause inaccuracy, because the Odds (and thus the winnings) are scaled by a + // factor 10000 (the oddsDivisor) + burn = (winnings - betAmount * oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nMoneyLineHomePotentialLiability += payout / COIN ; pe.nMoneyLineHomeBets += 1; }else if (plBet.nOutcome == moneyLineLose){ winnings = betAmount * pe.nAwayOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nMoneyLineAwayPotentialLiability += payout / COIN ; pe.nMoneyLineAwayBets += 1; }else if (plBet.nOutcome == moneyLineDraw){ winnings = betAmount * pe.nDrawOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nMoneyLineDrawPotentialLiability += payout / COIN ; pe.nMoneyLineDrawBets += 1; }else if (plBet.nOutcome == spreadHome){ winnings = betAmount * pe.nSpreadHomeOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nSpreadHomePotentialLiability += payout / COIN ; @@ -985,7 +988,7 @@ void SetEventAccummulators (CPeerlessBet plBet, CAmount betAmount) { }else if (plBet.nOutcome == spreadAway){ winnings = betAmount * pe.nSpreadAwayOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nSpreadAwayPotentialLiability += payout / COIN ; @@ -995,7 +998,7 @@ void SetEventAccummulators (CPeerlessBet plBet, CAmount betAmount) { }else if (plBet.nOutcome == totalOver){ winnings = betAmount * pe.nTotalOverOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nTotalOverPotentialLiability += payout / COIN ; @@ -1005,7 +1008,7 @@ void SetEventAccummulators (CPeerlessBet plBet, CAmount betAmount) { }else if (plBet.nOutcome == totalUnder){ winnings = betAmount * pe.nTotalUnderOdds; - burn = (winnings - betAmount*oddsDivisor) * betXPermille / 2000; + burn = (winnings - betAmount*oddsDivisor) / 2000 * betXPermille; payout = winnings - burn; pe.nTotalUnderPotentialLiability += payout / COIN; @@ -1741,31 +1744,31 @@ std::vector GetBetPayouts(int height) CBlockIndex *BlocksIndex = NULL; BlocksIndex = chainActive[nCurrentHeight - Params().BetBlocksIndexTimespan()]; - unsigned int oddsDivisor = Params().OddsDivisor(); - unsigned int betXPermille = Params().BetXPermille(); + uint64_t oddsDivisor = Params().OddsDivisor(); + uint64_t betXPermille = Params().BetXPermille(); OutcomeType nMoneylineResult = (OutcomeType) 0; std::vector vSpreadsResult; std::vector vTotalsResult; - unsigned int nMoneylineOdds = 0; - unsigned int nSpreadsOdds = 0; - unsigned int nTotalsOdds = 0; - unsigned int nTotalsPoints = result.nHomeScore + result.nAwayScore; - unsigned int nSpreadsDifference = 0; + uint64_t nMoneylineOdds = 0; + uint64_t nSpreadsOdds = 0; + uint64_t nTotalsOdds = 0; + uint64_t nTotalsPoints = result.nHomeScore + result.nAwayScore; + uint64_t nSpreadsDifference = 0; bool HomeFavorite = false; // We keep temp values as we can't be sure of the order of the TX's being stored in a block. // This can lead to a case were some bets don't - unsigned int nTempMoneylineOdds = 0; - unsigned int nTempSpreadsOdds = 0; - unsigned int nTempTotalsOdds = 0; + uint64_t nTempMoneylineOdds = 0; + uint64_t nTempSpreadsOdds = 0; + uint64_t nTempTotalsOdds = 0; bool UpdateMoneyLine = false; bool UpdateSpreads = false; bool UpdateTotals = false; - unsigned int nSpreadsWinner = 0; - unsigned int nTotalsWinner = 0; + uint64_t nSpreadsWinner = 0; + uint64_t nTotalsWinner = 0; time_t tempEventStartTime = 0; time_t latestEventStartTime = 0; @@ -2004,7 +2007,7 @@ std::vector GetBetPayouts(int height) // Calculate the bet winnings for the current bet. if (winnings > 0) { - payout = (winnings - ((winnings - betAmount*oddsDivisor) * betXPermille / 1000)) / oddsDivisor; + payout = (winnings - ((winnings - betAmount*oddsDivisor) / 1000 * betXPermille)) / oddsDivisor; } else { payout = 0; diff --git a/src/chainparams.h b/src/chainparams.h index af98b1566..a9a26e03f 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -135,13 +135,13 @@ class CChainParams int BetStartHeight() const { return nBetStartHeight; } std::string DevPayoutAddr() const { return strDevPayoutAddr; } std::string OMNOPayoutAddr() const { return strOMNOPayoutAddr; } - int OMNORewardPermille() const { return nOMNORewardPermille; } - int DevRewardPermille() const { return nDevRewardPermille; } - int OddsDivisor() const { return nOddsDivisor; } - int BetXPermille() const { return nBetXPermille; } - int BetBlockPayoutAmount() const { return nBetBlockPayoutAmount; } - int MaxBetPayoutRange() const { return nMaxBetPayoutRange; } - int MinBetPayoutRange() const { return nMinBetPayoutRange; } + uint64_t OMNORewardPermille() const { return nOMNORewardPermille; } + uint64_t DevRewardPermille() const { return nDevRewardPermille; } + uint64_t OddsDivisor() const { return nOddsDivisor; } + uint64_t BetXPermille() const { return nBetXPermille; } + int BetBlockPayoutAmount() const { return nBetBlockPayoutAmount; } // Currently not used + int64_t MaxBetPayoutRange() const { return nMaxBetPayoutRange; } + int64_t MinBetPayoutRange() const { return nMinBetPayoutRange; } int BetPlaceTimeoutBlocks() const { return nBetPlaceTimeoutBlocks; } protected: CChainParams() {} @@ -213,13 +213,13 @@ class CChainParams int nBetStartHeight; std::string strDevPayoutAddr; std::string strOMNOPayoutAddr; - int nOMNORewardPermille; - int nDevRewardPermille; - int nOddsDivisor; - int nBetXPermille; - int nBetBlockPayoutAmount; - int nMinBetPayoutRange; - int nMaxBetPayoutRange; + uint64_t nOMNORewardPermille; + uint64_t nDevRewardPermille; + uint64_t nOddsDivisor; + uint64_t nBetXPermille; + uint64_t nBetBlockPayoutAmount; + int64_t nMinBetPayoutRange; + int64_t nMaxBetPayoutRange; int nBetPlaceTimeoutBlocks; };