From 776d0f34595fd616129d4816a337662ff39de7c6 Mon Sep 17 00:00:00 2001 From: s_nakamoto Date: Tue, 23 Nov 2010 19:16:36 +0000 Subject: [PATCH] new getwork git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@189 1a98c847-1fd6-4fd8-948a-caf3550aa51b --- coding.txt | 41 ++++ db.cpp | 4 +- db.h | 7 +- main.cpp | 524 ++++++++++++++++++++++++++++------------------------ main.h | 11 ++ rpc.cpp | 119 +++++++++++- serialize.h | 2 +- sha256.cpp | 6 +- ui.cpp | 4 +- util.cpp | 1 + 10 files changed, 467 insertions(+), 252 deletions(-) create mode 100644 coding.txt diff --git a/coding.txt b/coding.txt new file mode 100644 index 000000000..470747669 --- /dev/null +++ b/coding.txt @@ -0,0 +1,41 @@ +Please be consistent with the existing coding style. + +Block style: + +bool Function(char* psz, int n) +{ + // Comment summarising what this section of code does + for (int i = 0; i < n; i++) + { + // When something fails, return early + if (!Something()) + return false; + ... + } + + // Success return is usually at the end + return true; +} + +- ANSI/Allman block style +- 4 space indenting, no tabs +- No extra spaces inside parenthesis; please don't do ( this ) +- No space after function names, one space after if, for and while + +Variable names begin with the type in lowercase, like nSomeVariable. +Please don't put the first word of the variable name in lowercase like +someVariable. + +Common types: +n integer number: short, unsigned short, int, unsigned int, + int64, uint64, sometimes char if used as a number +d double, float +f flag +hash uint256 +p pointer or array, one p for each level of indirection +psz pointer to null terminated string +str string object +v vector or similar list objects +map map or multimap +set set or multiset +bn CBigNum diff --git a/db.cpp b/db.cpp index 28ae5583b..c768778c5 100644 --- a/db.cpp +++ b/db.cpp @@ -961,7 +961,7 @@ void CWalletDB::ReturnKey(int64 nIndex) printf("keypool return %"PRI64d"\n", nIndex); } -vector CWalletDB::GetKeyFromKeyPool() +vector GetKeyFromKeyPool() { CWalletDB walletdb; int64 nIndex = 0; @@ -971,7 +971,7 @@ vector CWalletDB::GetKeyFromKeyPool() return keypool.vchPubKey; } -int64 CWalletDB::GetOldestKeyPoolTime() +int64 GetOldestKeyPoolTime() { CWalletDB walletdb; int64 nIndex = 0; diff --git a/db.h b/db.h index df48699e9..0f705a863 100644 --- a/db.h +++ b/db.h @@ -26,6 +26,8 @@ extern DbEnv dbenv; extern void DBFlush(bool fShutdown); +extern vector GetKeyFromKeyPool(); +extern int64 GetOldestKeyPoolTime(); @@ -440,9 +442,8 @@ protected: void KeepKey(int64 nIndex); static void ReturnKey(int64 nIndex); friend class CReserveKey; -public: - vector GetKeyFromKeyPool(); - int64 GetOldestKeyPoolTime(); + friend vector GetKeyFromKeyPool(); + friend int64 GetOldestKeyPoolTime(); }; bool LoadWallet(bool& fFirstRunRet); diff --git a/main.cpp b/main.cpp index 1f5261d4e..acfcbc90f 100644 --- a/main.cpp +++ b/main.cpp @@ -159,7 +159,7 @@ bool AddToWallet(const CWalletTx& wtxIn) if (txout.scriptPubKey == scriptDefaultKey) { CWalletDB walletdb; - vchDefaultKey = walletdb.GetKeyFromKeyPool(); + vchDefaultKey = GetKeyFromKeyPool(); walletdb.WriteDefaultKey(vchDefaultKey); walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); } @@ -1557,31 +1557,25 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock) // Preliminary checks if (!pblock->CheckBlock()) - { - delete pblock; return error("ProcessBlock() : CheckBlock FAILED"); - } // If don't already have its previous block, shunt it off to holding area until we get it if (!mapBlockIndex.count(pblock->hashPrevBlock)) { printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); - mapOrphanBlocks.insert(make_pair(hash, pblock)); - mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); + CBlock* pblock2 = new CBlock(*pblock); + mapOrphanBlocks.insert(make_pair(hash, pblock2)); + mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2)); // Ask this guy to fill in what we're missing if (pfrom) - pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock)); + pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2)); return true; } // Store to disk if (!pblock->AcceptBlock()) - { - delete pblock; return error("ProcessBlock() : AcceptBlock FAILED"); - } - delete pblock; // Recursively process any orphan blocks that depended on this one vector vWorkQueue; @@ -2504,7 +2498,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) CInv inv(MSG_BLOCK, pblock->GetHash()); pfrom->AddInventoryKnown(inv); - if (ProcessBlock(pfrom, pblock.release())) + if (ProcessBlock(pfrom, pblock.get())) mapAlreadyAskedFor.erase(inv); } @@ -2549,7 +2543,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) // Keep giving the same key to the same ip until they use it if (!mapReuseKey.count(pfrom->addr.ip)) - mapReuseKey[pfrom->addr.ip] = CWalletDB().GetKeyFromKeyPool(); + mapReuseKey[pfrom->addr.ip] = GetKeyFromKeyPool(); // Send back approval of order and pubkey to use CScript scriptPubKey; @@ -3000,19 +2994,19 @@ inline void SHA256Transform(void* pstate, void* pinput, const void* pinit) // 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, +// between calls, but periodically or if nNonce is 0xffff0000 or above, // 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 ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) { - unsigned int& nNonce = *(unsigned int*)(pblock + 12); + unsigned int& nNonce = *(unsigned int*)(pdata + 12); for (;;) { // Crypto++ SHA-256 - // Hash pblock using pmidstate as the starting state into + // Hash pdata using pmidstate as the starting state into // preformatted buffer phash1, then hash phash1 into phash nNonce++; - SHA256Transform(phash1, pblock, pmidstate); + SHA256Transform(phash1, pdata, pmidstate); SHA256Transform(phash, phash1, pSHA256InitState); // Return the nonce if the hash has at least some zero bits, @@ -3055,6 +3049,262 @@ public: }; +CBlock* CreateNewBlock(CReserveKey& reservekey) +{ + CBlockIndex* pindexPrev = pindexBest; + + // Create new block + auto_ptr pblock(new CBlock()); + if (!pblock.get()) + return NULL; + + // Create coinbase tx + CTransaction txNew; + txNew.vin.resize(1); + txNew.vin[0].prevout.SetNull(); + txNew.vout.resize(1); + txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; + + // Add our coinbase tx as first transaction + pblock->vtx.push_back(txNew); + + // Collect memory pool transactions into the block + int64 nFees = 0; + CRITICAL_BLOCK(cs_main) + CRITICAL_BLOCK(cs_mapTransactions) + { + CTxDB txdb("r"); + + // Priority order to process transactions + list vOrphan; // list memory doesn't move + map > mapDependers; + multimap mapPriority; + for (map::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi) + { + CTransaction& tx = (*mi).second; + if (tx.IsCoinBase() || !tx.IsFinal()) + continue; + + COrphan* porphan = NULL; + double dPriority = 0; + foreach(const CTxIn& txin, tx.vin) + { + // Read prev transaction + CTransaction txPrev; + CTxIndex txindex; + if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + { + // Has to wait for dependencies + if (!porphan) + { + // Use list for automatic deletion + vOrphan.push_back(COrphan(&tx)); + porphan = &vOrphan.back(); + } + mapDependers[txin.prevout.hash].push_back(porphan); + porphan->setDependsOn.insert(txin.prevout.hash); + continue; + } + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + + // Read block header + int nConf = 0; + CBlock block; + if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + { + map::iterator it = mapBlockIndex.find(block.GetHash()); + if (it != mapBlockIndex.end()) + { + CBlockIndex* pindex = (*it).second; + if (pindex->IsInMainChain()) + nConf = 1 + nBestHeight - pindex->nHeight; + } + } + + dPriority += (double)nValueIn * nConf; + + if (fDebug && mapArgs.count("-printpriority")) + printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); + } + + // Priority is sum(valuein * age) / txsize + dPriority /= ::GetSerializeSize(tx, SER_NETWORK); + + if (porphan) + porphan->dPriority = dPriority; + else + mapPriority.insert(make_pair(-dPriority, &(*mi).second)); + + if (fDebug && mapArgs.count("-printpriority")) + { + printf("priority %-20.1f %s\n%s", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str()); + if (porphan) + porphan->print(); + printf("\n"); + } + } + + // Collect transactions into block + map mapTestPool; + uint64 nBlockSize = 1000; + int nBlockSigOps = 100; + while (!mapPriority.empty()) + { + // Take highest priority transaction off priority queue + double dPriority = -(*mapPriority.begin()).first; + CTransaction& tx = *(*mapPriority.begin()).second; + mapPriority.erase(mapPriority.begin()); + + // Size limits + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK); + if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) + continue; + int nTxSigOps = tx.GetSigOpCount(); + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + continue; + + // Transaction fee required depends on block size + bool fAllowFree = (nBlockSize + nTxSize < 4000 || dPriority > COIN * 144 / 250); + int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree); + + // Connecting shouldn't fail due to dependency on other memory pool transactions + // because we're already processing them in order of dependency + map mapTestPoolTmp(mapTestPool); + if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee)) + continue; + swap(mapTestPool, mapTestPoolTmp); + + // Added + pblock->vtx.push_back(tx); + nBlockSize += nTxSize; + nBlockSigOps += nTxSigOps; + + // Add transactions that depend on this one to the priority queue + uint256 hash = tx.GetHash(); + if (mapDependers.count(hash)) + { + foreach(COrphan* porphan, mapDependers[hash]) + { + if (!porphan->setDependsOn.empty()) + { + porphan->setDependsOn.erase(hash); + if (porphan->setDependsOn.empty()) + mapPriority.insert(make_pair(-porphan->dPriority, porphan->ptx)); + } + } + } + } + } + pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); + + // Fill in header + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nBits = GetNextWorkRequired(pindexPrev); + pblock->nNonce = 0; + + return pblock.release(); +} + + +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime) +{ + // Update nExtraNonce + int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + if (++nExtraNonce >= 0x7f && nNow > nPrevTime+1) + { + nExtraNonce = 1; + nPrevTime = nNow; + } + pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); +} + + +void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1) +{ + // + // Prebuild 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 (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); +} + + +bool CheckWork(CBlock* pblock, CReserveKey& reservekey) +{ + uint256 hash = pblock->GetHash(); + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + if (hash > hashTarget) + return false; + + //// debug print + printf("BitcoinMiner:\n"); + printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); + pblock->print(); + printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); + printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); + + // Found a solution + CRITICAL_BLOCK(cs_main) + { + if (pblock->hashPrevBlock != hashBestChain) + return error("BitcoinMiner : generated block is stale"); + + // Remove key from key pool + reservekey.KeepKey(); + + // Track how many getdata requests this block gets + CRITICAL_BLOCK(cs_mapRequestCount) + mapRequestCount[pblock->GetHash()] = 0; + + // Process this block the same as if we had received it from another node + if (!ProcessBlock(NULL, pblock)) + return error("BitcoinMiner : ProcessBlock, block not accepted"); + } + + Sleep(2000); + return true; +} + void BitcoinMiner() { @@ -3064,9 +3314,11 @@ void BitcoinMiner() if (mapArgs.count("-4way")) f4WaySSE2 = (mapArgs["-4way"] != "0"); + // Each thread has its own key and counter CReserveKey reservekey; unsigned int nExtraNonce = 0; int64 nPrevTime = 0; + while (fGenerateBitcoins) { if (AffinityBugWorkaround(ThreadBitcoinMiner)) @@ -3082,210 +3334,32 @@ void BitcoinMiner() return; } - unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; - CBlockIndex* pindexPrev = pindexBest; - unsigned int nBits = GetNextWorkRequired(pindexPrev); - - - // - // Create coinbase tx - // - CTransaction txNew; - txNew.vin.resize(1); - txNew.vin[0].prevout.SetNull(); - int64 nNow = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - if (++nExtraNonce >= 0x7f && nNow > nPrevTime+1) - { - nExtraNonce = 1; - nPrevTime = nNow; - } - txNew.vin[0].scriptSig << nBits << CBigNum(nExtraNonce); - txNew.vout.resize(1); - txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG; - // // Create new block // - auto_ptr pblock(new CBlock()); + unsigned int nTransactionsUpdatedLast = nTransactionsUpdated; + CBlockIndex* pindexPrev = pindexBest; + + auto_ptr pblock(CreateNewBlock(reservekey)); if (!pblock.get()) return; + IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce, nPrevTime); - // Add our coinbase tx as first transaction - pblock->vtx.push_back(txNew); - - // Collect memory pool transactions into the block - int64 nFees = 0; - CRITICAL_BLOCK(cs_main) - CRITICAL_BLOCK(cs_mapTransactions) - { - CTxDB txdb("r"); - - // Priority order to process transactions - list vOrphan; // list memory doesn't move - map > mapDependers; - multimap mapPriority; - for (map::iterator mi = mapTransactions.begin(); mi != mapTransactions.end(); ++mi) - { - CTransaction& tx = (*mi).second; - if (tx.IsCoinBase() || !tx.IsFinal()) - continue; - - COrphan* porphan = NULL; - double dPriority = 0; - foreach(const CTxIn& txin, tx.vin) - { - // Read prev transaction - CTransaction txPrev; - CTxIndex txindex; - if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) - { - // Has to wait for dependencies - if (!porphan) - { - // Use list for automatic deletion - vOrphan.push_back(COrphan(&tx)); - porphan = &vOrphan.back(); - } - mapDependers[txin.prevout.hash].push_back(porphan); - porphan->setDependsOn.insert(txin.prevout.hash); - continue; - } - int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; - - // Read block header - int nConf = 0; - CBlock block; - if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) - { - map::iterator it = mapBlockIndex.find(block.GetHash()); - if (it != mapBlockIndex.end()) - { - CBlockIndex* pindex = (*it).second; - if (pindex->IsInMainChain()) - nConf = 1 + nBestHeight - pindex->nHeight; - } - } - - dPriority += (double)nValueIn * nConf; - - if (fDebug && mapArgs.count("-printpriority")) - printf("priority nValueIn=%-12I64d nConf=%-5d dPriority=%-20.1f\n", nValueIn, nConf, dPriority); - } - - // Priority is sum(valuein * age) / txsize - dPriority /= ::GetSerializeSize(tx, SER_NETWORK); - - if (porphan) - porphan->dPriority = dPriority; - else - mapPriority.insert(make_pair(-dPriority, &(*mi).second)); - - if (fDebug && mapArgs.count("-printpriority")) - { - printf("priority %-20.1f %s\n%s", dPriority, tx.GetHash().ToString().substr(0,10).c_str(), tx.ToString().c_str()); - if (porphan) - porphan->print(); - printf("\n"); - } - } - - // Collect transactions into block - map mapTestPool; - uint64 nBlockSize = 1000; - int nBlockSigOps = 100; - while (!mapPriority.empty()) - { - // Take highest priority transaction off priority queue - double dPriority = -(*mapPriority.begin()).first; - CTransaction& tx = *(*mapPriority.begin()).second; - mapPriority.erase(mapPriority.begin()); - - // Size limits - unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK); - if (nBlockSize + nTxSize >= MAX_BLOCK_SIZE_GEN) - continue; - int nTxSigOps = tx.GetSigOpCount(); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) - continue; - - // Transaction fee required depends on block size - bool fAllowFree = (nBlockSize + nTxSize < 4000 || dPriority > COIN * 144 / 250); - int64 nMinFee = tx.GetMinFee(nBlockSize, fAllowFree); - - // Connecting shouldn't fail due to dependency on other memory pool transactions - // because we're already processing them in order of dependency - map mapTestPoolTmp(mapTestPool); - if (!tx.ConnectInputs(txdb, mapTestPoolTmp, CDiskTxPos(1,1,1), pindexPrev, nFees, false, true, nMinFee)) - continue; - swap(mapTestPool, mapTestPoolTmp); - - // Added - pblock->vtx.push_back(tx); - nBlockSize += nTxSize; - nBlockSigOps += nTxSigOps; - - // Add transactions that depend on this one to the priority queue - uint256 hash = tx.GetHash(); - if (mapDependers.count(hash)) - { - foreach(COrphan* porphan, mapDependers[hash]) - { - if (!porphan->setDependsOn.empty()) - { - porphan->setDependsOn.erase(hash); - if (porphan->setDependsOn.empty()) - mapPriority.insert(make_pair(-porphan->dPriority, porphan->ptx)); - } - } - } - } - } - pblock->nBits = nBits; - pblock->vtx[0].vout[0].nValue = GetBlockValue(pindexPrev->nHeight+1, nFees); printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size()); // - // Prebuild hash buffer + // Prebuild hash buffers // - struct tmpworkspace - { - 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]; - }; - char tmpbuf[sizeof(tmpworkspace)+16]; - tmpworkspace& tmp = *(tmpworkspace*)alignup<16>(tmpbuf); + 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); - tmp.block.nVersion = pblock->nVersion; - tmp.block.hashPrevBlock = pblock->hashPrevBlock = pindexPrev->GetBlockHash(); - tmp.block.hashMerkleRoot = pblock->hashMerkleRoot = pblock->BuildMerkleTree(); - tmp.block.nTime = pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - tmp.block.nBits = pblock->nBits = nBits; - tmp.block.nNonce = pblock->nNonce = 0; + FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); - unsigned int nBlocks0 = FormatHashBlocks(&tmp.block, sizeof(tmp.block)); - unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); - - // Byte swap all the input buffer - for (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 - uint256 midstatebuf[2]; - uint256& midstate = *alignup<16>(midstatebuf); - SHA256Transform(&midstate, &tmp.block, pSHA256InitState); + unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); + unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); // @@ -3303,11 +3377,11 @@ void BitcoinMiner() #ifdef FOURWAYSSE2 if (f4WaySSE2) // tcatm's 4-way 128-bit SSE2 SHA-256 - nNonceFound = ScanHash_4WaySSE2((char*)&midstate, (char*)&tmp.block + 64, (char*)&tmp.hash1, (char*)&hash, nHashesDone); + nNonceFound = ScanHash_4WaySSE2(pmidstate, pdata + 64, phash1, (char*)&hash, nHashesDone); else #endif // Crypto++ SHA-256 - nNonceFound = ScanHash_CryptoPP((char*)&midstate, (char*)&tmp.block + 64, (char*)&tmp.hash1, (char*)&hash, nHashesDone); + nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1, (char*)&hash, nHashesDone); // Check if something found if (nNonceFound != -1) @@ -3321,33 +3395,9 @@ void BitcoinMiner() pblock->nNonce = ByteReverse(nNonceFound); assert(hash == pblock->GetHash()); - //// debug print - printf("BitcoinMiner:\n"); - printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str()); - pblock->print(); - printf("%s ", DateTimeStrFormat("%x %H:%M", GetTime()).c_str()); - printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str()); - SetThreadPriority(THREAD_PRIORITY_NORMAL); - CRITICAL_BLOCK(cs_main) - { - if (pindexPrev == pindexBest) - { - // Remove key from key pool - reservekey.KeepKey(); - - // Track how many getdata requests this block gets - CRITICAL_BLOCK(cs_mapRequestCount) - mapRequestCount[pblock->GetHash()] = 0; - - // Process this block the same as if we had received it from another node - if (!ProcessBlock(NULL, pblock.release())) - printf("ERROR in BitcoinMiner, ProcessBlock, block not accepted\n"); - } - } + CheckWork(pblock.get(), reservekey); SetThreadPriority(THREAD_PRIORITY_LOWEST); - - Sleep(500); break; } } @@ -3393,7 +3443,7 @@ void BitcoinMiner() return; if (vNodes.empty()) break; - if (tmp.block.nNonce >= 0xff000000) + if (nBlockNonce >= 0xffff0000) break; if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) break; @@ -3402,7 +3452,7 @@ void BitcoinMiner() // Update nTime every few seconds pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - tmp.block.nTime = ByteReverse(pblock->nTime); + nBlockTime = ByteReverse(pblock->nTime); } } } diff --git a/main.h b/main.h index dda5f730c..e5000d757 100644 --- a/main.h +++ b/main.h @@ -83,6 +83,10 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); void GenerateBitcoins(bool fGenerate); void ThreadBitcoinMiner(void* parg); +CBlock* CreateNewBlock(CReserveKey& reservekey); +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime); +void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); +bool CheckWork(CBlock* pblock, CReserveKey& reservekey); void BitcoinMiner(); bool CheckProofOfWork(uint256 hash, unsigned int nBits); bool IsInitialBlockDownload(); @@ -753,21 +757,28 @@ public: void Init() { + vtxPrev.clear(); + mapValue.clear(); + vOrderForm.clear(); nTimeReceived = 0; fFromMe = false; fSpent = false; fTimeReceivedIsTxTime = false; fUnused = false; + strFromAccount.clear(); fDebitCached = false; fCreditCached = false; nDebitCached = 0; nCreditCached = 0; nTimeDisplayed = 0; nLinesDisplayed = 0; + fConfirmedDisplayed = false; } IMPLEMENT_SERIALIZE ( + if (fRead) + const_cast(this)->Init(); nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action); READWRITE(vtxPrev); READWRITE(mapValue); diff --git a/rpc.cpp b/rpc.cpp index 271d36c2f..113de85a9 100644 --- a/rpc.cpp +++ b/rpc.cpp @@ -3,6 +3,7 @@ // file license.txt or http://www.opensource.org/licenses/mit-license.php. #include "headers.h" +#include "cryptopp/sha.h" #undef printf #include #include @@ -50,6 +51,7 @@ void PrintConsole(const char* format, ...) ret = limit - 1; buffer[limit-1] = 0; } + printf("%s", buffer); #if defined(__WXMSW__) && defined(GUI) MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); #else @@ -263,7 +265,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("testnet", fTestNet)); - obj.push_back(Pair("keypoololdest", (boost::int64_t)CWalletDB().GetOldestKeyPoolTime())); + obj.push_back(Pair("keypoololdest", (boost::int64_t)GetOldestKeyPoolTime())); obj.push_back(Pair("paytxfee", (double)nTransactionFee / (double)COIN)); obj.push_back(Pair("errors", GetWarnings("statusbar"))); return obj; @@ -285,7 +287,7 @@ Value getnewaddress(const Array& params, bool fHelp) strAccount = params[0].get_str(); // Generate a new key that is added to wallet - string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); + string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); SetAddressBookName(strAddress, strAccount); return strAddress; @@ -329,7 +331,7 @@ Value getaccountaddress(const Array& params, bool fHelp) // Generate a new key if (account.vchPubKey.empty()) { - account.vchPubKey = CWalletDB().GetKeyFromKeyPool(); + account.vchPubKey = GetKeyFromKeyPool(); string strAddress = PubKeyToAddress(account.vchPubKey); SetAddressBookName(strAddress, strAccount); walletdb.WriteAccount(strAccount, account); @@ -925,6 +927,112 @@ Value validateaddress(const Array& params, bool fHelp) } +Value getwork(const Array& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getwork [data]\n" + "If [data] is not specified, returns formatted hash data to work on:\n" + " \"midstate\" : precomputed hash state after hashing the first half of the data\n" + " \"data\" : block data\n" + " \"hash1\" : formatted hash buffer for second hash\n" + " \"target\" : little endian hash target\n" + "If [data] is specified, tries to solve the block and returns true if it was successful."); + + if (vNodes.empty()) + throw JSONRPCError(-9, "Bitcoin is not connected!"); + + if (IsInitialBlockDownload()) + throw JSONRPCError(-10, "Bitcoin is downloading blocks..."); + + static map > mapNewBlock; + static vector vNewBlock; + static CReserveKey reservekey; + + if (params.size() == 0) + { + // Update block + static unsigned int nTransactionsUpdatedLast; + static CBlockIndex* pindexPrev; + static int64 nStart; + static CBlock* pblock; + if (pindexPrev != pindexBest || + (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)) + { + if (pindexPrev != pindexBest) + { + // Deallocate old blocks since they're obsolete now + mapNewBlock.clear(); + foreach(CBlock* pblock, vNewBlock) + delete pblock; + vNewBlock.clear(); + } + nTransactionsUpdatedLast = nTransactionsUpdated; + pindexPrev = pindexBest; + nStart = GetTime(); + + // Create new block + pblock = CreateNewBlock(reservekey); + if (!pblock) + throw JSONRPCError(-7, "Out of memory"); + vNewBlock.push_back(pblock); + } + + // Update nTime + pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nNonce = 0; + + // Update nExtraNonce + static unsigned int nExtraNonce = 0; + static int64 nPrevTime = 0; + IncrementExtraNonce(pblock, pindexPrev, nExtraNonce, nPrevTime); + + // Save + mapNewBlock[pblock->hashMerkleRoot] = make_pair(pblock, nExtraNonce); + + // Prebuild hash buffers + char pmidstate[32]; + char pdata[128]; + char phash1[64]; + FormatHashBuffers(pblock, pmidstate, pdata, phash1); + + uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); + + Object result; + result.push_back(Pair("midstate", HexStr(BEGIN(pmidstate), END(pmidstate)))); + result.push_back(Pair("data", HexStr(BEGIN(pdata), END(pdata)))); + result.push_back(Pair("hash1", HexStr(BEGIN(phash1), END(phash1)))); + result.push_back(Pair("target", HexStr(BEGIN(hashTarget), END(hashTarget)))); + return result; + } + else + { + // Parse parameters + vector vchData = ParseHex(params[0].get_str()); + if (vchData.size() != 128) + throw JSONRPCError(-8, "Invalid parameter"); + CBlock* pdata = (CBlock*)&vchData[0]; + + // Byte reverse + for (int i = 0; i < 128/4; i++) + ((unsigned int*)pdata)[i] = CryptoPP::ByteReverse(((unsigned int*)pdata)[i]); + + // Get saved block + if (!mapNewBlock.count(pdata->hashMerkleRoot)) + return false; + CBlock* pblock = mapNewBlock[pdata->hashMerkleRoot].first; + unsigned int nExtraNonce = mapNewBlock[pdata->hashMerkleRoot].second; + + pblock->nTime = pdata->nTime; + pblock->nNonce = pdata->nNonce; + pblock->vtx[0].vin[0].scriptSig = CScript() << pblock->nBits << CBigNum(nExtraNonce); + pblock->hashMerkleRoot = pblock->BuildMerkleTree(); + + return CheckWork(pblock, reservekey); + } +} + + @@ -972,6 +1080,7 @@ pair pCallTable[] = make_pair("getbalance", &getbalance), make_pair("move", &movecmd), make_pair("sendfrom", &sendfrom), + make_pair("getwork", &getwork), }; map mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); @@ -996,6 +1105,7 @@ string pAllowInSafeMode[] = "getaddressesbylabel", // deprecated "backupwallet", "validateaddress", + "getwork", }; set setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0])); @@ -1418,7 +1528,8 @@ void ThreadRPCServer2(void* parg) if (valMethod.type() != str_type) throw JSONRPCError(-32600, "Method must be a string"); string strMethod = valMethod.get_str(); - printf("ThreadRPCServer method=%s\n", strMethod.c_str()); + if (strMethod != "getwork") + printf("ThreadRPCServer method=%s\n", strMethod.c_str()); // Parse params Value valParams = find_value(request, "params"); diff --git a/serialize.h b/serialize.h index dde2aeb9a..a289769f2 100644 --- a/serialize.h +++ b/serialize.h @@ -22,7 +22,7 @@ class CDataStream; class CAutoFile; static const unsigned int MAX_SIZE = 0x02000000; -static const int VERSION = 31600; +static const int VERSION = 31601; static const char* pszSubVer = ""; diff --git a/sha256.cpp b/sha256.cpp index 56a89260c..530c2c7c1 100644 --- a/sha256.cpp +++ b/sha256.cpp @@ -110,15 +110,15 @@ 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 ScanHash_4WaySSE2(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone) { - unsigned int& nNonce = *(unsigned int*)(pblock + 12); + unsigned int& nNonce = *(unsigned int*)(pdata + 12); for (;;) { nNonce += NPAR; unsigned int thashbuf[9][NPAR]; unsigned int (&thash)[9][NPAR] = *alignup<16>(&thashbuf); - DoubleBlockSHA256(pblock, phash1, pmidstate, thash, pSHA256InitState); + DoubleBlockSHA256(pdata, phash1, pmidstate, thash, pSHA256InitState); for (int j = 0; j < NPAR; j++) { diff --git a/ui.cpp b/ui.cpp index b4eec0a55..aafd4a7a8 100644 --- a/ui.cpp +++ b/ui.cpp @@ -1171,7 +1171,7 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event) string strName = dialog.GetValue(); // Generate new key - string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); + string strAddress = PubKeyToAddress(GetKeyFromKeyPool()); // Save SetAddressBookName(strAddress, strName); @@ -2575,7 +2575,7 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event) strName = dialog.GetValue(); // Generate new key - strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); + strAddress = PubKeyToAddress(GetKeyFromKeyPool()); } // Add to list and select it diff --git a/util.cpp b/util.cpp index 7576beaba..607dc3f11 100644 --- a/util.cpp +++ b/util.cpp @@ -175,6 +175,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...) va_start(arg_ptr, pszFormat); ret = vfprintf(fileout, pszFormat, arg_ptr); va_end(arg_ptr); + fflush(fileout); } }