eMule 49b. TK4 Mod 2.2b



The TK4 Mod has 5 credit system options.

TK4 Credit System

Objectives.

I believe a credit system does two things, it helps you download a file faster because you give more data to people who share and hence you get data back from them faster as most of them will be using a credit system. You give less data to Leeches,(people who deliberately take and do not give). This protect the network, because if everyone leeched, there would be no file sharing.

Firstly I will describe my credit system, the TK4 system. Note C++ for all of the systems is at the end of this document.

Overview.

If you are sharing completed files and someone downloads data from one of these from you they probably cannot give you data back as you have all of the file. So in the TK4 system their credit rating remains unchanged. If you are downloading a file and someone takes data from you from the parts of the file you have they will be subject to the credit system and depending on how much they have given they may have their credit rating reduced. At any time if anyone gives you data they get a credit rating increase. The credit system works basically like this:

credit start point = 10
allowance = 'Mb given'/4 + 1 Mb

if 'Mb taken' greater than 'Mb given + allowance + 1Mb (they have taken more than they gave + some)

Then if the file is a file we are downloading

	if '(Mb taken - allowance)' is between 1 to 81Mb credit multiplier range = 9 to 1
	math:  10 - square root('(Mb taken - allowance)' - 'Mb given')
	if '(Mb taken - allowance)' is greater than 81Mb credit multiplier range = 1 to 0.14
	math:   9 / square root('(Mb taken - allowance)' -'Mb given')
if 'Mb given' is greater than 'Mb taken' (they have given more than they have taken)
	credit multiplier range = 10 to 342
	math: 10 + log(2.72+('Mb given'-'Mb taken)*4)+('Mb taken/12)
There is no absolute range for multipliers but I have quoted a range of 0.14< to >342 (Assumes around a max. 4Gb difference) with a starting point of 10. Clients with failed SUI will start at 10, but not go up.


The eMule standard system.

The eMule standard system documented as working thus:

There are two different credit modifier calculated:

  Ratio1 = Uploaded Total x 2 / Downloaded Total
  Ratio2 = SQRT(Uploaded Total + 2)

Both ratios are compared and the lower value is used as modifier. Some boundary conditions also exist:

  Uploaded Total << 1MB => Modifier = 1
  Downloaded Total = 0 => Modifier = 10
  The modifier may not be lower than 1 or higher than 10

But as of version 46c the actual code does this:

There are two different credit modifier calculated:

  Ratio1 = Uploaded Total x 2 / Downloaded Total
  Ratio2 = SQRT(Uploaded Total + 2)

Both ratios are compared and the lower value is used as modifier.
Some boundary conditions also exist:

  Uploaded Total > 0.95MB => Modifier = 1
  The modifier may not be lower than 1 or higher than 10

Although this may change in future eMules as this *is* the eMule credit system whether by design or not. If you select 'eMule Standard' credit system. You will be selecting the same algorithm as in the un-mod'ed eMule 46c.


Lovelace.

Lovelace is the credit system from the Lovelace mod and is a popular credit system.
Below is algorithm implemented for Lovelace:

dl-modifier=100*((1-1/(1+exp((3*{MB uploaded to us}^2-{MB downloaded from us}^2)/1000)))^6.6667)
new credit system (start:1, max:100, min:0.1, ratio:1:1.5, only one formula)
Only clients using the 'SecureHash' are able to get a multiplier of 100. All others will stick at 10.
Eastshare.

Eastshare is the credit from the Eastshare mod another popular credit system.

base ratings: id. users(100); invalid id. users(0); min.=10, max.=5000
  +6 per MB uploaded and -2 for downloaded; +100 if upload 1MB+; if rating < 50 and upload 1MB+, rating = 50
Fine.

The Fine credit system created by CiccioBastardo is a true file sharing credit system. Whereas my own credit system and others could be siad to have trading elements, eg. you give more you are likely to recieve more back. The Fine credit system punishes leechers but does not reward givers thus operating in the true spirit of file sharing.

CiccioBastardo's source code description: 
				"With this type of credits attribution I'm only penalizing those clients that do not upload enough only for non complete files.
				For complete files there is no credits evaluation.
				This menagement is "symmetric", as two clients using it will both not get penalized if the simple rules are respected.
				Moreover unlike the official and the other modification I've seen so far, there's no way to exploit it for credit shaping.
				That is, you get nothing more than what you deserves by waiting in the queue if you upload enough. Uploading more gives you
				no advantages. This prevents using tactics like powersharing unfinished files to get more credits. No tit-for-tat possible.
				Respecting the rules makes the clients competing on the same basis as newbies or those asking for complete files.
				In short, you are always neutral, and fairly treated, untill you are not able to keep U-D gap below the maximum limit possible
				and start being evil. The bigger the gap, the worse the treatment (but you can always wait enough in the queue to download
				something more and make you position still worse).
				There are no promoted good clients as in other CS which can be exploited for that. Nor there's a newbie boost which can be 
				exploited as well by changing the hash every session.

				Moreover the equation is based on an absolute difference so there is no the trick to upload X and be able to download n*X 
				before things start even out, as in the official CS.

				Doubts remain on how to treat clients with no SUI. For now a small penalty is applied."
For those of you who know C++ below is the GetScoreRatio() with some comments remove,(for easy reading in a text only format)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changed for version 1.3c to speed up the code results are unchanged, Eastshare code updated form Eastshare for 1.4g.
Changed for version 1.5e to further reduce CPU usage.
Changed for version 2.0b to further reduce CPU usage.
float CClientCredits::GetScoreRatio(uint32 dwForIP, CUpDownClient* pClient,  CKnownFile* currequpfile) const
{  //Why make a duplicate call? 
	EIdentState currentIDstate = GetCurrentIdentState(dwForIP);// get the client ident status
	float result;//result returned
	
	switch(thePrefs.creditsystem_tk4){	

case 0:{/*STANDARD eMule credit system - RANGE 1.0F - 10.0F */
        //Below the credit system as per eMule above the system as per it's description on the eMule site
        // bad guy - no credits for you
		if((currentIDstate == IS_IDFAILED || currentIDstate == IS_IDBADGUY || currentIDstate == IS_IDNEEDED) && theApp.clientcredits->CryptoAvailable()) return 1.0F;
		 //Given less than 1Mb
		if (GetDownloadedTotal() < 1000000)	return 1.0F;
		result = 10.0F;
		if(GetUploadedTotal()) result = (float)(((double)GetDownloadedTotal()*2.0)/(double)GetUploadedTotal());
		// Ratio2 = SQRT(given in Mb + 2)
		float result2 = (float)sqrt((float)(GetDownloadedTotal()/1048576.0) + 2.0F);
		//Take the lowest value
		if(result > result2)	result = result2;
		//keep within range
		if(result > 1.0F) return 1.0F;
		if (result > 10.0F) return 10.0F;
		return result;
	   }
	 
case 1:{/*LOVELACE credit formula -TK4 implementation- RANGE 0.1F - 100.0F //anti-leeching */
	    /*lovelace: dl-modifier=100*((1-1/(1+exp((3*{MB uploaded to us}^2-{MB downloaded from us}^2)/1000)))^6.6667)
		Credit system (start:1, max:100, min:0.1, ratio:1:1.5, only one formula)
		CreditThefts will not get any credits. Only clients using the 'SecureHash' are able to get a multiplier of 100. All others will stick at 10.
		CreditThefts part not implemented! */  	
		
		//	bad guy - no credits for you (they get 1.0F)
		if((currentIDstate == IS_IDFAILED || currentIDstate == IS_IDBADGUY || currentIDstate == IS_IDNEEDED) && theApp.clientcredits->CryptoAvailable())	return 0.1F;

		float uPloadMbSqd   =  powf(((float)GetDownloadedTotal()/1048576.0F),2.0F);
		float dOwnloadMbSqd =  powf(((float)GetUploadedTotal()/1048576.0F),2.0F);

		result = 100.0F*powf(1.0F-1.0F/(float)(1.0F+ exp((3.0F*uPloadMbSqd-dOwnloadMbSqd)/1000.0F)),6.6667F);
		//Client does not have secure hash so they have a maximum credit ceiling of 10
		if((currentIDstate!=IS_IDENTIFIED || m_pCredits->nKeySize == 0)  && result>10.0F) return 10.0F;
		//Keep within range,(needed?)
		if(result<0.1F) return 0.1F;
  		return result;
	   }
case 2:{// EastShare START - Added by TAHO, new Credit System //Modified by Pretender
		if((currentIDstate == IS_IDFAILED || currentIDstate == IS_IDBADGUY || currentIDstate == IS_IDNEEDED) && theApp.clientcredits->CryptoAvailable()) return 1.0F; //is before the switch in Eastshare
		result = 100;
		result += (float)((double)GetDownloadedTotal()/174762.67 - (double)GetUploadedTotal()/524288); //Modefied by Pretender - 20040120
			
		if((double)GetDownloadedTotal() > 1048576)
		  {
			result += 100; 
			if(result&<50 && ((double)GetDownloadedTotal()*10 > (double)GetUploadedTotal())) result=50;
		   } //Modefied by Pretender - 20040330

		if( result < 10 )
		  {
			result = 10;
		   } else 
			 if( result > 5000 )
		            {
			          result = 5000;
		             }
		result = result / 100;
		return result;
	 // EastShare END - Added by TAHO, new Credit System
	   }
case 4:{ // Created by CiccioBastardo
			/* With this type of credits attribution I'm only penalizing those clients that do not upload enough only for non complete files.
				For complete files there is no credits evaluation.
				This menagement is "symmetric", as two clients using it will both not get penalized if the simple rules are respected.
				Moreover unlike the official and the other modification I've seen so far, there's no way to exploit it for credit shaping.
				That is, you get nothing more than what you deserves by waiting in the queue if you upload enough. Uploading more gives you
				no advantages. This prevents using tactics like powersharing unfinished files to get more credits. No tit-for-tat possible.
				Respecting the rules makes the clients competing on the same basis as newbies or those asking for complete files.
				In short, you are always neutral, and fairly treated, untill you are not able to keep U-D gap below the maximum limit possible
				and start being evil. The bigger the gap, the worse the treatment (but you can always wait enough in the queue to download
				something more and make you position still worse).
				There are no promoted good clients as in other CS which can be exploited for that. Nor there's a newbie boost which can be 
				exploited as well by changing the hash every session.

				Moreover the equation is based on an absolute difference so there is no the trick to upload X and be able to download n*X 
				before things start even out, as in the official CS.

				Doubts remain on how to treat clients with no SUI. For now a small penalty is applied.
			*/
			
			#define UP_DOWN_GAP_LIMIT (PARTSIZE*4)

			//CUpDownClient* client = theApp.clientlist->FindClientByIP(dwForIP); //This is sloooooooow.
			// I pass the client as argument so I can extract all the info I need here
			//CKnownFile *currequpfile = theApp.sharedfiles->GetFileByID(pClient->GetUploadFileID()); // Uses hash map. Fast

			if(!currequpfile)
				return 1.0F;

			float result = 1.0F;

			// only for not complete files
			if (currequpfile->IsPartFile() && GetUploadedTotal() > GetDownloadedTotal()) {
				uint64 diff = GetUploadedTotal() - GetDownloadedTotal();
			
				if (GetDownloadedTotal() < PARTSIZE) // If not received at least a chunk, limit "risk" to 3 chunks instead of 4
					diff += PARTSIZE;
				
				if (diff > (uint64)UP_DOWN_GAP_LIMIT) {
					result *= (float)UP_DOWN_GAP_LIMIT/(float)diff; // This is surely smaller than 1
					result *= result;
				}			
		
				if (result > 1.0F)
					AddDebugLogLine(false, _T("Wrong rating for client %s (%s): %0.2f (diff: %s U:%s D:%s)"), pClient->GetUserName(), currequpfile->GetFileName(), result, CastItoXBytes((uint64)diff, false), CastItoXBytes((uint64)GetUploadedTotal(), false), CastItoXBytes((uint64)GetDownloadedTotal(), false));
			}
			
			return result;
			break;
		}
case 3:
default:
	   {//TK4 credit formula. Aims punish leechers quickly but be fair to those we want nothing from and reward sharers
		 //float result = 10.0F;
		 uint64 DownTotalInt;//added to remove a Divide by 4 and repalce it with a >> 2
		 //if SUI failed then credit starts at 10 as for everyone else but will not go up
		 if((currentIDstate == IS_IDFAILED || currentIDstate == IS_IDBADGUY || currentIDstate == IS_IDNEEDED) && theApp.clientcredits->CryptoAvailable()){
			 // CUpDownClient* pClient = theApp.clientlist->FindClientByIP(dwForIP);//Get 'client' so we can get file info
			  float dOwnloadedSessionTotal = (float)(DownTotalInt = pClient->GetTransferredDown());
			  float uPloadedSessionTotal = (float)pClient->GetTransferredUp();
			  float allowance = (float)(DownTotalInt >> 2);
			  //partfile 10 - 0.14 complete 10
			  if(uPloadedSessionTotal > (float)(dOwnloadedSessionTotal + allowance + 1048576.0F)){
			 // CKnownFile* file = theApp.sharedfiles->GetFileByID(pClient->GetUploadFileID()); ///*Faster for version 2.0b*/
			     if(currequpfile!=NULL){//Are they requesting a file? NULL can be produced when client details calls getscoreratio() without this line eMule will crash.
					            if(currequpfile->IsPartFile()){//It's a file we are trying to obtain so we want to give to givers so we may get the file quicker.
							       float MbSqd =sqrt((float)(uPloadedSessionTotal-(dOwnloadedSessionTotal + allowance))/1048576.0F);
							       if(MbSqd > 9.0F) return ( 9.0F / MbSqd); //above 81mb values 1 - 0 9/(9 - x)
							         else	      return (10.0F - MbSqd); //for the first 81Mb (10 -(0-9))
							      }

				}
			  } 
			return 10.0F;
		    }
		//float is 1e38 it should be sufficient given 1 Gig is 1e9 hence 1000Gig is 1e12....
		float dOwnloadedTotal =  (float)( DownTotalInt = GetDownloadedTotal());//(Given to us)
		float uPloadedTotal = (float)GetUploadedTotal(); //(Taken from us)
		float allowance = (float)(DownTotalInt >> 2);//reward uploaders with 1 Mb allowance for every 4Mb uploaded over what they have uploaded.
		if(uPloadedTotal>(float)(dOwnloadedTotal + allowance + 1048576.0F))//If they have taken above (1Mb + 'allowance')
		  {
 		   //  CUpDownClient* pClient = theApp.clientlist->FindClientByIP(dwForIP);//Get 'client' so we can get file info
			  // CKnownFile* file = theApp.sharedfiles->GetFileByID(pClient->GetUploadFileID()); /*Faster for version 2.0b*/
			  if(currequpfile!=NULL){//Are they requesting a file? NULL can be produced when client details calls getscoreratio() without this line eMule will crash.
			                 if(currequpfile->IsPartFile()){//It's a file we are trying to obtain so we want to give to givers so we may get the file quicker.
							       float MbSqd =sqrt((float)(uPloadedTotal-(dOwnloadedTotal + allowance))/1048576.0F);
							       if(MbSqd > 9.0F) return ( 9.0F / MbSqd); //above 81mb values 1 - 0 9/(9 - x)
							         else	      return (10.0F - MbSqd); //for the first 81Mb (10 -(0-9))
							      }
						    }
			} else //We may owe them :o) give a small proportional boost to an uploader
			 	  if(dOwnloadedTotal>uPloadedTotal){ // return  log(2.72 + (given - taken in Mb * 4)) + (given in bytes / 12Mb) + 10 (eg +1 for every 12Mb +.5  6Mb etc)
						return ( log(2.72F + (float)(dOwnloadedTotal-uPloadedTotal)/262144.0F) + (float)(10.0F + dOwnloadedTotal/12582912.0F) );
						}
		      return 10.0F;
           }
	   
	}//end switch

}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Below is eMule credit system as it should be according to its documentation:

		// bad guy - no credits for you
		if((currentIDstate == IS_IDFAILED || currentIDstate == IS_IDBADGUY || currentIDstate == IS_IDNEEDED) && theApp.clientcredits->CryptoAvailable()) return 1.0F;
		//Given < 1Mb
		if (GetDownloadedTotal() > 1048576)	return 1.0F; //was 1000000 (Fix CiccioBastardo - Bastard Mod Dev)
		//Not taken anything full credit else credit = (given*2)/taken
		if(!GetUploadedTotal())	return 10.0F;  //was result = 10.0F - TK4 Fix
		  else {
			    float result = (float)(((double)GetDownloadedTotal()*2.0)/(double)GetUploadedTotal());
		        // Ratio2 = SQRT(given in Mb + 2)
		        float result2 = (float)sqrt((float)(GetDownloadedTotal()/1048576.0) + 2.0F);
		        //Take the lowest value
		        if(result > result2)	result = result2;
		        //keep within range
		        if(result < 1.0F)	return 1.0F;
		        if (result > 10.0F)	return 10.0F;
		        return result;
			 }