1) Remove stakes verification code from CheckWork() function, create separate CheckStake() function.
2) Add -stakepooledkeys option, which allows user to get keys for the last coinstake output from keypool. This feature disabled by default.
" -bind=<addr> " + _("Bind to given address. Use [host]:port notation for IPv6") + "\n" +
" -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" +
" -nosynccheckpoints " + _("Disable sync checkpoints (default: 0)") + "\n" +
+ " -stakepooledkeys " + _("Use pooled pubkeys for the last coinstake output (default: 0)") + "\n" +
" -banscore=<n> " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
" -bantime=<n> " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
" -maxreceivebuffer=<n> " + _("Maximum per-connection receive buffer, <n>*1000 bytes (default: 5000)") + "\n" +
// ********************************************************* Step 2: parameter interactions
nNodeLifespan = GetArg("-addrlifespan", 7);
-
+ fStakeUsePooledKeys = GetBoolArg("-stakepooledkeys", false);
fTestNet = GetBoolArg("-testnet");
if (fTestNet) {
SoftSetBoolArg("-irc", true);
// quantities so as to generate blocks faster, degrading the system back into
// a proof-of-work situation.
//
-bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake)
+bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake)
{
if (nTimeTx < txPrev.nTime) // Transaction timestamp violation
return error("CheckStakeKernelHash() : nTime violation");
}
CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60);
+ targetProofOfStake = (bnCoinDayWeight * bnTargetPerCoinDay).getuint256();
// Calculate hash
CDataStream ss(SER_GETHASH, 0);
}
// Check kernel hash target and coinstake signature
-bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake)
+bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake)
{
if (!tx.IsCoinStake())
return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString().c_str());
if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false))
return fDebug? error("CheckProofOfStake() : read block failed") : false; // unable to read block of previous transaction
- if (!CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, txPrev, txin.prevout, tx.nTime, hashProofOfStake, fDebug))
+ if (!CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, txPrev, txin.prevout, tx.nTime, hashProofOfStake, targetProofOfStake, fDebug))
return tx.DoS(1, error("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx.GetHash().ToString().c_str(), hashProofOfStake.ToString().c_str())); // may occur during initial download or if behind on block chain sync
return true;
// Check whether stake kernel meets hash target
// Sets hashProofOfStake on success return
-bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake=false);
+bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, uint256& targetProofOfStake, bool fPrintProofOfStake=false);
// Check kernel hash target and coinstake signature
// Sets hashProofOfStake on success return
-bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake);
+bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hashProofOfStake, uint256& targetProofOfStake);
// Check whether the coinstake timestamp meets protocol
bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx);
// Settings
int64 nTransactionFee = MIN_TX_FEE;
-
+bool fStakeUsePooledKeys = false;
//////////////////////////////////////////////////////////////////////////////
//
// 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
// 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);
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);
}
uint256 hash = 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", hash.GetHex().c_str());
+
+ if (hash > 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", hash.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();
// 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("CheckWork() : ProcessBlock, block not accepted");
+ }
+
+ return true;
+}
+
+bool CheckStake(CBlock* pblock, CWallet& wallet)
+{
+ uint256 proofHash = 0, hashTarget = 0;
+ uint256 hash = pblock->GetHash();
+
+ if(!pblock->IsProofOfStake())
+ return error("CheckStake() : %s is not a proof-of-stake block", hash.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", hash.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[pblock->GetHash()] = 0;
+ }
+
+ // Process this block the same as if we had received it from another node
+ if (!ProcessBlock(NULL, pblock))
+ return error("CheckStake() : ProcessBlock, block not accepted");
}
return true;
// Make this thread recognisable as the mining thread
RenameThread("bitcoin-miner");
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
+ // Each thread has its own counter
unsigned int nExtraNonce = 0;
while (fProofOfStake)
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;
}
}
// Settings
extern int64 nTransactionFee;
+extern bool fStakeUsePooledKeys;
// Minimum disk space required - used in CheckDiskSpace()
static const uint64 nMinDiskSpace = 52428800;
void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1);
bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey);
+bool CheckStake(CBlock* pblock, CWallet& wallet);
bool CheckProofOfWork(uint256 hash, unsigned int nBits);
int64 GetProofOfWorkReward(unsigned int nBits);
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, bool bCoinYearOnly=false);
{
// Search backward in time from the given txNew timestamp
// Search nSearchInterval seconds back up to nMaxStakeSearchInterval
- uint256 hashProofOfStake = 0;
+ uint256 hashProofOfStake = 0, targetProofOfStake = 0;
COutPoint prevoutStake = COutPoint(pcoin.first->GetHash(), pcoin.second);
- if (CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake))
+ if (CheckStakeKernelHash(nBits, block, txindex.pos.nTxPos - txindex.pos.nBlockPos, *pcoin.first, prevoutStake, txNew.nTime - n, hashProofOfStake, targetProofOfStake))
{
// Found a kernel
if (fDebug && GetBoolArg("-printcoinstake"))
// Set output amount
if (txNew.vout.size() == 3)
{
+ // Should we use keys from pool for the last coinstake output?
+ if (fStakeUsePooledKeys)
+ {
+ CReserveKey reservekey((CWallet*) &keystore);
+
+ // Replace current key with the new one
+ txNew.vout[2].SetNull();
+ txNew.vout[2].scriptPubKey << reservekey.GetReservedKey() << OP_CHECKSIG;
+
+ // Remove key from pool
+ reservekey.KeepKey();
+ }
+
txNew.vout[1].nValue = ((nCredit - nMinFee) / 2 / CENT) * CENT;
txNew.vout[2].nValue = nCredit - nMinFee - txNew.vout[1].nValue;
}