Merge remote branch 'refs/remotes/svn/trunk' into svn

This commit is contained in:
Gavin Andresen 2010-11-23 15:01:34 -05:00
commit 94073ecf7b
10 changed files with 467 additions and 252 deletions

41
coding.txt Normal file
View file

@ -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

4
db.cpp
View file

@ -961,7 +961,7 @@ void CWalletDB::ReturnKey(int64 nIndex)
printf("keypool return %"PRI64d"\n", nIndex); printf("keypool return %"PRI64d"\n", nIndex);
} }
vector<unsigned char> CWalletDB::GetKeyFromKeyPool() vector<unsigned char> GetKeyFromKeyPool()
{ {
CWalletDB walletdb; CWalletDB walletdb;
int64 nIndex = 0; int64 nIndex = 0;
@ -971,7 +971,7 @@ vector<unsigned char> CWalletDB::GetKeyFromKeyPool()
return keypool.vchPubKey; return keypool.vchPubKey;
} }
int64 CWalletDB::GetOldestKeyPoolTime() int64 GetOldestKeyPoolTime()
{ {
CWalletDB walletdb; CWalletDB walletdb;
int64 nIndex = 0; int64 nIndex = 0;

7
db.h
View file

@ -26,6 +26,8 @@ extern DbEnv dbenv;
extern void DBFlush(bool fShutdown); extern void DBFlush(bool fShutdown);
extern vector<unsigned char> GetKeyFromKeyPool();
extern int64 GetOldestKeyPoolTime();
@ -440,9 +442,8 @@ protected:
void KeepKey(int64 nIndex); void KeepKey(int64 nIndex);
static void ReturnKey(int64 nIndex); static void ReturnKey(int64 nIndex);
friend class CReserveKey; friend class CReserveKey;
public: friend vector<unsigned char> GetKeyFromKeyPool();
vector<unsigned char> GetKeyFromKeyPool(); friend int64 GetOldestKeyPoolTime();
int64 GetOldestKeyPoolTime();
}; };
bool LoadWallet(bool& fFirstRunRet); bool LoadWallet(bool& fFirstRunRet);

524
main.cpp
View file

@ -159,7 +159,7 @@ bool AddToWallet(const CWalletTx& wtxIn)
if (txout.scriptPubKey == scriptDefaultKey) if (txout.scriptPubKey == scriptDefaultKey)
{ {
CWalletDB walletdb; CWalletDB walletdb;
vchDefaultKey = walletdb.GetKeyFromKeyPool(); vchDefaultKey = GetKeyFromKeyPool();
walletdb.WriteDefaultKey(vchDefaultKey); walletdb.WriteDefaultKey(vchDefaultKey);
walletdb.WriteName(PubKeyToAddress(vchDefaultKey), ""); walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
} }
@ -1557,31 +1557,25 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// Preliminary checks // Preliminary checks
if (!pblock->CheckBlock()) if (!pblock->CheckBlock())
{
delete pblock;
return error("ProcessBlock() : CheckBlock FAILED"); return error("ProcessBlock() : CheckBlock FAILED");
}
// If don't already have its previous block, shunt it off to holding area until we get it // If don't already have its previous block, shunt it off to holding area until we get it
if (!mapBlockIndex.count(pblock->hashPrevBlock)) if (!mapBlockIndex.count(pblock->hashPrevBlock))
{ {
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str()); printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,20).c_str());
mapOrphanBlocks.insert(make_pair(hash, pblock)); CBlock* pblock2 = new CBlock(*pblock);
mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock)); mapOrphanBlocks.insert(make_pair(hash, pblock2));
mapOrphanBlocksByPrev.insert(make_pair(pblock2->hashPrevBlock, pblock2));
// Ask this guy to fill in what we're missing // Ask this guy to fill in what we're missing
if (pfrom) if (pfrom)
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock)); pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
return true; return true;
} }
// Store to disk // Store to disk
if (!pblock->AcceptBlock()) if (!pblock->AcceptBlock())
{
delete pblock;
return error("ProcessBlock() : AcceptBlock FAILED"); return error("ProcessBlock() : AcceptBlock FAILED");
}
delete pblock;
// Recursively process any orphan blocks that depended on this one // Recursively process any orphan blocks that depended on this one
vector<uint256> vWorkQueue; vector<uint256> vWorkQueue;
@ -2504,7 +2498,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_BLOCK, pblock->GetHash()); CInv inv(MSG_BLOCK, pblock->GetHash());
pfrom->AddInventoryKnown(inv); pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, pblock.release())) if (ProcessBlock(pfrom, pblock.get()))
mapAlreadyAskedFor.erase(inv); 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 // Keep giving the same key to the same ip until they use it
if (!mapReuseKey.count(pfrom->addr.ip)) 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 // Send back approval of order and pubkey to use
CScript scriptPubKey; 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. // ScanHash scans nonces looking for a hash with at least some zero bits.
// It operates on big endian data. Caller does the byte reversing. // It operates on big endian data. Caller does the byte reversing.
// All input buffers are 16-byte aligned. nNonce is usually preserved // 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. // 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 (;;) for (;;)
{ {
// Crypto++ SHA-256 // 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 // preformatted buffer phash1, then hash phash1 into phash
nNonce++; nNonce++;
SHA256Transform(phash1, pblock, pmidstate); SHA256Transform(phash1, pdata, pmidstate);
SHA256Transform(phash, phash1, pSHA256InitState); SHA256Transform(phash, phash1, pSHA256InitState);
// Return the nonce if the hash has at least some zero bits, // 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() void BitcoinMiner()
{ {
@ -3064,9 +3314,11 @@ void BitcoinMiner()
if (mapArgs.count("-4way")) if (mapArgs.count("-4way"))
f4WaySSE2 = (mapArgs["-4way"] != "0"); f4WaySSE2 = (mapArgs["-4way"] != "0");
// Each thread has its own key and counter
CReserveKey reservekey; CReserveKey reservekey;
unsigned int nExtraNonce = 0; unsigned int nExtraNonce = 0;
int64 nPrevTime = 0; int64 nPrevTime = 0;
while (fGenerateBitcoins) while (fGenerateBitcoins)
{ {
if (AffinityBugWorkaround(ThreadBitcoinMiner)) if (AffinityBugWorkaround(ThreadBitcoinMiner))
@ -3082,210 +3334,32 @@ void BitcoinMiner()
return; 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 // 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()) if (!pblock.get())
return; 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()); printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());
// //
// Prebuild hash buffer // Prebuild hash buffers
// //
struct tmpworkspace char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf);
{ char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf);
struct unnamed2 char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf);
{
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; FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1);
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& nBlockTime = *(unsigned int*)(pdata + 64 + 4);
unsigned int nBlocks1 = FormatHashBlocks(&tmp.hash1, sizeof(tmp.hash1)); unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12);
// 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);
// //
@ -3303,11 +3377,11 @@ void BitcoinMiner()
#ifdef FOURWAYSSE2 #ifdef FOURWAYSSE2
if (f4WaySSE2) if (f4WaySSE2)
// tcatm's 4-way 128-bit SSE2 SHA-256 // 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 else
#endif #endif
// Crypto++ SHA-256 // 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 // Check if something found
if (nNonceFound != -1) if (nNonceFound != -1)
@ -3321,33 +3395,9 @@ void BitcoinMiner()
pblock->nNonce = ByteReverse(nNonceFound); pblock->nNonce = ByteReverse(nNonceFound);
assert(hash == pblock->GetHash()); 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); SetThreadPriority(THREAD_PRIORITY_NORMAL);
CRITICAL_BLOCK(cs_main) CheckWork(pblock.get(), reservekey);
{
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");
}
}
SetThreadPriority(THREAD_PRIORITY_LOWEST); SetThreadPriority(THREAD_PRIORITY_LOWEST);
Sleep(500);
break; break;
} }
} }
@ -3393,7 +3443,7 @@ void BitcoinMiner()
return; return;
if (vNodes.empty()) if (vNodes.empty())
break; break;
if (tmp.block.nNonce >= 0xff000000) if (nBlockNonce >= 0xffff0000)
break; break;
if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60) if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
break; break;
@ -3402,7 +3452,7 @@ void BitcoinMiner()
// Update nTime every few seconds // Update nTime every few seconds
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
tmp.block.nTime = ByteReverse(pblock->nTime); nBlockTime = ByteReverse(pblock->nTime);
} }
} }
} }

11
main.h
View file

@ -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); string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false);
void GenerateBitcoins(bool fGenerate); void GenerateBitcoins(bool fGenerate);
void ThreadBitcoinMiner(void* parg); 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(); void BitcoinMiner();
bool CheckProofOfWork(uint256 hash, unsigned int nBits); bool CheckProofOfWork(uint256 hash, unsigned int nBits);
bool IsInitialBlockDownload(); bool IsInitialBlockDownload();
@ -753,21 +757,28 @@ public:
void Init() void Init()
{ {
vtxPrev.clear();
mapValue.clear();
vOrderForm.clear();
nTimeReceived = 0; nTimeReceived = 0;
fFromMe = false; fFromMe = false;
fSpent = false; fSpent = false;
fTimeReceivedIsTxTime = false; fTimeReceivedIsTxTime = false;
fUnused = false; fUnused = false;
strFromAccount.clear();
fDebitCached = false; fDebitCached = false;
fCreditCached = false; fCreditCached = false;
nDebitCached = 0; nDebitCached = 0;
nCreditCached = 0; nCreditCached = 0;
nTimeDisplayed = 0; nTimeDisplayed = 0;
nLinesDisplayed = 0; nLinesDisplayed = 0;
fConfirmedDisplayed = false;
} }
IMPLEMENT_SERIALIZE IMPLEMENT_SERIALIZE
( (
if (fRead)
const_cast<CWalletTx*>(this)->Init();
nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action); nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion, ser_action);
READWRITE(vtxPrev); READWRITE(vtxPrev);
READWRITE(mapValue); READWRITE(mapValue);

119
rpc.cpp
View file

@ -3,6 +3,7 @@
// file license.txt or http://www.opensource.org/licenses/mit-license.php. // file license.txt or http://www.opensource.org/licenses/mit-license.php.
#include "headers.h" #include "headers.h"
#include "cryptopp/sha.h"
#undef printf #undef printf
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/iostreams/concepts.hpp> #include <boost/iostreams/concepts.hpp>
@ -50,6 +51,7 @@ void PrintConsole(const char* format, ...)
ret = limit - 1; ret = limit - 1;
buffer[limit-1] = 0; buffer[limit-1] = 0;
} }
printf("%s", buffer);
#if defined(__WXMSW__) && defined(GUI) #if defined(__WXMSW__) && defined(GUI)
MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION); MyMessageBox(buffer, "Bitcoin", wxOK | wxICON_EXCLAMATION);
#else #else
@ -263,7 +265,7 @@ Value getinfo(const Array& params, bool fHelp)
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("hashespersec", gethashespersec(params, false))); obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
obj.push_back(Pair("testnet", fTestNet)); 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("paytxfee", (double)nTransactionFee / (double)COIN));
obj.push_back(Pair("errors", GetWarnings("statusbar"))); obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj; return obj;
@ -285,7 +287,7 @@ Value getnewaddress(const Array& params, bool fHelp)
strAccount = params[0].get_str(); strAccount = params[0].get_str();
// Generate a new key that is added to wallet // Generate a new key that is added to wallet
string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
SetAddressBookName(strAddress, strAccount); SetAddressBookName(strAddress, strAccount);
return strAddress; return strAddress;
@ -329,7 +331,7 @@ Value getaccountaddress(const Array& params, bool fHelp)
// Generate a new key // Generate a new key
if (account.vchPubKey.empty()) if (account.vchPubKey.empty())
{ {
account.vchPubKey = CWalletDB().GetKeyFromKeyPool(); account.vchPubKey = GetKeyFromKeyPool();
string strAddress = PubKeyToAddress(account.vchPubKey); string strAddress = PubKeyToAddress(account.vchPubKey);
SetAddressBookName(strAddress, strAccount); SetAddressBookName(strAddress, strAccount);
walletdb.WriteAccount(strAccount, account); 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("getbalance", &getbalance),
make_pair("move", &movecmd), make_pair("move", &movecmd),
make_pair("sendfrom", &sendfrom), make_pair("sendfrom", &sendfrom),
make_pair("getwork", &getwork),
}; };
map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0])); map<string, rpcfn_type> mapCallTable(pCallTable, pCallTable + sizeof(pCallTable)/sizeof(pCallTable[0]));
@ -996,6 +1105,7 @@ string pAllowInSafeMode[] =
"getaddressesbylabel", // deprecated "getaddressesbylabel", // deprecated
"backupwallet", "backupwallet",
"validateaddress", "validateaddress",
"getwork",
}; };
set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0])); set<string> setAllowInSafeMode(pAllowInSafeMode, pAllowInSafeMode + sizeof(pAllowInSafeMode)/sizeof(pAllowInSafeMode[0]));
@ -1418,7 +1528,8 @@ void ThreadRPCServer2(void* parg)
if (valMethod.type() != str_type) if (valMethod.type() != str_type)
throw JSONRPCError(-32600, "Method must be a string"); throw JSONRPCError(-32600, "Method must be a string");
string strMethod = valMethod.get_str(); 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 // Parse params
Value valParams = find_value(request, "params"); Value valParams = find_value(request, "params");

View file

@ -22,7 +22,7 @@ class CDataStream;
class CAutoFile; class CAutoFile;
static const unsigned int MAX_SIZE = 0x02000000; static const unsigned int MAX_SIZE = 0x02000000;
static const int VERSION = 31600; static const int VERSION = 31601;
static const char* pszSubVer = ""; static const char* pszSubVer = "";

View file

@ -110,15 +110,15 @@ static const unsigned int pSHA256InitState[8] =
{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; {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 (;;) for (;;)
{ {
nNonce += NPAR; nNonce += NPAR;
unsigned int thashbuf[9][NPAR]; unsigned int thashbuf[9][NPAR];
unsigned int (&thash)[9][NPAR] = *alignup<16>(&thashbuf); 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++) for (int j = 0; j < NPAR; j++)
{ {

4
ui.cpp
View file

@ -1171,7 +1171,7 @@ void CMainFrame::OnButtonNew(wxCommandEvent& event)
string strName = dialog.GetValue(); string strName = dialog.GetValue();
// Generate new key // Generate new key
string strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); string strAddress = PubKeyToAddress(GetKeyFromKeyPool());
// Save // Save
SetAddressBookName(strAddress, strName); SetAddressBookName(strAddress, strName);
@ -2575,7 +2575,7 @@ void CAddressBookDialog::OnButtonNew(wxCommandEvent& event)
strName = dialog.GetValue(); strName = dialog.GetValue();
// Generate new key // Generate new key
strAddress = PubKeyToAddress(CWalletDB().GetKeyFromKeyPool()); strAddress = PubKeyToAddress(GetKeyFromKeyPool());
} }
// Add to list and select it // Add to list and select it

View file

@ -175,6 +175,7 @@ inline int OutputDebugStringF(const char* pszFormat, ...)
va_start(arg_ptr, pszFormat); va_start(arg_ptr, pszFormat);
ret = vfprintf(fileout, pszFormat, arg_ptr); ret = vfprintf(fileout, pszFormat, arg_ptr);
va_end(arg_ptr); va_end(arg_ptr);
fflush(fileout);
} }
} }