|
|
|
@ -159,7 +159,7 @@ bool AddToWallet(const CWalletTx& wtxIn)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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:
@@ -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()
@@ -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()
@@ -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()
@@ -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()
@@ -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()
@@ -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()
@@ -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); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|