uint256 hashGenesisBlock = hashGenesisBlockOfficial;
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
static CBigNum bnInitialHashTarget(~uint256(0) >> 40);
+unsigned int nStakeMinAge = STAKE_MIN_AGE;
+int nCoinbaseMaturity = COINBASE_MATURITY_PPC;
CBlockIndex* pindexGenesisBlock = NULL;
int nBestHeight = -1;
CBigNum bnBestChainTrust = 0;
{
if (!(IsCoinBase() || IsCoinStake()))
return 0;
- return max(0, (COINBASE_MATURITY+20) - GetDepthInMainChain());
+ return max(0, (nCoinbaseMaturity+20) - GetDepthInMainChain());
}
return pblockOrphan->hashPrevBlock;
}
-int64 static GetProofOfWorkReward(unsigned int nBits)
+int64 GetProofOfWorkReward(unsigned int nBits)
{
CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK;
CBigNum bnTarget;
// If prev is coinbase/coinstake, check that it's matured
if (txPrev.IsCoinBase() || txPrev.IsCoinStake())
- for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < COINBASE_MATURITY; pindex = pindex->pprev)
+ for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < nCoinbaseMaturity; pindex = pindex->pprev)
if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile)
return error("ConnectInputs() : tried to spend coinbase/coinstake at depth %d", pindexBlock->nHeight - pindex->nHeight);
if (!GetCoinAge(txdb, nCoinAge))
return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str());
int64 nStakeReward = GetValueOut() - nValueIn;
- if (nStakeReward > GetProofOfStakeReward(nCoinAge))
+ if (nStakeReward > GetProofOfStakeReward(nCoinAge) - GetMinFee() + MIN_TX_FEE)
return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str()));
}
else
// ppcoin: coinstake must meet hash target according to the protocol:
-// input 0 must meet the formula
+// kernel (input 0) must meet the formula
// 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.
if (!IsCoinStake())
return true;
- // Input 0 must match the stake hash target per coin age (nBits)
+ // Kernel (input 0) must match the stake hash target per coin age (nBits)
const CTxIn& txin = vin[0];
// First try finding the previous transaction in database
CBlock block;
if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
return false; // unable to read block of previous transaction
- if (block.GetBlockTime() + STAKE_MIN_AGE > nTime)
+ if (block.GetBlockTime() + nStakeMinAge > nTime)
return false; // only count coins meeting min age requirement
int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
- CBigNum bnCoinDay = CBigNum(nValueIn) * (nTime-txPrev.nTime) / COIN / (24 * 60 * 60);
+ CBigNum bnCoinDay = CBigNum(nValueIn) * min(nTime-txPrev.nTime, (unsigned int)STAKE_MAX_AGE) / COIN / (24 * 60 * 60);
// Calculate hash
CDataStream ss(SER_GETHASH, 0);
ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << txPrev.nTime << txin.prevout.n << nTime;
CBlock block;
if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
return false; // unable to read block of previous transaction
- if (block.GetBlockTime() + STAKE_MIN_AGE > nTime)
+ if (block.GetBlockTime() + nStakeMinAge > nTime)
continue; // only count coins meeting min age requirement
int64 nValueIn = txPrev.vout[txin.prevout.n].nValue;
return DoS(50, error("CheckBlock() : coinstake timestamp is too early"));
// Check coinbase reward
- if (vtx[0].GetValueOut() > (IsProofOfWork()? GetProofOfWorkReward(nBits) : 0))
+ if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0))
return DoS(50, error("CheckBlock() : coinbase reward exceeded %s > %s",
FormatMoney(vtx[0].GetValueOut()).c_str(),
FormatMoney(IsProofOfWork()? GetProofOfWorkReward(nBits) : 0).c_str()));
{
hashGenesisBlock = hashGenesisBlockTestNet;
bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
- pchMessageStart[0] = 0xfa;
- pchMessageStart[1] = 0xbf;
- pchMessageStart[2] = 0xb5;
- pchMessageStart[3] = 0xda;
+ nStakeMinAge = 60 * 60 * 24; // test net min age is 1 day
+ nCoinbaseMaturity = 60;
+ bnInitialHashTarget = CBigNum(~uint256(0) >> 29);
}
+ printf("%s Network: genesis=0x%s nBitsLimit=0x%08x nBitsInitial=0x%08x nStakeMinAge=%d nCoinbaseMaturity=%d\n",
+ fTestNet? "Test" : "PPCoin", hashGenesisBlock.ToString().substr(0, 20).c_str(), bnProofOfWorkLimit.GetCompact(), bnInitialHashTarget.GetCompact(), nStakeMinAge, nCoinbaseMaturity);
+
//
// Load block index
//
return error("LoadBlockIndex() : failed to write new checkpoint master key to db");
if (!txdb.TxnCommit())
return error("LoadBlockIndex() : failed to commit new checkpoint master key to db");
- if (!Checkpoints::ResetSyncCheckpoint())
+ if ((!fTestNet) && !Checkpoints::ResetSyncCheckpoint())
return error("LoadBlockIndex() : failed to reset sync-checkpoint");
}
txdb.Close();
// print item
CBlock block;
block.ReadFromDisk(pindex);
- printf("%d (%u,%u) %s %08lx %s mint %s tx %d",
+ printf("%d (%u,%u) %s %08lx %s mint %7s tx %d",
pindex->nHeight,
pindex->nFile,
pindex->nBlockPos,
- block.GetHash().ToString().substr(0,20).c_str(),
+ block.GetHash().ToString().c_str(),
block.nBits,
DateTimeStrFormat(block.GetBlockTime()).c_str(),
FormatMoney(pindex->nMint).c_str(),
// ppcoin: should not enter safe mode for longer invalid chain
// ppcoin: if sync-checkpoint too old enter safe mode
- if (Checkpoints::IsMatureSyncCheckpoint())
+ if (Checkpoints::IsMatureSyncCheckpoint() && !fTestNet)
{
nPriority = 2000;
strStatusBar = strRPC = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers of the issue.";
-// The message start string is designed to be unlikely to occur in normal data.
-// The characters are rarely used upper ascii, not valid as UTF-8, and produce
-// a large 4-byte int at any alignment.
-unsigned char pchMessageStart[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
-
-
bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
static map<CService, vector<unsigned char> > mapReuseKey;
printf(" getblocks stopping at %d %s (%u bytes)\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str(), nBytes);
// ppcoin: tell downloading node about the latest block if it's
// without risk being rejected due to stake connection check
- if (hashStop != hashBestChain && pindex->GetBlockTime() + STAKE_MIN_AGE > pindexBest->GetBlockTime())
+ if (hashStop != hashBestChain && pindex->GetBlockTime() + nStakeMinAge > pindexBest->GetBlockTime())
pfrom->PushInventory(CInv(MSG_BLOCK, hashBestChain));
break;
}
// (x) data
//
+ unsigned char pchMessageStart[4];
+ GetMessageStart(pchMessageStart);
+ static int64 nTimeLastPrintMessageStart = 0;
+ if (fDebug && GetBoolArg("-printmessagestart") && nTimeLastPrintMessageStart + 30 < GetAdjustedTime())
+ {
+ string strMessageStart((const char *)pchMessageStart, sizeof(pchMessageStart));
+ vector<unsigned char> vchMessageStart(strMessageStart.begin(), strMessageStart.end());
+ printf("ProcessMessages : AdjustedTime=%"PRI64d" MessageStart=%s\n", GetAdjustedTime(), HexStr(vchMessageStart).c_str());
+ nTimeLastPrintMessageStart = GetAdjustedTime();
+ }
+
loop
{
// Scan for message start
uint64 nLastBlockTx = 0;
uint64 nLastBlockSize = 0;
+int64 nLastCoinStakeSearchInterval = 0;
// CreateNewBlock:
// fProofOfStake: try (best effort) to make a proof-of-stake block
pblock->vtx.push_back(txNew);
// ppcoin: if coinstake available add coinstake tx
- static unsigned int nLastCoinStakeCheckTime = GetAdjustedTime() - nMaxClockDrift / 2; // only initialized at startup
+ static int64 nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup
CBlockIndex* pindexPrev = pindexBest;
if (fProofOfStake) // attemp to find a coinstake
{
- while (nLastCoinStakeCheckTime < GetAdjustedTime())
+ pblock->nBits = GetNextTargetRequired(pindexPrev, true);
+ CTransaction txCoinStake;
+ int64 nSearchTime = GetAdjustedTime();
+ if (nSearchTime > nLastCoinStakeSearchTime)
{
- pindexPrev = pindexBest; // get best block again to avoid getting stale
- pblock->nBits = GetNextTargetRequired(pindexPrev, true);
- CTransaction txCoinStake;
- {
- static CCriticalSection cs;
- LOCK(cs);
- // mining may have been suspended for a while so
- // need to take max to satisfy the timestamp protocol
- nLastCoinStakeCheckTime++;
- nLastCoinStakeCheckTime = max(nLastCoinStakeCheckTime, (unsigned int) (GetAdjustedTime() - nMaxClockDrift / 2));
- txCoinStake.nTime = nLastCoinStakeCheckTime;
- }
- if (pwallet->CreateCoinStake(pblock->nBits, txCoinStake))
+ if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake))
{
pblock->vtx.push_back(txCoinStake);
pblock->vtx[0].vout[0].SetEmpty();
- break;
}
+ nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime;
+ nLastCoinStakeSearchTime = nSearchTime;
}
}
IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
- // ppcoin: if proof-of-stake block found then process block
if (fProofOfStake)
{
+ // ppcoin: if proof-of-stake block found then process block
if (pblock->IsProofOfStake())
{
if (!pblock->SignBlock(*pwalletMain))