Post
Topic
Board Meta
Merits 17 from 9 users
Re: Negative Sendable Merits. A bug?
by
theymos
on 30/05/2025, 16:21:21 UTC
⭐ Merited by fillippone (3) ,dkbit98 (3) ,pooya87 (3) ,TryNinja (2) ,LoyceV (2) ,vapourminer (1) ,NotATether (1) ,notocactus (1) ,Cyrus (1)
It should be fixed now, sorry about that! I've been making a number of little tweaks over the past few days which could cause hard-to-predict bugs, so let me know if you see any other buggy behavior.

Can anyone find the bug? This function worked for years, but then I did something very far away (i.e. I didn't change this function at all) which broke it.

function calculate_smerit($user){
        
$sendableUserMerit db_query("select sum(amount) from merit_ledger where ID_MEMBER_TO=$user"__FILE____LINE__);
        if(
mysql_num_rows($sendableUserMerit))
                
$sendableUserMerit = (int)(mysql_fetch_array($sendableUserMerit)[0]/2);
        else
                
$sendableUserMerit 0;
        
        
// merit_sources is a log of when users' source merit was changed: "source merit becomes 'amount' at timestamp 'time'"
        
$q db_query("select time, amount from merit_sources where ID_MEMBER=$user order by time asc"__FILE____LINE__);
        if(!
mysql_num_rows($q)) {
                
$sent db_query("select sum(amount) from merit_ledger where ID_MEMBER_FROM=$user"__FILE____LINE__);
                if(
mysql_num_rows($sent))
                        
$sent = (int)mysql_fetch_array($sent)[0];
                else
                        
$sent 0;
                return array(
$sendableUserMerit $sent0);
        }
        
        
// this user is/was a source, so the calculation is more complex
        
$sourceAmtLog = array();
        while(
$row=mysql_fetch_array($q))
                
$sourceAmtLog[] = $row;
        
mysql_free_result($q);

        
$timeWindow 60*60*24*30;
        list(
$excessSent) = mysql_fetch_array(db_query("select sum(amount) from merit_ledger where ID_MEMBER_FROM=$user and time<{$sourceAmtLog[0][0]}"__FILE____LINE__));
        if(empty(
$excessSent))
                
$excessSent 0;

        
$sourceMeritSendsRange = array();
        
$sourceMeritSendsRangeSum 0;
        
$sourcePos 0;

        
$q db_query("select time, amount from merit_ledger where ID_MEMBER_FROM=$user and time>={$sourceAmtLog[0][0]}"__FILE____LINE__);
        
$sends = array();
        while(
$row mysql_fetch_array($q))
                
$sends[] = $row;
        
mysql_free_result($q);

        foreach(
$sends as $send) {
                if(
$sourcePos count($sourceAmtLog)-&& $send[0] >= $sourceAmtLog[$sourcePos+1][0]) {
                        
$sourcePos++;
                        
$sourceMeritSendsRangeSum=0;
                        
$sourceMeritSendsRange = array();
                }
                while(
count($sourceMeritSendsRange)>&& ($send[0] - $sourceMeritSendsRange[0][0] > $timeWindow)) {
                        
$sourceMeritSendsRangeSum -= array_shift($sourceMeritSendsRange)[1];
                }
                
$remainingSource max($sourceAmtLog[$sourcePos][1]-$sourceMeritSendsRangeSum0);
                
$excessSent += max($send[1]-$remainingSource0);
                
$sourceMeritSendAmount min($remainingSource$send[1]);
                if(
$sourceMeritSendAmount>0) {
                        
$sourceMeritSendsRange[] = array($send[0], $sourceMeritSendAmount);
                        
$sourceMeritSendsRangeSum += $sourceMeritSendAmount;
                }
        }

        
$sendableUserMerit -= $excessSent;
        if(
$sourcePos != count($sourceAmtLog)-1) {
                
$sourcePos count($sourceAmtLog)-1;
                
$sourceMeritSendsRangeSum=0;
                
$sourceMeritSendsRange = array();
        }
        while(
count($sourceMeritSendsRange) > && (time() - $sourceMeritSendsRange[0][0] > $timeWindow)) {
                
$sourceMeritSendsRangeSum -= array_shift($sourceMeritSendsRange)[1];
        }

        
$sendableSourceMerit max($sourceAmtLog[$sourcePos][1] - $sourceMeritSendsRangeSum0);
        return array(
$sendableUserMerit$sendableSourceMerit);
}