aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coding.txt41
-rw-r--r--db.cpp4
-rw-r--r--db.h7
-rw-r--r--main.cpp528
-rw-r--r--main.h11
-rw-r--r--rpc.cpp119
-rw-r--r--serialize.h2
-rw-r--r--sha256.cpp6
-rw-r--r--ui.cpp4
-rw-r--r--util.cpp1
10 files changed, 469 insertions, 254 deletions
diff --git a/coding.txt b/coding.txt
new file mode 100644
index 0000000000..4707476697
--- /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 28ae5583b1..c768778c5f 100644
--- a/db.cpp
+++ b/db.cpp
@@ -961,7 +961,7 @@ void CWalletDB::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex);
}
-vector<unsigned char> CWalletDB::GetKeyFromKeyPool()
+vector<unsigned char> GetKeyFromKeyPool()
{
CWalletDB walletdb;
int64 nIndex = 0;
@@ -971,7 +971,7 @@ vector<unsigned char> CWalletDB::GetKeyFromKeyPool()
return keypool.vchPubKey;
}
-int64 CWalletDB::GetOldestKeyPoolTime()
+int64 GetOldestKeyPoolTime()
{
CWalletDB walletdb;
int64 nIndex = 0;
diff --git a/db.h b/db.h
index df48699e91..0f705a863d 100644
--- a/db.h
+++ b/db.h
@@ -26,6 +26,8 @@ extern DbEnv dbenv;
extern void DBFlush(bool fShutdown);
+extern vector<unsigned char> GetKeyFromKeyPool();
+extern int64 GetOldestKeyPoolTime();
@@ -440,9 +442,8 @@ protected:
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);
diff --git a/main.cpp b/main.cpp
index 1f5261d4e9..acfcbc90fd 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<uint256> 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<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 @@ 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<CBlock> pblock(new CBlock());
+ unsigned int nTransactionsUpdatedLast = nTransactionsUpdated;
+ CBlockIndex* pindexPrev = pindexBest;
+
+ auto_ptr<CBlock> 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<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);
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 @@ 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 dda5f730c7..e5000d7579 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<CWalletTx*>(this)->Init();
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
READWRITE(vtxPrev);
READWRITE(mapValue);
diff --git a/rpc.cpp b/rpc.cpp
index 271d36c2f6..113de85a9d 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 <boost/asio.hpp>
#include <boost/iostreams/concepts.hpp>
@@ -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<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 @@ pair<string, rpcfn_type> pCallTable[] =
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 @@ string pAllowInSafeMode[] =
"getaddressesbylabel", // deprecated
"backupwallet",
"validateaddress",
+ "getwork",
};
set<string> 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 dde2aeb9a1..a289769f22 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 56a89260cb..530c2c7c19 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 b4eec0a55a..aafd4a7a8a 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 7576beabaa..607dc3f11e 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);
}
}