#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>
const string strMessageMagic = "NovaCoin Signed Message:\n";
-double dHashesPerSec;
-int64 nHPSTimerStart;
-
// Settings
int64 nTransactionFee = MIN_TX_FEE;
-
+bool fStakeUsePooledKeys = false;
//////////////////////////////////////////////////////////////////////////////
//
}
//
-// minimum amount of work that could possibly be required nTime after
-// minimum work required was nBase
+// maximum nBits value could possible be required nTime after
//
-unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
+unsigned int ComputeMaxBits(CBigNum bnTargetLimit, unsigned int nBase, int64 nTime)
{
- CBigNum bnTargetLimit = bnProofOfWorkLimit;
-
CBigNum bnResult;
bnResult.SetCompact(nBase);
bnResult *= 2;
return bnResult.GetCompact();
}
+//
+// minimum amount of work that could possibly be required nTime after
+// minimum proof-of-work required was nBase
+//
+unsigned int ComputeMinWork(unsigned int nBase, int64 nTime)
+{
+ return ComputeMaxBits(bnProofOfWorkLimit, nBase, nTime);
+}
+
+//
+// minimum amount of stake that could possibly be required nTime after
+// minimum proof-of-stake required was nBase
+//
+unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime)
+{
+ return ComputeMaxBits(GetProofOfStakeLimit(0, nBlockTime), nBase, nTime);
+}
+
+
// ppcoin: find last block index up to pindex
const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake)
{
if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
return DoS(100, error("CheckBlock() : size limits failed"));
- // Special short-term limits to avoid 10,000 BDB lock limit:
- if (GetBlockTime() < LOCKS_SWITCH_TIME)
- {
- // Rule is: #unique txids referenced <= 4,500
- // ... to prevent 10,000 BDB lock exhaustion on old clients
- set<uint256> setTxIn;
- for (size_t i = 0; i < vtx.size(); i++)
- {
- setTxIn.insert(vtx[i].GetHash());
- if (i == 0) continue; // skip coinbase txin
- BOOST_FOREACH(const CTxIn& txin, vtx[i].vin)
- setTxIn.insert(txin.prevout.hash);
- }
- size_t nTxids = setTxIn.size();
- if (nTxids > 4500)
- return error("CheckBlock() : maxlocks violation");
- }
-
// Check proof of work matches claimed amount
if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits))
return DoS(50, error("CheckBlock() : proof of work failed"));
if (!Checkpoints::CheckHardened(nHeight, hash))
return DoS(100, error("AcceptBlock() : rejected by hardened checkpoint lock-in at %d", nHeight));
- // ppcoin: check that the block satisfies synchronized checkpoint
- if (!Checkpoints::CheckSync(hash, pindexPrev))
- {
- if(!GetBoolArg("-nosynccheckpoints", false))
- {
- return error("AcceptBlock() : rejected by synchronized checkpoint");
- }
- else
- {
- strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!");
- }
- }
+ // Check that the block satisfies synchronized checkpoint
+ if (!GetBoolArg("-nosynccheckpoints", false) && !Checkpoints::CheckSync(hash, pindexPrev))
+ return error("AcceptBlock() : rejected by synchronized checkpoint");
// Enforce rule that the coinbase starts with serialized block height
CScript expect = CScript() << nHeight;
// ppcoin: verify hash target and signature of coinstake tx
if (pblock->IsProofOfStake())
{
- uint256 hashProofOfStake = 0;
- if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake))
+ uint256 hashProofOfStake = 0, targetProofOfStake = 0;
+ if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, hashProofOfStake, targetProofOfStake))
{
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
CBigNum bnNewBlock;
bnNewBlock.SetCompact(pblock->nBits);
CBigNum bnRequired;
- bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, pblock->IsProofOfStake())->nBits, deltaTime));
+
+ if (pblock->IsProofOfStake())
+ bnRequired.SetCompact(ComputeMinStake(GetLastBlockIndex(pcheckpoint, true)->nBits, deltaTime, pblock->nTime));
+ else
+ bnRequired.SetCompact(ComputeMinWork(GetLastBlockIndex(pcheckpoint, false)->nBits, deltaTime));
+
if (bnNewBlock > bnRequired)
{
if (pfrom)
FILE* AppendBlockFile(unsigned int& nFileRet)
{
nFileRet = 0;
- loop
+ while (true)
{
FILE* file = OpenBlockFile(nCurrentBlockFile, 0, "ab");
if (!file)
strStatusBar = strMiscWarning;
}
- // ppcoin: should not enter safe mode for longer invalid chain
- // ppcoin: if sync-checkpoint is too old do not enter safe mode
- if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload())
+ // * Should not enter safe mode for longer invalid chain
+ // * If sync-checkpoint is too old do not enter safe mode
+ // * Do not display warning if -nosynccheckpoints specified
+ if (!GetBoolArg("-nosynccheckpoints", false) && Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 10) && !fTestNet && !IsInitialBlockDownload())
{
nPriority = 100;
strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers.";
nPriority = alert.nPriority;
strStatusBar = alert.strStatusBar;
if (nPriority > 1000)
- strRPC = strStatusBar; // ppcoin: safe mode for high alert
+ strRPC = strStatusBar;
}
}
}
{
CBlock block;
vRecv >> block;
+ uint256 hashBlock = block.GetHash();
- printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
+ printf("received block %s\n", hashBlock.ToString().substr(0,20).c_str());
// block.print();
- CInv inv(MSG_BLOCK, block.GetHash());
+ CInv inv(MSG_BLOCK, hashBlock);
pfrom->AddInventoryKnown(inv);
if (ProcessBlock(pfrom, &block))
// (x) data
//
- loop
+ while (true)
{
// Don't bother if send buffer is too full to respond anyway
if (pfrom->vSend.size() >= SendBufferSize())
// fProofOfStake: try (best effort) to make a proof-of-stake block
CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake)
{
- CReserveKey reservekey(pwallet);
-
// Create new block
auto_ptr<CBlock> pblock(new CBlock());
if (!pblock.get())
txNew.vin.resize(1);
txNew.vin[0].prevout.SetNull();
txNew.vout.resize(1);
- txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+
+ if (!fProofOfStake)
+ {
+ CReserveKey reservekey(pwallet);
+ txNew.vout[0].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+ }
+ else
+ txNew.vout[0].SetEmpty();
// Add our coinbase tx as first transaction
pblock->vtx.push_back(txNew);
// Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));
- // Special compatibility rule before 20 Aug: limit size to 500,000 bytes:
- if (GetAdjustedTime() < LOCKS_SWITCH_TIME)
- nBlockMaxSize = std::min(nBlockMaxSize, (unsigned int)(MAX_BLOCK_SIZE_GEN));
-
// How much of the block should be dedicated to high-priority transactions,
// included regardless of the fees they pay
unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", 27000);
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);
}
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
{
- uint256 hash = pblock->GetHash();
+ uint256 hashBlock = pblock->GetHash();
uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
- if (hash > hashTarget && pblock->IsProofOfWork())
- return error("BitcoinMiner : proof-of-work not meeting target");
+ if(!pblock->IsProofOfWork())
+ return error("CheckWork() : %s is not a proof-of-work block", hashBlock.GetHex().c_str());
+
+ if (hashBlock > hashTarget)
+ return error("CheckWork() : proof-of-work not meeting target");
//// debug print
- printf("BitcoinMiner:\n");
- printf("new block found \n hash: %s \ntarget: %s\n", hash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ printf("CheckWork() : new proof-of-stake block found \n hash: %s \ntarget: %s\n", hashBlock.GetHex().c_str(), hashTarget.GetHex().c_str());
pblock->print();
printf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue).c_str());
{
LOCK(cs_main);
if (pblock->hashPrevBlock != hashBestChain)
- return error("BitcoinMiner : generated block is stale");
+ return error("CheckWork() : generated block is stale");
// Remove key from key pool
reservekey.KeepKey();
// Track how many getdata requests this block gets
{
LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
+ wallet.mapRequestCount[hashBlock] = 0;
+ }
+
+ // Process this block the same as if we had received it from another node
+ if (!ProcessBlock(NULL, pblock))
+ return error("CheckWork() : ProcessBlock, block not accepted");
+ }
+
+ return true;
+}
+
+bool CheckStake(CBlock* pblock, CWallet& wallet)
+{
+ uint256 proofHash = 0, hashTarget = 0;
+ uint256 hashBlock = pblock->GetHash();
+
+ if(!pblock->IsProofOfStake())
+ return error("CheckStake() : %s is not a proof-of-stake block", hashBlock.GetHex().c_str());
+
+ // verify hash target and signature of coinstake tx
+ if (!CheckProofOfStake(pblock->vtx[1], pblock->nBits, proofHash, hashTarget))
+ return error("CheckStake() : proof-of-stake checking failed");
+
+ //// debug print
+ printf("CheckStake() : new proof-of-stake block found \n hash: %s \nproofhash: %s \ntarget: %s\n", hashBlock.GetHex().c_str(), proofHash.GetHex().c_str(), hashTarget.GetHex().c_str());
+ pblock->print();
+ printf("out %s\n", FormatMoney(pblock->vtx[1].GetValueOut()).c_str());
+
+ // Found a solution
+ {
+ LOCK(cs_main);
+ if (pblock->hashPrevBlock != hashBestChain)
+ return error("CheckStake() : generated block is stale");
+
+ // Track how many getdata requests this block gets
+ {
+ LOCK(wallet.cs_wallet);
+ wallet.mapRequestCount[hashBlock] = 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");
+ return error("CheckStake() : ProcessBlock, block not accepted");
}
return true;
}
-void BitcoinMiner(CWallet *pwallet, bool fProofOfStake)
+void StakeMiner(CWallet *pwallet)
{
SetThreadPriority(THREAD_PRIORITY_LOWEST);
// Make this thread recognisable as the mining thread
- RenameThread("bitcoin-miner");
+ RenameThread("novacoin-miner");
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
+ // Each thread has its own counter
unsigned int nExtraNonce = 0;
- while (fProofOfStake)
+ while (true)
{
if (fShutdown)
return;
Sleep(1000);
if (fShutdown)
return;
- if (!fProofOfStake)
- return;
}
while (pwallet->IsLocked())
//
CBlockIndex* pindexPrev = pindexBest;
- auto_ptr<CBlock> pblock(CreateNewBlock(pwallet, fProofOfStake));
+ auto_ptr<CBlock> pblock(CreateNewBlock(pwallet, true));
if (!pblock.get())
return;
IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce);
- if (fProofOfStake)
+ if(pblock->IsProofOfStake())
{
- // ppcoin: if proof-of-stake block found then process block
- if (pblock->IsProofOfStake())
+ // Trying to sign a block
+ if (!pblock->SignBlock(*pwalletMain))
{
- if (!pblock->SignBlock(*pwalletMain))
- {
- strMintWarning = strMintMessage;
- continue;
- }
- strMintWarning = "";
- printf("StakeMiner : 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);
+ strMintWarning = strMintMessage;
+ continue;
}
- Sleep(500);
- continue;
+
+ strMintWarning = "";
+ SetThreadPriority(THREAD_PRIORITY_NORMAL);
+ CheckStake(pblock.get(), *pwalletMain);
+ SetThreadPriority(THREAD_PRIORITY_LOWEST);
}
+
+ Sleep(500);
+ continue;
}
}