aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authors_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>2010-09-13 22:14:24 +0000
committers_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>2010-09-13 22:14:24 +0000
commit3df62878c3cece15a8921fbbdee7859ee9368768 (patch)
tree022c49f65221446777bda53e1d73cb89689bbdd9
parentfdbf76d4f49c220e2ed4412a3d8d8cd6efd74826 (diff)
downloadbitcoin-3df62878c3cece15a8921fbbdee7859ee9368768.tar.xz
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
-rw-r--r--main.cpp231
-rw-r--r--main.h3
-rw-r--r--serialize.h2
-rw-r--r--sha256.cpp52
4 files changed, 175 insertions, 113 deletions
diff --git a/main.cpp b/main.cpp
index 8d2fdde0ea..c26755f72f 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<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 dd86fc19f7..0082d5d065 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 6c636e1b8b..e9f7e2db78 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 1bba8cf93a..56a89260cb 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 <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;