From df370a367fe62c8215599a15b971f37478e54df4 Mon Sep 17 00:00:00 2001 From: Jimmy Kiselak Date: Fri, 1 Apr 2016 21:37:44 -0400 Subject: [PATCH] switch to dedicated PoW hash function for CheckProofOfWork --- src/chain.h | 5 ++++ src/chainparams.cpp | 8 +++--- src/hash.cpp | 9 +++++++ src/hash.h | 2 ++ src/main.cpp | 4 +-- src/miner.cpp | 52 +++++++++--------------------------- src/primitives/block.cpp | 9 +++++++ src/primitives/block.h | 2 ++ src/rpcmining.cpp | 2 +- src/test/claimtrie_tests.cpp | 2 +- src/test/miner_tests.cpp | 2 +- src/test/test_bitcoin.cpp | 2 +- src/txdb.cpp | 2 +- 13 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/chain.h b/src/chain.h index c7e0d263f..3b800934c 100644 --- a/src/chain.h +++ b/src/chain.h @@ -226,6 +226,11 @@ public: return *phashBlock; } + uint256 GetBlockPoWHash() const + { + return GetBlockHeader().GetPoWHash(); + } + int64_t GetBlockTime() const { return (int64_t)nTime; diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7b1ea382f..be6ddb400 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -59,15 +59,15 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.hashMerkleRoot = genesis.ComputeMerkleRoot(); genesis.hashClaimTrie = uint256S("0x0000000000000000000000000000000000000000000000000000000000000001"); - /*bool found = false; - while (!found) + /*while (true) { genesis.nNonce += 1; - if (CheckProofOfWork2(genesis.GetHash(), nBits, consensus)) + if (CheckProofOfWork2(genesis.GetPoWHash(), nBits, consensus)) { std::cout << "nonce: " << genesis.nNonce << std::endl; std::cout << "hex: " << genesis.GetHash().GetHex() << std::endl; - found = true; + std::cout << "pow hash: " << genesis.GetPoWHash().GetHex() << std::endl; + break; } }*/ return genesis; diff --git a/src/hash.cpp b/src/hash.cpp index 9711293e3..58999d108 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -13,6 +13,15 @@ inline uint32_t ROTL32(uint32_t x, int8_t r) return (x << r) | (x >> (32 - r)); } +uint256 PoWHash(const std::vector& input) +{ + CHash256 h; + h.Write(input.data(), input.size()); + uint256 result; + h.Finalize((unsigned char*)&result); + return result; +} + unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash) { // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp diff --git a/src/hash.h b/src/hash.h index 077155562..ac24b9444 100644 --- a/src/hash.h +++ b/src/hash.h @@ -159,6 +159,8 @@ uint256 SerializeHash(const T& obj, int nType=SER_GETHASH, int nVersion=PROTOCOL return ss.GetHash(); } +uint256 PoWHash(const std::vector& input); + unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector& vDataToHash); void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]); diff --git a/src/main.cpp b/src/main.cpp index d0e2436a9..7ad23b990 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1074,7 +1074,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + if (!CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus())) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; @@ -2849,7 +2849,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) + if (fCheckPOW && !CheckProofOfWork(block.GetPoWHash(), block.nBits, Params().GetConsensus())) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); diff --git a/src/miner.cpp b/src/miner.cpp index 0f5117126..e8cf02e74 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -504,39 +504,6 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned // Internal miner // -// -// ScanHash scans nonces looking for a hash with at least some zero bits. -// The nonce is usually preserved between calls, but periodically or if the -// nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at -// zero. -// -bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash) -{ - // Write the first 108 bytes of the block header to a double-SHA256 state. - CHash256 hasher; - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << *pblock; - assert(ss.size() == 112); - hasher.Write((unsigned char*)&ss[0], 108); - - while (true) { - nNonce++; - - // 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, - // caller will check if it has enough to reach the target - if (((uint16_t*)phash)[15] == 0) - return true; - - // If nothing found after trying for a while, return -1 - if ((nNonce & 0xfff) == 0) - return false; - } -} - static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams) { LogPrintf("%s\n", pblock->ToString()); @@ -618,17 +585,17 @@ void static BitcoinMiner(const CChainParams& chainparams) int64_t nStart = GetTime(); arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); uint256 hash; - uint32_t nNonce = 0; + pblock->nNonce = 0; + bool found = false; while (true) { // Check if something found - if (ScanHash(pblock, nNonce, &hash)) + while (true) { - if (UintToArith256(hash) <= hashTarget) + hash = pblock->GetPoWHash(); + if (((uint16_t*)&hash)[15] == 0 && UintToArith256(hash) <= hashTarget) { + found = true; // Found a solution - pblock->nNonce = nNonce; - assert(hash == pblock->GetHash()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("LBRYcrdMiner:\n"); LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex()); @@ -642,14 +609,19 @@ void static BitcoinMiner(const CChainParams& chainparams) break; } + pblock->nNonce += 1; + if ((pblock->nNonce & 0xFF) == 0) + break; } + if (found) + break; // Check for stop or if block needs to be rebuilt boost::this_thread::interruption_point(); // Regtest mode doesn't require peers if (vNodes.empty() && chainparams.MiningRequiresPeers()) break; - if (nNonce >= 0xffff0000) + if (pblock->nNonce >= 0xffff0000) break; if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index f5f0a6d38..7e7a0b63b 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -9,12 +9,21 @@ #include "tinyformat.h" #include "utilstrencodings.h" #include "crypto/common.h" +#include "streams.h" uint256 CBlockHeader::GetHash() const { return SerializeHash(*this); } +uint256 CBlockHeader::GetPoWHash() const +{ + CDataStream ds(SER_GETHASH, PROTOCOL_VERSION); + ds << *this; + std::vector input(ds.begin(), ds.end()); + return PoWHash(input); +} + uint256 CBlock::ComputeMerkleRoot(bool* fMutated) const { /* WARNING! If you're reading this because you're learning about crypto diff --git a/src/primitives/block.h b/src/primitives/block.h index 06c0bbb83..49420956a 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -67,6 +67,8 @@ public: uint256 GetHash() const; + uint256 GetPoWHash() const; + int64_t GetBlockTime() const { return (int64_t)nTime; diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 7e9b45759..00eb9fb66 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -165,7 +165,7 @@ UniValue generate(const UniValue& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { + while (!CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen. ++pblock->nNonce; diff --git a/src/test/claimtrie_tests.cpp b/src/test/claimtrie_tests.cpp index fe01df273..2671720f4 100644 --- a/src/test/claimtrie_tests.cpp +++ b/src/test/claimtrie_tests.cpp @@ -89,7 +89,7 @@ bool CreateBlock(CBlockTemplate* pblocktemplate) for (int i = 0; ; ++i) { pblock->nNonce = i; - if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) + if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { break; } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 79e178c0f..67ff9f297 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) for (int j = 0; !fFound; j++) { pblock->nNonce = j; - if (CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) + if (CheckProofOfWork(pblock->GetPoWHash(), pblock->nBits, Params().GetConsensus())) { fFound = true; std::cout << pblock->nNonce << ","; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 26b0ff0ee..efc537e0e 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -126,7 +126,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector& unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); - while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; + while (!CheckProofOfWork(block.GetPoWHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce; CValidationState state; ProcessNewBlock(state, NULL, &block, true, NULL); diff --git a/src/txdb.cpp b/src/txdb.cpp index 9fddc6652..1d000e87e 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -204,7 +204,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) + if (!CheckProofOfWork(pindexNew->GetBlockPoWHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); pcursor->Next();