Switch miner.cpp to use sha2 instead of OpenSSL.

This commit is contained in:
Pieter Wuille 2014-04-27 23:34:02 +02:00
parent cf0c47b269
commit 85aab2a088
3 changed files with 29 additions and 165 deletions

View File

@ -6,14 +6,13 @@
#include "miner.h" #include "miner.h"
#include "core.h" #include "core.h"
#include "hash.h"
#include "main.h" #include "main.h"
#include "net.h" #include "net.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include "wallet.h" #include "wallet.h"
#endif #endif
#include <openssl/sha.h>
using namespace std; using namespace std;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -21,42 +20,6 @@ using namespace std;
// BitcoinMiner // BitcoinMiner
// //
int static 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;
}
static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
void SHA256Transform(void* pstate, void* pinput, const void* pinit)
{
SHA256_CTX ctx;
unsigned char data[64];
SHA256_Init(&ctx);
for (int i = 0; i < 16; i++)
((uint32_t*)data)[i] = ByteReverse(((uint32_t*)pinput)[i]);
for (int i = 0; i < 8; i++)
ctx.h[i] = ((uint32_t*)pinit)[i];
SHA256_Update(&ctx, data, sizeof(data));
for (int i = 0; i < 8; i++)
((uint32_t*)pstate)[i] = ctx.h[i];
}
// //
// Unconfirmed transactions in the memory pool often depend on other // Unconfirmed transactions in the memory pool often depend on other
// transactions in the memory pool. When we select transactions from the // transactions in the memory pool. When we select transactions from the
@ -372,51 +335,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
} }
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1)
{
//
// Pre-build hash buffers
//
struct
{
struct unnamed2
{
int nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
unsigned int nTime;
unsigned int nBits;
unsigned int nNonce;
}
block;
unsigned char pchPadding0[64];
uint256 hash1;
unsigned char pchPadding1[64];
}
tmp;
memset(&tmp, 0, sizeof(tmp));
tmp.block.nVersion = pblock->nVersion;
tmp.block.hashPrevBlock = pblock->hashPrevBlock;
tmp.block.hashMerkleRoot = pblock->hashMerkleRoot;
tmp.block.nTime = pblock->nTime;
tmp.block.nBits = pblock->nBits;
tmp.block.nNonce = pblock->nNonce;
FormatHashBlocks(&tmp.block, sizeof(tmp.block));
FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1));
// Byte swap all the input buffer
for (unsigned int i = 0; i < sizeof(tmp)/4; i++)
((unsigned int*)&tmp)[i] = ByteReverse(((unsigned int*)&tmp)[i]);
// Precalc the first half of the first hash, which stays constant
SHA256Transform(pmidstate, &tmp.block, pSHA256InitState);
memcpy(pdata, &tmp.block, 128);
memcpy(phash1, &tmp.hash1, 64);
}
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// //
@ -427,34 +345,33 @@ int64_t nHPSTimerStart = 0;
// //
// ScanHash scans nonces looking for a hash with at least some zero bits. // ScanHash scans nonces looking for a hash with at least some zero bits.
// It operates on big endian data. Caller does the byte reversing. // The nonce is usually preserved between calls, but periodically or if the
// All input buffers are 16-byte aligned. nNonce is usually preserved // nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at
// between calls, but periodically or if nNonce is 0xffff0000 or above, // zero.
// the block is rebuilt and nNonce starts over at zero.
// //
unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) {
{ // Write the first 76 bytes of the block header to a double-SHA256 state.
unsigned int& nNonce = *(unsigned int*)(pdata + 12); CHash256 hasher;
for (;;) CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
{ ss << *pblock;
// Crypto++ SHA256 assert(ss.size() == 80);
// Hash pdata using pmidstate as the starting state into hasher.Write((unsigned char*)&ss[0], 76);
// pre-formatted buffer phash1, then hash phash1 into phash
for (;;) {
nNonce++; nNonce++;
SHA256Transform(phash1, pdata, pmidstate);
SHA256Transform(phash, phash1, pSHA256InitState); // Write the last 4 bytes of the block header (the nonce) to a copy of
// the double-SHA256 state, and compute the result.
CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);
// Return the nonce if the hash has at least some zero bits, // Return the nonce if the hash has at least some zero bits,
// caller will check if it has enough to reach the target // caller will check if it has enough to reach the target
if (((unsigned short*)phash)[14] == 0) if (((uint16_t*)phash)[15] == 0)
return nNonce; return true;
// If nothing found after trying for a while, return -1 // If nothing found after trying for a while, return -1
if ((nNonce & 0xffff) == 0) if ((nNonce & 0xffff) == 0)
{ return false;
nHashesDone = 0xffff+1;
return (unsigned int) -1;
}
if ((nNonce & 0xfff) == 0) if ((nNonce & 0xfff) == 0)
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
} }
@ -541,46 +458,27 @@ void static BitcoinMiner(CWallet *pwallet)
LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(), LogPrintf("Running BitcoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));
//
// Pre-build hash buffers
//
char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
FormatHashBuffers(pblock, pmidstate, pdata, phash1);
unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
unsigned int& nBlockBits = *(unsigned int*)(pdata + 64 + 8);
unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
// //
// Search // Search
// //
int64_t nStart = GetTime(); int64_t nStart = GetTime();
uint256 hashTarget = uint256().SetCompact(pblock->nBits); uint256 hashTarget = uint256().SetCompact(pblock->nBits);
uint256 hashbuf[2]; uint256 hash;
uint256& hash = *alignup<16>(hashbuf); uint32_t nNonce = 0;
uint32_t nOldNonce = 0;
while (true) while (true)
{ {
unsigned int nHashesDone = 0; bool fFound = ScanHash(pblock, nNonce, &hash);
unsigned int nNonceFound; uint32_t nHashesDone = nNonce - nOldNonce;
nOldNonce = nNonce;
// Crypto++ SHA256
nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
(char*)&hash, nHashesDone);
// Check if something found // Check if something found
if (nNonceFound != (unsigned int) -1) if (fFound)
{ {
for (unsigned int i = 0; i < sizeof(hash)/4; i++)
((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
if (hash <= hashTarget) if (hash <= hashTarget)
{ {
// Found a solution // Found a solution
pblock->nNonce = ByteReverse(nNonceFound); pblock->nNonce = nNonce;
assert(hash == pblock->GetHash()); assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL); SetThreadPriority(THREAD_PRIORITY_NORMAL);
@ -629,7 +527,7 @@ void static BitcoinMiner(CWallet *pwallet)
// Regtest mode doesn't require peers // Regtest mode doesn't require peers
if (vNodes.empty() && Params().MiningRequiresPeers()) if (vNodes.empty() && Params().MiningRequiresPeers())
break; break;
if (nBlockNonce >= 0xffff0000) if (nNonce >= 0xffff0000)
break; break;
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break; break;
@ -638,11 +536,9 @@ void static BitcoinMiner(CWallet *pwallet)
// Update nTime every few seconds // Update nTime every few seconds
UpdateTime(*pblock, pindexPrev); UpdateTime(*pblock, pindexPrev);
nBlockTime = ByteReverse(pblock->nTime);
if (Params().AllowMinDifficultyBlocks()) if (Params().AllowMinDifficultyBlocks())
{ {
// Changing pblock->nTime can change work required on testnet: // Changing pblock->nTime can change work required on testnet:
nBlockBits = ByteReverse(pblock->nBits);
hashTarget.SetCompact(pblock->nBits); hashTarget.SetCompact(pblock->nBits);
} }
} }

View File

@ -23,12 +23,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey); CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */ /** Modify the extranonce in a block */
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
/** Do mining precalculation */
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
/** Check mined block */ /** Check mined block */
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
/** Base sha256 mining transform */
void SHA256Transform(void* pstate, void* pinput, const void* pinit);
extern double dHashesPerSec; extern double dHashesPerSec;
extern int64_t nHPSTimerStart; extern int64_t nHPSTimerStart;

View File

@ -9,8 +9,6 @@
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
extern void SHA256Transform(void* pstate, void* pinput, const void* pinit);
BOOST_AUTO_TEST_SUITE(miner_tests) BOOST_AUTO_TEST_SUITE(miner_tests)
static static
@ -259,30 +257,4 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
} }
BOOST_AUTO_TEST_CASE(sha256transform_equality)
{
unsigned int pSHA256InitState[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
// unsigned char pstate[32];
unsigned char pinput[64];
int i;
for (i = 0; i < 32; i++) {
pinput[i] = i;
pinput[i+32] = 0;
}
uint256 hash;
SHA256Transform(&hash, pinput, pSHA256InitState);
BOOST_TEST_MESSAGE(hash.GetHex());
uint256 hash_reference("0x2df5e1c65ef9f8cde240d23cae2ec036d31a15ec64bc68f64be242b1da6631f3");
BOOST_CHECK(hash == hash_reference);
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()