From fe038d999ac1d67fa617f0a0e7aeae96a4d4cd04 Mon Sep 17 00:00:00 2001 From: 0xDEADFACE Date: Sun, 18 Oct 2015 12:29:53 -0700 Subject: [PATCH] Use 4Way hashing in proof-of-stake miner, if available. --- src/kernel.cpp | 47 ---------- src/kernel.h | 3 - src/kernel_worker.cpp | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ src/kernel_worker.h | 11 ++- src/miner.cpp | 22 ++--- 5 files changed, 262 insertions(+), 66 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index e554aff..3069c2c 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -468,53 +468,6 @@ bool ScanKernelForward(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxT return true; } -// Scan given midstate for solution -bool ScanContextBackward(SHA256_CTX &ctx, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::pair &solution) -{ - CBigNum bnTargetPerCoinDay; - bnTargetPerCoinDay.SetCompact(nBits); - - // Get maximum possible target to filter out the majority of obviously insufficient hashes - CBigNum bnMaxTargetPerCoinDay = bnTargetPerCoinDay * CBigNum(nValueIn) * nStakeMaxAge / COIN / nOneDay; - uint256 maxTarget = bnMaxTargetPerCoinDay.getuint256(); - - SHA256_CTX ctxCopy = ctx; - - // Search backward in time from the given timestamp - // Stopping search in case of shutting down - for (uint32_t nTimeTx=SearchInterval.first; nTimeTx>SearchInterval.second && !fShutdown; nTimeTx--) - { - // Complete first hashing iteration - uint256 hash1; - SHA256_Update(&ctxCopy, (unsigned char*)&nTimeTx, 4); - SHA256_Final((unsigned char*)&hash1, &ctxCopy); - - // Restore context - ctxCopy = ctx; - - // Finally, calculate kernel hash - uint256 hashProofOfStake; - SHA256((unsigned char*)&hash1, sizeof(hashProofOfStake), (unsigned char*)&hashProofOfStake); - - // Skip if hash doesn't satisfy the maximum target - if (hashProofOfStake > maxTarget) - continue; - - CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / nOneDay; - CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay; - - if (bnTargetProofOfStake >= CBigNum(hashProofOfStake)) - { - solution.first = hashProofOfStake; - solution.second = nTimeTx; - - return true; - } - } - - return false; -} - // Check kernel hash target and coinstake signature bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake) { diff --git a/src/kernel.h b/src/kernel.h index 3278a85..c76c00d 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -36,9 +36,6 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, uint32_t // Scan given kernel for solutions bool ScanKernelForward(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::vector > &solutions); -// Scan given context for kernel solutions -bool ScanContextBackward(SHA256_CTX &ctx, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::pair &solution); - // Check kernel hash target and coinstake signature // Sets hashProofOfStake on success return bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake); diff --git a/src/kernel_worker.cpp b/src/kernel_worker.cpp index 0c3b9d3..ee8400c 100644 --- a/src/kernel_worker.cpp +++ b/src/kernel_worker.cpp @@ -386,3 +386,248 @@ vector >& KernelWorker::GetSolutions() return solutions; } +// Scan given kernel for solutions +bool ScanKernelBackward(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::pair &solution) +{ + CBigNum bnTargetPerCoinDay; + bnTargetPerCoinDay.SetCompact(nBits); + + CBigNum bnValueIn(nValueIn); + + // Get maximum possible target to filter out the majority of obviously insufficient hashes + uint256 nMaxTarget = (bnTargetPerCoinDay * bnValueIn * nStakeMaxAge / COIN / nOneDay).getuint256(); + +#ifdef USE_ASM + +#ifdef __x86_64__ + if (false && fUse8Way) // AVX2 CPU + { + uint32_t blocks1[8 * 16] __attribute__((aligned(16))); + uint32_t blocks2[8 * 16] __attribute__((aligned(16))); + uint32_t candidates[8 * 8] __attribute__((aligned(16))); + + vector vRow = vector(8); + uint32_t *pnKernel = (uint32_t *) kernel; + + for(int i = 0; i < 7; i++) + { + fill(vRow.begin(), vRow.end(), pnKernel[i]); + copyrow8_swap32(&blocks1[i*8], &vRow[0]); + } + + memcpy(&blocks1[56], &block1_suffix_8way[0], 36*8); // sha256 padding + memcpy(&blocks2[64], &block2_suffix_8way[0], 32*8); + + uint32_t nHashes[8]; + uint32_t nTimeStamps[8]; + + // Search forward in time from the given timestamp + // Stopping search in case of shutting down + for (uint32_t nTimeTx=SearchInterval.first, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx= CBigNum(nHashProofOfStake)) + { + solution.first = nHashProofOfStake; + solution.second = nTimeStamps[nResult]; + + return true; + } + } + } + } + } + else +#endif + if (fUse4Way) // SSE2 or Neon CPU + { + uint32_t blocks1[4 * 16] __attribute__((aligned(16))); + uint32_t blocks2[4 * 16] __attribute__((aligned(16))); + uint32_t candidates[4 * 8] __attribute__((aligned(16))); + + vector vRow = vector(4); + uint32_t *pnKernel = (uint32_t *) kernel; + + for(int i = 0; i < 7; i++) + { + fill(vRow.begin(), vRow.end(), pnKernel[i]); + copyrow4_swap32(&blocks1[i*4], &vRow[0]); + } + + memcpy(&blocks1[28], &block1_suffix_4way[0], 36*4); // sha256 padding + memcpy(&blocks2[32], &block2_suffix_4way[0], 32*4); + + uint32_t nHashes[4]; + uint32_t nTimeStamps[4]; + + // Search forward in time from the given timestamp + // Stopping search in case of shutting down + for (uint32_t nTimeTx=SearchInterval.first, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx= CBigNum(nHashProofOfStake)) + { + solution.first = nHashProofOfStake; + solution.second = nTimeStamps[nResult]; + + return true; + } + } + } + } + } + else // Other CPU + { +#endif + +#if !defined(USE_ASM) || defined(__i386__) + SHA256_CTX ctx, workerCtx; + // Init new sha256 context and update it + // with first 24 bytes of kernel + SHA256_Init(&ctx); + SHA256_Update(&ctx, kernel, 8 + 16); + workerCtx = ctx; // save context + + // Search backward in time from the given timestamp + // Stopping search in case of shutting down + for (uint32_t nTimeTx=SearchInterval.first; nTimeTx>SearchInterval.second && !fShutdown; nTimeTx--) + { + // Complete first hashing iteration + uint256 hash1; + SHA256_Update(&ctx, (unsigned char*)&nTimeTx, 4); + SHA256_Final((unsigned char*)&hash1, &ctx); + + // Restore context + ctx = workerCtx; + + // Finally, calculate kernel hash + uint256 hashProofOfStake; + SHA256((unsigned char*)&hash1, sizeof(hashProofOfStake), (unsigned char*)&hashProofOfStake); + + // Skip if hash doesn't satisfy the maximum target + if (hashProofOfStake > nMaxTarget) + continue; + + CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / nOneDay; + CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay; + + if (bnTargetProofOfStake >= CBigNum(hashProofOfStake)) + { + solution.first = hashProofOfStake; + solution.second = nTimeTx; + + return true; + } + } +#else + uint32_t block1[16] __attribute__((aligned(16))); + uint32_t block2[16] __attribute__((aligned(16))); + uint32_t candidate[8] __attribute__((aligned(16))); + + memcpy(&block1[7], &block1_suffix[0], 36); // sha256 padding + memcpy(&block2[8], &block2_suffix[0], 32); + + uint32_t *pnKernel = (uint32_t *) kernel; + + for (int i = 0; i < 6; i++) + block1[i] = __builtin_bswap32(pnKernel[i]); + + // Search forward in time from the given timestamp + // Stopping search in case of shutting down + for (uint32_t nTimeTx=SearchInterval.first, nMaxTarget32 = nMaxTarget.Get32(7); nTimeTx nMaxTarget32) + continue; + + uint256 nHashProofOfStake; + uint32_t *pnHashProofOfStake = (uint32_t *) &nHashProofOfStake; + + for (int i = 0; i < 7; i++) + pnHashProofOfStake[i] = __builtin_bswap32(candidate[i]); + pnHashProofOfStake[7] = nHash7; + + CBigNum bnCoinDayWeight = bnValueIn * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / nOneDay; + CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay; + + if (bnTargetProofOfStake >= CBigNum(nHashProofOfStake)) + { + solution.first = nHashProofOfStake; + solution.second = nTimeTx; + + return true; + } + } +#endif +#ifdef USE_ASM + } +#endif + + return false; +} diff --git a/src/kernel_worker.h b/src/kernel_worker.h index 63217b9..7bea423 100644 --- a/src/kernel_worker.h +++ b/src/kernel_worker.h @@ -1,6 +1,10 @@ #ifndef BITCOIN_HERNELWORKER_H #define BITCOIN_HERNELWORKER_H +#include + +using namespace std; + class KernelWorker { public: @@ -8,7 +12,7 @@ public: { } KernelWorker(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, uint32_t nIntervalBegin, uint32_t nIntervalEnd); void Do(); - vector >& GetSolutions(); + vector >& GetSolutions(); private: #ifdef USE_ASM @@ -23,7 +27,7 @@ private: void Do_generic(); // Kernel solutions. - std::vector > solutions; + vector > solutions; // Kernel metadaya uint8_t *kernel; @@ -36,4 +40,7 @@ private: uint32_t nIntervalEnd; }; +// Scan given kernel for solutions +bool ScanKernelBackward(unsigned char *kernel, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, pair &SearchInterval, pair &solution); + #endif diff --git a/src/miner.cpp b/src/miner.cpp index f9bdf80..6057eec 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -7,6 +7,7 @@ #include "txdb.h" #include "miner.h" #include "kernel.h" +#include "kernel_worker.h" using namespace std; @@ -530,8 +531,8 @@ bool CheckStake(CBlock* pblock, CWallet& wallet) } // Precalculated SHA256 contexts and metadata -// (txid, vout.n) => (SHA256_CTX, (tx.nTime, nAmount)) -typedef std::map, std::pair > > MidstateMap; +// (txid, vout.n) => (kernel, (tx.nTime, nAmount)) +typedef std::map, std::pair, std::pair > > MidstateMap; // Fill the inputs map with precalculated contexts and metadata bool FillMap(CWallet *pwallet, uint32_t nUpperTime, MidstateMap &inputsMap) @@ -598,16 +599,9 @@ bool FillMap(CWallet *pwallet, uint32_t nUpperTime, MidstateMap &inputsMap) CDataStream ssKernel(SER_GETHASH, 0); ssKernel << nStakeModifier; ssKernel << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin->first->nTime << pcoin->second; - CDataStream::const_iterator itK = ssKernel.begin(); - // Init new sha256 context and update it - // with first 24 bytes of kernel - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, (unsigned char*)&itK[0], 8 + 16); - - // (txid, vout.n) => (SHA256_CTX, (tx.nTime, nAmount)) - inputsMap[key] = make_pair(ctx, make_pair(pcoin->first->nTime, pcoin->first->vout[pcoin->second].nValue)); + // (txid, vout.n) => (kernel, (tx.nTime, nAmount)) + inputsMap[key] = make_pair(std::vector(ssKernel.begin(), ssKernel.end()), make_pair(pcoin->first->nTime, pcoin->first->vout[pcoin->second].nValue)); } nStakeInputsMapSize = inputsMap.size(); @@ -633,13 +627,13 @@ bool ScanMap(const MidstateMap &inputsMap, uint32_t nBits, MidstateMap::key_type interval.first = nSearchTime; interval.second = nSearchTime - min(nSearchTime-nLastCoinStakeSearchTime, nMaxStakeSearchInterval); - // (txid, nout) => (SHA256_CTX, (tx.nTime, nAmount)) + // (txid, nout) => (kernel, (tx.nTime, nAmount)) for(MidstateMap::const_iterator input = inputsMap.begin(); input != inputsMap.end(); input++) { - SHA256_CTX ctx = input->second.first; + unsigned char *kernel = (unsigned char *) &input->second.first[0]; // scan(State, Bits, Time, Amount, ...) - if (ScanContextBackward(ctx, nBits, input->second.second.first, input->second.second.second, interval, solution)) + if (ScanKernelBackward(kernel, nBits, input->second.second.first, input->second.second.second, interval, solution)) { // Solution found LuckyInput = input->first; // (txid, nout) -- 1.7.1