From 71cc095cb26c4967ed9e9ebf89b6eb1e685c3844 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Mon, 13 Sep 2010 22:14:24 +0000 Subject: [PATCH] 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 --- main.cpp | 231 +++++++++++++++++++++++++++------------------------- main.h | 3 +- serialize.h | 2 +- sha256.cpp | 52 +++++++++++- 4 files changed, 175 insertions(+), 113 deletions(-) diff --git a/main.cpp b/main.cpp index 8d2fdde0..c26755f7 100644 --- a/main.cpp +++ b/main.cpp @@ -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, 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 mapTestPool; vector 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(); - nCycleCounter = 0; - } - else - nCycleCounter++; - if (GetTimeMillis() - nHPSTimerStart > 4000) + nHPSTimerStart = GetTimeMillis(); + nHashCounter = 0; + } + else + nHashCounter += nHashesDone; + if (GetTimeMillis() - nHPSTimerStart > 4000) + { + static CCriticalSection cs; + CRITICAL_BLOCK(cs) { - 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; + // 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; - pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - tmp.block.nTime = ByteReverse(pblock->nTime); - } + // 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()) { diff --git a/main.h b/main.h index dd86fc19..0082d5d0 100644 --- a/main.h +++ b/main.h @@ -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 diff --git a/serialize.h b/serialize.h index 6c636e1b..e9f7e2db 100644 --- a/serialize.h +++ b/serialize.h @@ -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"; diff --git a/sha256.cpp b/sha256.cpp index 1bba8cf9..56a89260 100644 --- a/sha256.cpp +++ b/sha256.cpp @@ -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 @@ -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 +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; +} + +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 Double_BlockSHA256(const void* pin, void* pad, const void *pre, unsigned int thash[9][NPAR], const void *init) +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;