// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
-// Copyright (c) 2011-2012 The PPCoin developers
+// Copyright (c) 2011-2013 The PPCoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "net.h"
#include "init.h"
#include "ui_interface.h"
+#include "kernel.h"
+#include "scrypt_mine.h"
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
map<uint256, CBlockIndex*> mapBlockIndex;
set<pair<COutPoint, unsigned int> > setStakeSeen;
uint256 hashGenesisBlock = hashGenesisBlockOfficial;
-static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
-static CBigNum bnInitialHashTarget(~uint256(0) >> 40);
+static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20);
+static CBigNum bnInitialHashTarget(~uint256(0) >> 20);
unsigned int nStakeMinAge = STAKE_MIN_AGE;
int nCoinbaseMaturity = COINBASE_MATURITY_PPC;
CBlockIndex* pindexGenesisBlock = NULL;
map<uint256, CBlock*> mapOrphanBlocks;
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
set<pair<COutPoint, unsigned int> > setStakeSeenOrphan;
+map<uint256, uint256> mapProofOfStake;
map<uint256, CDataStream*> mapOrphanTransactions;
map<uint256, map<uint256, CDataStream*> > mapOrphanTransactionsByPrev;
// Constant stuff for coinbase transactions we create:
CScript COINBASE_FLAGS;
-const string strMessageMagic = "PPCoin Signed Message:\n";
+const string strMessageMagic = "NovaCoin Signed Message:\n";
double dHashesPerSec;
int64 nHPSTimerStart;
CBigNum bnTargetLimit = bnProofOfWorkLimit;
bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
- // ppcoin: subsidy is cut in half every 16x multiply of difficulty
+ // ppcoin: subsidy is cut in half every 64x multiply of difficulty
// A reasonably continuous curve is used to avoid shock to market
- // (nSubsidyLimit / nSubsidy) ** 4 == bnProofOfWorkLimit / bnTarget
+ // (nSubsidyLimit / nSubsidy) ** 6 == bnProofOfWorkLimit / bnTarget
+ //
+ // Human readable form:
+ //
+ // nSubsidy = 100 / (diff ^ 1/6)
CBigNum bnLowerBound = CENT;
CBigNum bnUpperBound = bnSubsidyLimit;
while (bnLowerBound + CENT <= bnUpperBound)
CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfWorkReward() : lower=%"PRI64d" upper=%"PRI64d" mid=%"PRI64d"\n", bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
- if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
+ if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
bnUpperBound = bnMidValue;
else
bnLowerBound = bnMidValue;
// ppcoin: miner's coin stake is rewarded based on coin age spent (coin-days)
int64 GetProofOfStakeReward(int64 nCoinAge)
{
- static int64 nRewardCoinYear = CENT; // creation amount per coin-year
+ static int64 nRewardCoinYear = 5 * CENT; // creation amount per coin-year
int64 nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
if (fDebug && GetBoolArg("-printcreation"))
printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d"\n", FormatMoney(nSubsidy).c_str(), nCoinAge);
}
static const int64 nTargetTimespan = 7 * 24 * 60 * 60; // one week
-static const int64 nTargetSpacingStake = 10 * 60; // ten minutes
-static const int64 nTargetSpacingWorkMax = 2 * 60 * 60; // two hours
+static const int64 nTargetSpacingWorkMax = 12 * STAKE_TARGET_SPACING; // 2-hour
//
// minimum amount of work that could possibly be required nTime after
// ppcoin: retarget with exponential moving toward target spacing
CBigNum bnNew;
bnNew.SetCompact(pindexPrev->nBits);
- int64 nTargetSpacing = fProofOfStake? nTargetSpacingStake : min(nTargetSpacingWorkMax, nTargetSpacingStake * (1 + pindexLast->nHeight - pindexPrev->nHeight));
+ int64 nTargetSpacing = fProofOfStake? STAKE_TARGET_SPACING : min(nTargetSpacingWorkMax, (int64) STAKE_TARGET_SPACING * (1 + pindexLast->nHeight - pindexPrev->nHeight));
int64 nInterval = nTargetTimespan / nTargetSpacing;
bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
bnNew /= ((nInterval + 1) * nTargetSpacing);
}
-// ppcoin: coinstake must meet hash target according to the protocol:
-// 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.
-// The reason this hash is chosen is the following:
-// 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(unsigned int nBits) const
-{
- CBigNum bnTargetPerCoinDay;
- bnTargetPerCoinDay.SetCompact(nBits);
-
- if (!IsCoinStake())
- return true;
-
- // 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
- CTxDB txdb("r");
- CTransaction txPrev;
- CTxIndex txindex;
- if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex))
- return false; // previous transaction not in main chain
- txdb.Close();
- if (nTime < txPrev.nTime)
- return false; // Transaction timestamp violation
-
- // Verify signature
- if (!VerifySignature(txPrev, *this, 0, true, 0))
- return DoS(100, error("CheckProofOfStake() : VerifySignature failed on coinstake %s", GetHash().ToString().c_str()));
-
- // Read block header
- CBlock block;
- if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
- return false; // unable to read block of previous transaction
- 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) * 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;
- if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay)
- return true;
- else
- return DoS(100, error("CheckProofOfStake() : check target failed on coinstake %s", GetHash().ToString().c_str()));
-}
-
// ppcoin: total coin age spent in transaction, in the unit of coin-days.
// Only those coins meeting minimum age requirement counts. As those
// transactions not in main chain are not currently indexed so we
CBlockIndex* pindexNew = new CBlockIndex(nFile, nBlockPos, *this);
if (!pindexNew)
return error("AddToBlockIndex() : new CBlockIndex failed");
- map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
- if (pindexNew->fProofOfStake)
- setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
- pindexNew->phashBlock = &((*mi).first);
+ pindexNew->phashBlock = &hash;
map<uint256, CBlockIndex*>::iterator miPrev = mapBlockIndex.find(hashPrevBlock);
if (miPrev != mapBlockIndex.end())
{
// ppcoin: compute chain trust score
pindexNew->bnChainTrust = (pindexNew->pprev ? pindexNew->pprev->bnChainTrust : 0) + pindexNew->GetBlockTrust();
+ // ppcoin: compute stake entropy bit for stake modifier
+ if (!pindexNew->SetStakeEntropyBit(GetStakeEntropyBit()))
+ return error("AddToBlockIndex() : SetStakeEntropyBit() failed");
+
+ // ppcoin: record proof-of-stake hash value
+ if (pindexNew->IsProofOfStake())
+ {
+ if (!mapProofOfStake.count(hash))
+ return error("AddToBlockIndex() : hashProofOfStake not found in map");
+ pindexNew->hashProofOfStake = mapProofOfStake[hash];
+ }
+
+ // ppcoin: compute stake modifier
+ uint64 nStakeModifier = 0;
+ bool fGeneratedStakeModifier = false;
+ if (!ComputeNextStakeModifier(pindexNew->pprev, nStakeModifier, fGeneratedStakeModifier))
+ return error("AddToBlockIndex() : ComputeNextStakeModifier() failed");
+ pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
+ pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew);
+ if (!CheckStakeModifierCheckpoints(pindexNew->nHeight, pindexNew->nStakeModifierChecksum))
+ return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindexNew->nHeight, nStakeModifier);
+
+ // Add to mapBlockIndex
+ map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first;
+ if (pindexNew->IsProofOfStake())
+ setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime));
+ pindexNew->phashBlock = &((*mi).first);
+
+ // Write to disk block index
CTxDB txdb;
if (!txdb.TxnBegin())
return false;
return DoS(50, error("CheckBlock() : coinbase timestamp is too early"));
// Check coinstake timestamp
- if (IsProofOfStake() && GetBlockTime() > (int64)vtx[1].nTime + nMaxClockDrift)
- return DoS(50, error("CheckBlock() : coinstake timestamp is too early"));
+ if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime))
+ return DoS(50, error("CheckBlock() : coinstake timestamp violation nTimeBlock=%u nTimeTx=%u", GetBlockTime(), vtx[1].nTime));
// Check coinbase reward
if (vtx[0].GetValueOut() > (IsProofOfWork()? (GetProofOfWorkReward(nBits) - vtx[0].GetMinFee() + MIN_TX_FEE) : 0))
if (!Checkpoints::CheckSync(hash, pindexPrev))
return error("AcceptBlock() : rejected by synchronized checkpoint");
+ if(nHeight > 0)
+ {
+ CScript expect = CScript() << nHeight;
+
+ if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin()))
+ return DoS(100, error("AcceptBlock() : block height mismatch in coinbase"));
+ }
+
// Write block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK, CLIENT_VERSION)))
return error("AcceptBlock() : out of disk space");
return error("ProcessBlock() : CheckBlock FAILED");
// ppcoin: verify hash target and signature of coinstake tx
- if (pblock->IsProofOfStake() && !pblock->vtx[1].CheckProofOfStake(pblock->nBits))
+ if (pblock->IsProofOfStake())
{
- printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str());
- return false; // do not error here as we expect this during initial block download
+ uint256 hashProofOfStake = 0;
+ if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake))
+ {
+ printf("WARNING: ProcessBlock(): check proof-of-stake failed for block %s\n", hash.ToString().c_str());
+ return false; // do not error here as we expect this during initial block download
+ }
+ if (!mapProofOfStake.count(hash)) // add to mapProofOfStake
+ mapProofOfStake.insert(make_pair(hash, hashProofOfStake));
}
CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint();
{
vector<valtype> vSolutions;
txnouttype whichType;
- const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
+ int nVouts = nTime < 1361664000 ? 1 : vtx[0].vout.size();
- if (!Solver(txout.scriptPubKey, whichType, vSolutions))
- return false;
- if (whichType == TX_PUBKEY)
+ if(!IsProofOfStake())
{
- // Sign
- const valtype& vchPubKey = vSolutions[0];
- CKey key;
- if (!keystore.GetKey(Hash160(vchPubKey), key))
- return false;
- if (key.GetPubKey() != vchPubKey)
+ for(int i = 0; i < nVouts; i++)
+ {
+ const CTxOut& txout = vtx[0].vout[i];
+
+ if (!Solver(txout.scriptPubKey, whichType, vSolutions))
+ continue;
+
+ if (whichType == TX_PUBKEY)
+ {
+ // Sign
+ valtype& vchPubKey = vSolutions[0];
+ CKey key;
+
+ if (!keystore.GetKey(Hash160(vchPubKey), key))
+ continue;
+ if (key.GetPubKey() != vchPubKey)
+ continue;
+ if(!key.Sign(GetHash(), vchBlockSig))
+ continue;
+
+ return true;
+ }
+ }
+ }
+ else
+ {
+ const CTxOut& txout = vtx[1].vout[1];
+
+ if (!Solver(txout.scriptPubKey, whichType, vSolutions))
return false;
- return key.Sign(GetHash(), vchBlockSig);
+
+ if (whichType == TX_PUBKEY)
+ {
+ // Sign
+ valtype& vchPubKey = vSolutions[0];
+ CKey key;
+
+ if (!keystore.GetKey(Hash160(vchPubKey), key))
+ return false;
+ if (key.GetPubKey() != vchPubKey)
+ return false;
+
+ return key.Sign(GetHash(), vchBlockSig);
+ }
}
+
+ printf("Sign failed\n");
return false;
}
vector<valtype> vSolutions;
txnouttype whichType;
- const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0];
+ int nVouts = nTime < 1361664000 ? 1 : vtx[0].vout.size();
- if (!Solver(txout.scriptPubKey, whichType, vSolutions))
- return false;
- if (whichType == TX_PUBKEY)
+ if(IsProofOfStake())
{
- const valtype& vchPubKey = vSolutions[0];
- CKey key;
- if (!key.SetPubKey(vchPubKey))
- return false;
- if (vchBlockSig.empty())
+ const CTxOut& txout = vtx[1].vout[1];
+
+ if (!Solver(txout.scriptPubKey, whichType, vSolutions))
return false;
- return key.Verify(GetHash(), vchBlockSig);
+ if (whichType == TX_PUBKEY)
+ {
+ valtype& vchPubKey = vSolutions[0];
+ CKey key;
+ if (!key.SetPubKey(vchPubKey))
+ return false;
+ if (vchBlockSig.empty())
+ return false;
+ return key.Verify(GetHash(), vchBlockSig);
+ }
+ }
+ else
+ {
+ for(int i = 0; i < nVouts; i++)
+ {
+ const CTxOut& txout = vtx[0].vout[i];
+
+ if (!Solver(txout.scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_PUBKEY)
+ {
+ // Verify
+ valtype& vchPubKey = vSolutions[0];
+ CKey key;
+ if (!key.SetPubKey(vchPubKey))
+ continue;
+ if (vchBlockSig.empty())
+ continue;
+ if(!key.Verify(GetHash(), vchBlockSig))
+ continue;
+
+ return true;
+ }
+ }
}
return false;
}
string strMessage = _("Warning: Disk space is low");
strMiscWarning = strMessage;
printf("*** %s\n", strMessage.c_str());
- ThreadSafeMessageBox(strMessage, "PPCoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
+ ThreadSafeMessageBox(strMessage, "NovaCoin", wxOK | wxICON_EXCLAMATION | wxMODAL);
StartShutdown();
return false;
}
if (fTestNet)
{
hashGenesisBlock = hashGenesisBlockTestNet;
- bnProofOfWorkLimit = CBigNum(~uint256(0) >> 28);
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);
+ printf("%s Network: genesis=0x%s nBitsLimit=0x%08x nBitsInitial=0x%08x nStakeMinAge=%d nCoinbaseMaturity=%d nModifierInterval=%d\n",
+ fTestNet? "Test" : "NovaCoin", hashGenesisBlock.ToString().substr(0, 20).c_str(), bnProofOfWorkLimit.GetCompact(), bnInitialHashTarget.GetCompact(), nStakeMinAge, nCoinbaseMaturity, nModifierInterval);
//
// Load block index
if (!fAllowNew)
return false;
- // Genesis Block:
- // CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- // CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- // CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- // CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- // vMerkleTree: 4a5e1e
-
// Genesis block
- const char* pszTimestamp = "Matonis 07-AUG-2012 Parallel Currencies And The Roadmap To Monetary Freedom";
+ const char* pszTimestamp = "https://bitcointalk.org/index.php?topic=134179.msg1502196#msg1502196";
CTransaction txNew;
- txNew.nTime = 1345083810;
+ txNew.nTime = 1360105017;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
block.hashPrevBlock = 0;
block.hashMerkleRoot = block.BuildMerkleTree();
block.nVersion = 1;
- block.nTime = 1345084287;
+ block.nTime = 1360105017;
block.nBits = bnProofOfWorkLimit.GetCompact();
- block.nNonce = 2179302059;
-
- if (fTestNet)
- {
- block.nTime = 1345090000;
- block.nNonce = 122894938;
- }
+ block.nNonce = 1575379;
//// debug print
- printf("%s\n", block.GetHash().ToString().c_str());
- printf("%s\n", hashGenesisBlock.ToString().c_str());
- printf("%s\n", block.hashMerkleRoot.ToString().c_str());
- assert(block.hashMerkleRoot == uint256("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
+ assert(block.hashMerkleRoot == uint256("0x4cb33b3b6a861dcbc685d3e614a9cafb945738d6833f182855679f2fad02057b"));
block.print();
assert(block.GetHash() == hashGenesisBlock);
assert(block.CheckBlock());
}
// ppcoin: should not enter safe mode for longer invalid chain
- // ppcoin: if sync-checkpoint too old enter safe mode
- if (Checkpoints::IsMatureSyncCheckpoint() && !fTestNet)
+ // ppcoin: if sync-checkpoint is too old do not enter safe mode
+ if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet)
{
- nPriority = 2000;
- strStatusBar = strRPC = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers of the issue.";
+ nPriority = 100;
+ strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers.";
}
// ppcoin: if detected invalid checkpoint enter safe mode
if (Checkpoints::hashInvalidCheckpoint != 0)
{
nPriority = 3000;
- strStatusBar = strRPC = "WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or notify developers of the issue.";
+ strStatusBar = strRPC = "WARNING: Invalid checkpoint found! Displayed transactions may not be correct! You may need to upgrade, or notify developers.";
}
// Alerts
((uint32_t*)pstate)[i] = ctx.h[i];
}
-//
-// 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 0xffff0000 or above,
-// the block is rebuilt and nNonce starts over at zero.
-//
-unsigned int static ScanHash_CryptoPP(char* pmidstate, char* pdata, char* phash1, char* phash, unsigned int& nHashesDone)
-{
- unsigned int& nNonce = *(unsigned int*)(pdata + 12);
- for (;;)
- {
- // Crypto++ SHA-256
- // Hash pdata using pmidstate as the starting state into
- // preformatted buffer phash1, then hash phash1 into phash
- nNonce++;
- SHA256Transform(phash1, pdata, pmidstate);
- SHA256Transform(phash, phash1, pSHA256InitState);
-
- // Return the nonce if the hash has at least some zero bits,
- // caller will check if it has enough to reach the target
- if (((unsigned short*)phash)[14] == 0)
- return nNonce;
-
- // If nothing found after trying for a while, return -1
- if ((nNonce & 0xffff) == 0)
- {
- nHashesDone = 0xffff+1;
- return (unsigned int) -1;
- }
- }
-}
-
// Some explaining would be appreciated
class COrphan
{
{
pblock->nBits = GetNextTargetRequired(pindexPrev, true);
CTransaction txCoinStake;
- int64 nSearchTime = GetAdjustedTime();
+ int64 nSearchTime = txCoinStake.nTime; // search to current time
if (nSearchTime > nLastCoinStakeSearchTime)
{
if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake))
{
- pblock->vtx.push_back(txCoinStake);
- pblock->vtx[0].vout[0].SetEmpty();
+ if (txCoinStake.nTime >= max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - nMaxClockDrift))
+ { // make sure coinstake would meet timestamp protocol
+ // as it would be the same as the block timestamp
+ pblock->vtx[0].vout[0].SetEmpty();
+ pblock->vtx[0].nTime = txCoinStake.nTime;
+ pblock->vtx.push_back(txCoinStake);
+ }
}
nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime;
nLastCoinStakeSearchTime = nSearchTime;
continue;
// Timestamp limit
- if (tx.nTime > GetAdjustedTime())
+ if (tx.nTime > GetAdjustedTime() || (pblock->IsProofOfStake() && tx.nTime > pblock->vtx[1].nTime))
continue;
// ppcoin: simplify transaction fee - allow free = false
// Fill in header
pblock->hashPrevBlock = pindexPrev->GetBlockHash();
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
+ if (pblock->IsProofOfStake())
+ pblock->nTime = pblock->vtx[1].nTime; //same as coinstake timestamp
pblock->nTime = max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime());
pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift);
- pblock->UpdateTime(pindexPrev);
+ if (pblock->IsProofOfWork())
+ pblock->UpdateTime(pindexPrev);
pblock->nNonce = 0;
return pblock.release();
hashPrevBlock = pblock->hashPrevBlock;
}
++nExtraNonce;
- pblock->vtx[0].vin[0].scriptSig = (CScript() << pblock->nTime << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
+
+ unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2
+ pblock->vtx[0].vin[0].scriptSig = (CScript() << nHeight << CBigNum(nExtraNonce)) + COINBASE_FLAGS;
+
assert(pblock->vtx[0].vin[0].scriptSig.size() <= 100);
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
{
+ void *scratchbuf = scrypt_buffer_alloc();
+
printf("CPUMiner started for proof-of-%s\n", fProofOfStake? "stake" : "work");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
//
int64 nStart = GetTime();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- uint256 hashbuf[2];
- uint256& hash = *alignup<16>(hashbuf);
+
+ unsigned int max_nonce = 0xffff0000;
+ block_header res_header;
+ uint256 result;
+
loop
{
unsigned int nHashesDone = 0;
unsigned int nNonceFound;
- // Crypto++ SHA-256
- nNonceFound = ScanHash_CryptoPP(pmidstate, pdata + 64, phash1,
- (char*)&hash, nHashesDone);
+ nNonceFound = scanhash_scrypt(
+ (block_header *)&pblock->nVersion,
+ scratchbuf,
+ max_nonce,
+ nHashesDone,
+ UBEGIN(result),
+ &res_header
+ );
// Check if something found
if (nNonceFound != (unsigned int) -1)
{
- for (unsigned int i = 0; i < sizeof(hash)/4; i++)
- ((unsigned int*)&hash)[i] = ByteReverse(((unsigned int*)&hash)[i]);
-
- if (hash <= hashTarget)
+ if (result <= hashTarget)
{
// Found a solution
- pblock->nNonce = ByteReverse(nNonceFound);
- assert(hash == pblock->GetHash());
+ pblock->nNonce = nNonceFound;
+ assert(result == pblock->GetHash());
if (!pblock->SignBlock(*pwalletMain))
{
strMintWarning = strMintMessage;
break; // need to update coinbase timestamp
}
}
+
+ scrypt_buffer_free(scratchbuf);
}
void static ThreadBitcoinMiner(void* parg)