From 2bc0f8cca250b65426f9fecf44d176dc1698f399 Mon Sep 17 00:00:00 2001 From: MASM fan Date: Tue, 7 Apr 2015 14:30:15 -0700 Subject: [PATCH] Replace kernel scanning function with more usable implementation. * Move midstate calculation to separate function; * Don't operate with transaction index and other low level data inside the scanning function. TODO: * Automatic kernel midstate precalculation for all unspent inputs; * Multi-threaded scanning. --- src/kernel.cpp | 67 +++++++++++++++++----------------------------------- src/kernel.h | 6 ++++- src/rpcmining.cpp | 35 +++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 47 deletions(-) diff --git a/src/kernel.cpp b/src/kernel.cpp index a3ec598..12b26aa 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -509,35 +509,24 @@ bool ScanForStakeKernelHash(MetaMap &mapMeta, uint32_t nBits, uint32_t nTime, ui return false; } -// Scan given input for kernel solution -bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits, uint32_t nSearchInterval, std::pair &solution) +// Precompute hashing state for static part of kernel +void GetKernelMidstate(uint64_t nStakeModifier, uint32_t nBlockTime, uint32_t nTxOffset, uint32_t nInputTxTime, uint32_t nOut, SHA256_CTX &ctx) { - CTxDB txdb("r"); - - CBlock block; - CTxIndex txindex; - - // Load transaction index item - if (!txdb.ReadTxIndex(tx.GetHash(), txindex)) - return false; - - // Read block header - if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - return false; - - uint64_t nStakeModifier = 0; - if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) - return false; - - uint32_t nTime = GetTime(); - // Only count coins meeting min age requirement - if (nStakeMinAge + block.nTime > nTime) - nTime += (nStakeMinAge + block.nTime - nTime); + // Build static part of kernel + CDataStream ssKernel(SER_GETHASH, 0); + ssKernel << nStakeModifier; + ssKernel << nBlockTime << nTxOffset << nInputTxTime << nOut; + CDataStream::const_iterator it = ssKernel.begin(); - // Transaction offset inside block - uint32_t nTxOffset = txindex.pos.nTxPos - txindex.pos.nBlockPos; - int64_t nValueIn = tx.vout[nOut].nValue; + // Init sha256 context and update it + // with first 24 bytes of kernel + SHA256_Init(&ctx); + SHA256_Update(&ctx, (unsigned char*)&it[0], 8 + 16); +} +// Scan given midstate for solution +bool ScanMidstateForward(SHA256_CTX &ctx, uint32_t nBits, uint32_t nInputTxTime, int64_t nValueIn, std::pair &SearchInterval, std::pair &solution) +{ CBigNum bnTargetPerCoinDay; bnTargetPerCoinDay.SetCompact(nBits); @@ -545,31 +534,19 @@ bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits CBigNum bnMaxTargetPerCoinDay = bnTargetPerCoinDay * CBigNum(nValueIn) * nStakeMaxAge / COIN / (24 * 60 * 60); uint256 maxTarget = bnMaxTargetPerCoinDay.getuint256(); - - // Build static part of kernel - CDataStream ssKernel(SER_GETHASH, 0); - ssKernel << nStakeModifier; - ssKernel << block.nTime << nTxOffset << tx.nTime << nOut; - CDataStream::const_iterator it = ssKernel.begin(); - - // Init sha256 context and update it - // with first 16 bytes of kernel - SHA256_CTX ctxCurrent; - SHA256_Init(&ctxCurrent); - SHA256_Update(&ctxCurrent, (unsigned char*)&it[0], 8 + 16); - SHA256_CTX ctxCopy = ctxCurrent; + SHA256_CTX ctxCopy = ctx; // Search forward in time from the given timestamp // Stopping search in case of shutting down - for (uint32_t nTimeTx=nTime; nTimeTx maxTarget) continue; - CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)tx.nTime, (int64_t)nTimeTx) / COIN / (24 * 60 * 60); + CBigNum bnCoinDayWeight = CBigNum(nValueIn) * GetWeight((int64_t)nInputTxTime, (int64_t)nTimeTx) / COIN / (24 * 60 * 60); CBigNum bnTargetProofOfStake = bnCoinDayWeight * bnTargetPerCoinDay; if (bnTargetProofOfStake >= CBigNum(hashProofOfStake)) diff --git a/src/kernel.h b/src/kernel.h index 9772782..a94ace2 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -36,7 +36,11 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, uint32_t // Scan given coins set for kernel solution bool ScanForStakeKernelHash(MetaMap &mapMeta, uint32_t nBits, uint32_t nTime, uint32_t nSearchInterval, CoinsSet::value_type &kernelcoin, uint32_t &nTimeTx, uint32_t &nBlockTime, uint64_t &nKernelsTried, uint64_t &nCoinDaysTried); -bool ScanInputForStakeKernelHash(CTransaction &tx, uint32_t nOut, uint32_t nBits, uint32_t nSearchInterval, std::pair &solution); +// Precompute hashing state for static part of kernel +void GetKernelMidstate(uint64_t nStakeModifier, uint32_t nBlockTime, uint32_t nTxOffset, uint32_t nInputTxTime, uint32_t nOut, SHA256_CTX &ctx); + +// Scan given midstate for kernel solutions +bool ScanMidstateForward(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 diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 8f02836..28d6ed8 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -106,8 +106,41 @@ Value scaninput(const Array& params, bool fHelp) uint256 hashBlock = 0; if (GetTransaction(hash, tx, hashBlock)) { + if (nOut > tx.vout.size()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Incorrect output number"); + + if (hashBlock == 0) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to find transaction in the blockchain"); + + CTxDB txdb("r"); + + CBlock block; + CTxIndex txindex; + + // Load transaction index item + if (!txdb.ReadTxIndex(tx.GetHash(), txindex)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Unable to read block index item"); + + // Read block header + if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "CBlock::ReadFromDisk() failed"); + + uint64_t nStakeModifier = 0; + if (!GetKernelStakeModifier(block.GetHash(), nStakeModifier)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No kernel stake modifier generated yet"); + + std::pair interval; + interval.first = GetTime(); + // Only count coins meeting min age requirement + if (nStakeMinAge + block.nTime > interval.first) + interval.first += (nStakeMinAge + block.nTime - interval.first); + interval.second = interval.first + nDays * 86400; + + SHA256_CTX ctx; + GetKernelMidstate(nStakeModifier, block.nTime, txindex.pos.nTxPos - txindex.pos.nBlockPos, tx.nTime, nOut, ctx); + std::pair solution; - if (ScanInputForStakeKernelHash(tx, nOut, nBits, nDays * 86400, solution)) + if (ScanMidstateForward(ctx, nBits, tx.nTime, tx.vout[nOut].nValue, interval, solution)) { Object r; r.push_back(Pair("hash", solution.first.GetHex())); -- 1.7.1