// ppcoin: target change every block
// ppcoin: retarget with exponential moving toward target spacing
CBigNum bnNew;
- bnNew.SetCompact(pindexLast->nBits);
+ bnNew.SetCompact(pindexPrev->nBits);
bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
bnNew /= ((nInterval + 1) * nTargetSpacing);
// ppcoin: coinstake must meet hash target according to the protocol:
// at least one input must meet the formula
-// hash(nBits + txPrev.block.nTime + txPrev.nTime + nTime) < bnTarget * nCoinDay
+// hash(nBits + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDay
// this ensures that the chance of getting a coinstake is proportional to the
// amount of coin age one owns.
// The reason this hash is chosen is the following:
-// nBits: encodes all past block timestamps, prevents computing hash in advance
-// txPrev.block.nTime: prevent nodes from guessing a good timestamp to generate
-// transaction for future advantage
-// txPrev.nTime: prevent nodes from meeting target simultaneously
-// block/tx hash should not be used here as they can be generated in vast quatities
-// so as to generate blocks faster, degrading the system back into a proof-of-work
-// situation.
+// nBits: encodes all past block timestamps, making computing hash in advance
+// more difficult
+// txPrev.block.nTime: prevent nodes from guessing a good timestamp to
+// generate transaction for future advantage
+// txPrev.offset: offset of txPrev inside block, to reduce the chance of
+// nodes generating coinstake at the same time
+// txPrev.nTime: reduce the chance of nodes generating coinstake at the same
+// time
+// txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
+// generating coinstake at the same time
+// block/tx hash should not be used here as they can be generated in vast
+// quantities so as to generate blocks faster, degrading the system back into
+// a proof-of-work situation.
//
bool CTransaction::CheckProofOfStake(CTxDB& txdb, unsigned int nBits) const
{
CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60);
// Calculate hash
CDataStream ss(SER_GETHASH, VERSION);
- ss << nBits << block.nTime << txPrev.nTime << nTime;
+ ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime;
if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay)
return true;
}
CBlockIndex* pindexPrev = (*mi).second;
int nHeight = pindexPrev->nHeight+1;
- // Check proof of work
+ // ppcoin: check for coinstake duplicate
+ if (IsProofOfStake())
+ { // check if coinstake is already connected; that would imply the owner
+ // of the coinstake sent multiple blocks with the same coinstake
+ CTxIndex txindex;
+ if (CTxDB("r").ReadTxIndex(vtx[1].GetHash(), txindex))
+ return error("AcceptBlock() : block %s has duplicate coinstake %s", hash.ToString().c_str(), vtx[1].GetHash().ToString().c_str());
+ }
+
+ // Check proof-of-work or proof-of-stake
if (nBits != GetNextTargetRequired(pindexPrev, IsProofOfStake()))
return DoS(100, error("AcceptBlock() : incorrect proof-of-work/proof-of-stake"));
bnNewBlock.SetCompact(pblock->nBits);
CBigNum bnRequired;
bnRequired.SetCompact(ComputeMinWork(pcheckpoint->nBits, deltaTime));
- if (bnNewBlock > bnRequired)
+ if (pblock->IsProofOfWork() && bnNewBlock > bnRequired)
{
pfrom->Misbehaving(100);
return error("ProcessBlock() : block with too little proof-of-work");
// print item
CBlock block;
block.ReadFromDisk(pindex);
- printf("%d (%u,%u) %s %s tx %d",
+ printf("%d (%u,%u) %s %08lx %s tx %d",
pindex->nHeight,
pindex->nFile,
pindex->nBlockPos,
block.GetHash().ToString().substr(0,20).c_str(),
+ block.nBits,
DateTimeStrFormat("%x %H:%M:%S", block.GetBlockTime()).c_str(),
block.vtx.size());
CBlock* CreateNewBlock(CWallet* pwallet)
{
- CBlockIndex* pindexPrev = pindexBest;
CReserveKey reservekey(pwallet);
// Create new block
pblock->vtx.push_back(txNew);
// ppcoin: if coinstake available add coinstake tx
- pblock->nBits = GetNextTargetRequired(pindexPrev, true);
- CTransaction txCoinStake;
- if (pwallet->CreateCoinStake(txNew.vout[0].scriptPubKey, pblock->nBits, txCoinStake))
- pblock->vtx.push_back(txCoinStake);
- else
- pblock->nBits = GetNextTargetRequired(pindexPrev, false);
+ static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift; // only initialized at startup
+ CBlockIndex* pindexPrev = pindexBest;
+ while (nLastCoinStakeCheckTime < GetAdjustedTime())
+ {
+ pindexPrev = pindexBest; // get best block again to avoid getting stale
+ pblock->nBits = GetNextTargetRequired(pindexPrev, true);
+ static CCriticalSection cs;
+ CTransaction txCoinStake;
+ CRITICAL_BLOCK(cs)
+ {
+ nLastCoinStakeCheckTime++;
+ txCoinStake.nTime = nLastCoinStakeCheckTime;
+ }
+ if (pwallet->CreateCoinStake(txNew.vout[0].scriptPubKey, pblock->nBits, txCoinStake))
+ {
+ pblock->vtx.push_back(txCoinStake);
+ break;
+ }
+ }
+
+ pblock->nBits = GetNextTargetRequired(pindexPrev, pblock->IsProofOfStake());
// Collect memory pool transactions into the block
int64 nFees = 0;
uint256 hash = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- if (hash > hashTarget)
- return false;
+ if (hash > hashTarget && pblock->IsProofOfWork())
+ return error("BitcoinMiner : proof-of-work not meeting target");
//// debug print
printf("BitcoinMiner:\n");
- printf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ printf("new block 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());
auto_ptr<CBlock> pblock(CreateNewBlock(pwallet));
if (!pblock.get())
return;
+
IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
+ // ppcoin: if proof-of-stake block found then process block
+ if (pblock->IsProofOfStake())
+ {
+ // should be able to sign block - assert here for now
+ assert(pblock->SignBlock(*pwalletMain));
+ printf("BitcoinMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString().c_str());
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);
+ CheckWork(pblock.get(), *pwalletMain, reservekey);
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ continue;
+ }
+
printf("Running BitcoinMiner with %d transactions in block\n", pblock->vtx.size());