reorganize BitcoinMiner to make it easier to add different SHA256 routines
authors_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
Mon, 13 Sep 2010 22:14:24 +0000 (22:14 +0000)
committers_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
Mon, 13 Sep 2010 22:14:24 +0000 (22:14 +0000)
git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@154 1a98c847-1fd6-4fd8-948a-caf3550aa51b

main.cpp
main.h
serialize.h
sha256.cpp

index 8d2fdde..c26755f 100644 (file)
--- 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<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();
-                    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 dd86fc1..0082d5d 100644 (file)
--- 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
index 6c636e1..e9f7e2d 100644 (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";
 
 
 
index 1bba8cf..56a8926 100644 (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;
+}
+
+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;