changeset 308:94c9b179df77 draft

new getwork git-svn-id: https://bitcoin.svn.sourceforge.net/svnroot/bitcoin/trunk@189 1a98c847-1fd6-4fd8-948a-caf3550aa51b
author s_nakamoto <s_nakamoto@1a98c847-1fd6-4fd8-948a-caf3550aa51b>
date Tue, 23 Nov 2010 19:16:36 +0000
parents 2d54f207a8b9
children 154be46537f5 0eeea91db5a1 0af264877a33
files coding.txt db.cpp db.h main.cpp main.h rpc.cpp serialize.h sha256.cpp ui.cpp util.cpp
diffstat 10 files changed, 470 insertions(+), 255 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /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
--- a/db.cpp
+++ b/db.cpp
@@ -961,7 +961,7 @@
     printf("keypool return %"PRI64d"\n", nIndex);
 }
 
-vector<unsigned char> CWalletDB::GetKeyFromKeyPool()
+vector<unsigned char> GetKeyFromKeyPool()
 {
     CWalletDB walletdb;
     int64 nIndex = 0;
@@ -971,7 +971,7 @@
     return keypool.vchPubKey;
 }
 
-int64 CWalletDB::GetOldestKeyPoolTime()
+int64 GetOldestKeyPoolTime()
 {
     CWalletDB walletdb;
     int64 nIndex = 0;
--- a/db.h
+++ b/db.h
@@ -26,6 +26,8 @@
 
 
 extern void DBFlush(bool fShutdown);
+extern vector<unsigned char> GetKeyFromKeyPool();
+extern int64 GetOldestKeyPoolTime();
 
 
 
@@ -440,9 +442,8 @@
     void KeepKey(int64 nIndex);
     static void ReturnKey(int64 nIndex);
     friend class CReserveKey;
-public:
-    vector<unsigned char> GetKeyFromKeyPool();
-    int64 GetOldestKeyPoolTime();
+    friend vector<unsigned char> GetKeyFromKeyPool();
+    friend int64 GetOldestKeyPoolTime();
 };
 
 bool LoadWallet(bool& fFirstRunRet);
--- a/main.cpp
+++ b/main.cpp
@@ -159,7 +159,7 @@
             if (txout.scriptPubKey == scriptDefaultKey)
             {
                 CWalletDB walletdb;
-                vchDefaultKey = walletdb.GetKeyFromKeyPool();
+                vchDefaultKey = GetKeyFromKeyPool();
                 walletdb.WriteDefaultKey(vchDefaultKey);
                 walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
             }
@@ -1557,31 +1557,25 @@
 
     // 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<uint256> vWorkQueue;
@@ -2504,7 +2498,7 @@
         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 @@
 
         // 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 @@
 // 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 @@
 };
 
 
+CBlock* CreateNewBlock(CReserveKey& reservekey)
+{
+    CBlockIndex* pindexPrev = pindexBest;
+
+    // Create new block
+    auto_ptr<CBlock> 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<COrphan> vOrphan; // list memory doesn't move
+        map<uint256, vector<COrphan*> > mapDependers;
+        multimap<double, CTransaction*> mapPriority;
+        for (map<uint256, CTransaction>::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<uint256, CBlockIndex*>::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<uint256, CTxIndex> 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<uint256, CTxIndex> 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 @@
     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 @@
                 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<CBlock> pblock(new CBlock());
+        unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
+        CBlockIndex* pindexPrev = pindexBest;
+
+        auto_ptr<CBlock> pblock(CreateNewBlock(reservekey));
         if (!pblock.get())
             return;
-
-        // 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<COrphan> vOrphan; // list memory doesn't move
-            map<uint256, vector<COrphan*> > mapDependers;
-            multimap<double, CTransaction*> mapPriority;
-            for (map<uint256, CTransaction>::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<uint256, CBlockIndex*>::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<uint256, CTxIndex> 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<uint256, CTxIndex> 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);
+        IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce, nPrevTime);
+
         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);
-
-        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;
-
-        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);
+        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.get(), pmidstate, pdata, phash1);
+
+        unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
+        unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
 
 
         //
@@ -3303,11 +3377,11 @@
 #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 @@
                     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 @@
                 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 @@
 
             // Update nTime every few seconds
             pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
-            tmp.block.nTime = ByteReverse(pblock->nTime);
+            nBlockTime = ByteReverse(pblock->nTime);
         }
     }
 }
--- a/main.h
+++ b/main.h
@@ -83,6 +83,10 @@
 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 @@
 
     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<CWalletTx*>(this)->Init();
         nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
         READWRITE(vtxPrev);
         READWRITE(mapValue);
--- 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 <boost/asio.hpp>
 #include <boost/iostreams/concepts.hpp>
@@ -50,6 +51,7 @@
         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 @@
     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 @@
         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 @@
         // 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 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<uint256, pair<CBlock*, unsigned int> > mapNewBlock;
+    static vector<CBlock*> 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<unsigned char> 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 @@
     make_pair("getbalance",            &getbalance),
     make_pair("move",                  &movecmd),
     make_pair("sendfrom",              &sendfrom),
+    make_pair("getwork",               &getwork),
 };
 map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
 
@@ -996,6 +1105,7 @@
     "getaddressesbylabel", // deprecated
     "backupwallet",
     "validateaddress",
+    "getwork",
 };
 set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
 
@@ -1418,7 +1528,8 @@
             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");
--- a/serialize.h
+++ b/serialize.h
@@ -22,7 +22,7 @@
 class CAutoFile;
 static const unsigned int MAX_SIZE = 0x02000000;
 
-static const int VERSION = 31600;
+static const int VERSION = 31601;
 static const char* pszSubVer = "";
 
 
--- a/sha256.cpp
+++ b/sha256.cpp
@@ -110,15 +110,15 @@
 {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++)
         {
--- a/ui.cpp
+++ b/ui.cpp
@@ -1171,7 +1171,7 @@
     string strName = dialog.GetValue();
 
     // Generate new key
-    string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
+    string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
 
     // Save
     SetAddressBookName(strAddress, strName);
@@ -2575,7 +2575,7 @@
         strName = dialog.GetValue();
 
         // Generate new key
-        strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool());
+        strAddress = PubKeyToAddress(GetKeyFromKeyPool());
     }
 
     // Add to list and select it
--- a/util.cpp
+++ b/util.cpp
@@ -175,6 +175,7 @@
             va_start(arg_ptr, pszFormat);
             ret = vfprintf(fileout, pszFormat, arg_ptr);
             va_end(arg_ptr);
+            fflush(fileout);
         }
     }