reorganize BitcoinMiner to make it easier to add different SHA256 routines

git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@154 1a98c847-1fd6-4fd8-948a-caf3550aa51b
This commit is contained in:
s_nakamoto 2010-09-13 22:14:24 +00:00
parent fdbf76d4f4
commit 3df62878c3
4 changed files with 176 additions and 114 deletions

233
main.cpp
View File

@ -2392,13 +2392,11 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
else if (strCommand == "getaddr")
{
// This includes all nodes that are currently online,
// since they rebroadcast an addr every 24 hours
// Nodes rebroadcast an addr every 24 hours
pfrom->vAddrToSend.clear();
int64 nSince = GetAdjustedTime() - 12 * 60 * 60; // in the last 12 hours
int64 nSince = GetAdjustedTime() - 6 * 60 * 60; // in the last 6 hours
CRITICAL_BLOCK(cs_mapAddresses)
{
unsigned int nSize = mapAddresses.size();
foreach(const PAIRTYPE(vector<unsigned char>, CAddress)& item, mapAddresses)
{
if (fShutdown)
@ -2738,35 +2736,6 @@ void ThreadBitcoinMiner(void* parg)
printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[3]);
}
int FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
unsigned char* pend = pdata + 64 * blocks;
memset(pdata + len, 0, 64 * blocks - len);
pdata[len] = 0x80;
unsigned int bits = len * 8;
pend[-1] = (bits >> 0) & 0xff;
pend[-2] = (bits >> 8) & 0xff;
pend[-3] = (bits >> 16) & 0xff;
pend[-4] = (bits >> 24) & 0xff;
return blocks;
}
using CryptoPP::ByteReverse;
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
memcpy(pstate, pinit, 32);
CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
}
static const int NPAR = 32;
extern void Double_BlockSHA256(const void* pin, void* pout, const void* pinit, unsigned int hash[8][NPAR], const void* init2);
#if defined(__GNUC__) && defined(CRYPTOPP_X86_ASM_AVAILABLE)
void CallCPUID(int in, int& aret, int& cret)
{
@ -2829,6 +2798,67 @@ bool Detect128BitSSE2()
bool Detect128BitSSE2() { return false; }
#endif
int FormatHashBlocks(void* pbuffer, unsigned int len)
{
unsigned char* pdata = (unsigned char*)pbuffer;
unsigned int blocks = 1 + ((len + 8) / 64);
unsigned char* pend = pdata + 64 * blocks;
memset(pdata + len, 0, 64 * blocks - len);
pdata[len] = 0x80;
unsigned int bits = len * 8;
pend[-1] = (bits >> 0) & 0xff;
pend[-2] = (bits >> 8) & 0xff;
pend[-3] = (bits >> 16) & 0xff;
pend[-4] = (bits >> 24) & 0xff;
return blocks;
}
using CryptoPP::ByteReverse;
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
inline void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
memcpy(pstate, pinit, 32);
CryptoPP::SHA256::Transform((CryptoPP::word32*)pstate, (CryptoPP::word32*)pinput);
}
//
// ScanHash scans nonces looking for a hash with at least some zero bits.
// It operates on big endian data. Caller does the byte reversing.
// All input buffers are 16-byte aligned. nNonce is usually preserved
// between calls, but periodically or if nNonce is above 0xff000000,
// the block is rebuilt and nNonce starts over at zero.
//
unsigned int ScanHash_CryptoPP(char* pmidstate, char* pblock, char* phash1, char* phash, unsigned int& nHashesDone)
{
unsigned int& nNonce = *(unsigned int*)(pblock + 12);
for (;;)
{
// Crypto++ SHA-256
// Hash pblock using pmidstate as the starting state into
// preformatted buffer phash1, then hash phash1 into phash
nNonce++;
SHA256Transform(phash1, pblock, pmidstate);
SHA256Transform(phash, phash1, pSHA256InitState);
// Return the nonce if the hash has at least some zero bits,
// caller will check if it has enough to reach the target
if (((unsigned short*)phash)[14] == 0)
return nNonce;
// If nothing found after trying for a while, return -1
if ((nNonce & 0xffff) == 0)
{
nHashesDone = 0xffff+1;
return -1;
}
}
}
extern unsigned int ScanHash_4WaySSE2(char* pmidstate, char* pblock, char* phash1, char* phash, unsigned int& nHashesDone);
@ -2883,7 +2913,7 @@ void BitcoinMiner()
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
// Collect the latest transactions into the block
// Collect memory pool transactions into the block
int64 nFees = 0;
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_mapTransactions)
@ -2891,9 +2921,9 @@ void BitcoinMiner()
CTxDB txdb("r");
map<uint256, CTxIndex> mapTestPool;
vector<char> vfAlreadyAdded(mapTransactions.size());
bool fFoundSomething = true;
uint64 nBlockSize = 10000;
int nBlockSigOps = 100;
bool fFoundSomething = true;
while (fFoundSomething)
{
fFoundSomething = false;
@ -2984,46 +3014,28 @@ void BitcoinMiner()
uint256& hash = *alignup<16>(hashbuf);
loop
{
unsigned int nHashesDone = 0;
unsigned int nNonceFound;
#ifdef FOURWAYSSE2
if (f4WaySSE2)
{
// tcatm's 4-way SSE2 SHA-256
tmp.block.nNonce += NPAR;
unsigned int thashbuf[9][NPAR];
unsigned int (&thash)[9][NPAR] = *alignup<16>(&thashbuf);
Double_BlockSHA256((char*)&tmp.block + 64, &tmp.hash1, &midstate, thash, pSHA256InitState);
((unsigned short*)&hash)[14] = 0xffff;
for (int j = 0; j < NPAR; j++)
{
if (thash[7][j] == 0)
{
for (int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = thash[i][j];
pblock->nNonce = ByteReverse(tmp.block.nNonce + j);
}
}
}
// tcatm's 4-way 128-bit SSE2 SHA-256
nNonceFound = ScanHash_4WaySSE2((char*)&midstate, (char*)&tmp.block + 64, (char*)&tmp.hash1, (char*)&hash, nHashesDone);
else
#endif
{
// Crypto++ SHA-256
tmp.block.nNonce++;
SHA256Transform(&tmp.hash1, (char*)&tmp.block + 64, &midstate);
SHA256Transform(&hash, &tmp.hash1, pSHA256InitState);
}
nNonceFound = ScanHash_CryptoPP((char*)&midstate, (char*)&tmp.block + 64, (char*)&tmp.hash1, (char*)&hash, nHashesDone);
if (((unsigned short*)&hash)[14] == 0)
// Check if something found
if (nNonceFound != -1)
{
// Byte swap the result after preliminary check
for (int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
if (hash <= hashTarget)
{
#ifdef FOURWAYSSE2
if (!f4WaySSE2)
#endif
pblock->nNonce = ByteReverse(tmp.block.nNonce);
// Found a solution
pblock->nNonce = ByteReverse(nNonceFound);
assert(hash == pblock->GetHash());
//// debug print
@ -3059,62 +3071,57 @@ void BitcoinMiner()
}
}
// Update nTime every few seconds
const unsigned int nMask = 0xffff;
const int nHashesPerCycle = (nMask+1);
if ((tmp.block.nNonce & nMask) == 0)
// Meter hashes/sec
static int64 nHashCounter;
if (nHPSTimerStart == 0)
{
// Meter hashes/sec
static int nCycleCounter;
if (nHPSTimerStart == 0)
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
}
else
nHashCounter += nHashesDone;
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
static CCriticalSection cs;
CRITICAL_BLOCK(cs)
{
nHPSTimerStart = GetTimeMillis();
nCycleCounter = 0;
}
else
nCycleCounter++;
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
static CCriticalSection cs;
CRITICAL_BLOCK(cs)
if (GetTimeMillis() - nHPSTimerStart > 4000)
{
if (GetTimeMillis() - nHPSTimerStart > 4000)
dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
nHPSTimerStart = GetTimeMillis();
nHashCounter = 0;
string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
UIThreadCall(bind(CalledSetStatusBar, strStatus, 0));
static int64 nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
dHashesPerSec = 1000.0 * nHashesPerCycle * nCycleCounter / (GetTimeMillis() - nHPSTimerStart);
nHPSTimerStart = GetTimeMillis();
nCycleCounter = 0;
string strStatus = strprintf(" %.0f khash/s", dHashesPerSec/1000.0);
UIThreadCall(bind(CalledSetStatusBar, strStatus, 0));
static int64 nLogTime;
if (GetTime() - nLogTime > 30 * 60)
{
nLogTime = GetTime();
printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
}
nLogTime = GetTime();
printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str());
printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[3], dHashesPerSec/1000.0);
}
}
}
// Check for stop or if block needs to be rebuilt
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
return;
if (vNodes.empty())
break;
if (tmp.block.nNonce == 0)
break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != pindexBest)
break;
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
tmp.block.nTime = ByteReverse(pblock->nTime);
}
// Check for stop or if block needs to be rebuilt
if (fShutdown)
return;
if (!fGenerateBitcoins)
return;
if (fLimitProcessors && vnThreadsRunning[3] > nLimitProcessors)
return;
if (vNodes.empty())
break;
if (tmp.block.nNonce >= 0xff000000)
break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break;
if (pindexPrev != pindexBest)
break;
// Update nTime every few seconds
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
tmp.block.nTime = ByteReverse(pblock->nTime);
}
}
}
@ -3352,6 +3359,10 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CK
if (!SignSignature(*pcoin, wtxNew, nIn++))
return false;
// Limit size
if (::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK) >= MAX_BLOCK_SIZE_GEN/5)
return false;
// Check that enough fee is included
if (nFee < wtxNew.GetMinFee())
{

3
main.h
View File

@ -15,6 +15,7 @@ class CWalletTx;
class CKeyItem;
static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2;
static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
static const int64 COIN = 100000000;
static const int64 CENT = 1000000;
@ -475,7 +476,7 @@ public:
return error("CTransaction::CheckTransaction() : vin or vout empty");
// Size limits
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_SIZE)
if (::GetSerializeSize(*this, SER_NETWORK) > MAX_BLOCK_SIZE)
return error("CTransaction::CheckTransaction() : size limits failed");
// Check for negative or overflow output values

View File

@ -23,7 +23,7 @@ class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 312;
static const char* pszSubVer = ".4";
static const char* pszSubVer = ".5";

View File

@ -2,6 +2,8 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
// tcatm's 4-way 128-bit SSE2 SHA-256
#ifdef FOURWAYSSE2
#include <string.h>
@ -13,6 +15,8 @@
#define NPAR 32
extern void DoubleBlockSHA256(const void* pin, void* pout, const void* pinit, unsigned int hash[8][NPAR], const void* init2);
static const unsigned int sha256_consts[] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, /* 0 */
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
@ -88,8 +92,54 @@ static inline void dumpreg(__m128i x, char *msg) {
#define dumpstate()
#endif
// Align by increasing pointer, must have extra space at end of buffer
template <size_t nBytes, typename T>
T* alignup(T* p)
{
union
{
T* ptr;
size_t n;
} u;
u.ptr = p;
u.n = (u.n + (nBytes-1)) & ~(nBytes-1);
return u.ptr;
}
void Double_BlockSHA256(const void* pin, void* pad, const void *pre, unsigned int thash[9][NPAR], const void *init)
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
unsigned int ScanHash_4WaySSE2(char* pmidstate, char* pblock, char* phash1, char* phash, unsigned int& nHashesDone)
{
unsigned int& nNonce = *(unsigned int*)(pblock + 12);
for (;;)
{
nNonce += NPAR;
unsigned int thashbuf[9][NPAR];
unsigned int (&thash)[9][NPAR] = *alignup<16>(&thashbuf);
DoubleBlockSHA256(pblock, phash1, pmidstate, thash, pSHA256InitState);
for (int j = 0; j < NPAR; j++)
{
if (thash[7][j] == 0)
{
for (int i = 0; i < 32/4; i++)
((unsigned int*)phash)[i] = thash[i][j];
return nNonce + j;
}
}
if ((nNonce & 0xffff) == 0)
{
nHashesDone = 0xffff+1;
return -1;
}
}
}
void DoubleBlockSHA256(const void* pin, void* pad, const void *pre, unsigned int thash[9][NPAR], const void *init)
{
unsigned int* In = (unsigned int*)pin;
unsigned int* Pad = (unsigned int*)pad;