From 2a7d702d81cf4d5afdcba80a25005196feb39282 Mon Sep 17 00:00:00 2001 From: Sunny King Date: Sat, 15 Sep 2012 03:05:18 +0100 Subject: [PATCH] PPCoin: Rework stake minting to use randomized stake timestamp --- src/bitcoinrpc.cpp | 1 + src/main.cpp | 30 +++++----------- src/wallet.cpp | 95 ++++++++++++++++++++++++++++----------------------- src/wallet.h | 2 +- 4 files changed, 63 insertions(+), 65 deletions(-) diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index e469e4e..3e32295 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -159,6 +159,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool fPri if (fPrintTransactionDetail) { txinfo.push_back(tx.ToStringShort()); + txinfo.push_back(DateTimeStrFormat(tx.nTime)); BOOST_FOREACH(const CTxIn& txin, tx.vin) txinfo.push_back(txin.ToStringShort()); BOOST_FOREACH(const CTxOut& txout, tx.vout) diff --git a/src/main.cpp b/src/main.cpp index d9039f8..2d5ee04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3621,32 +3621,20 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) 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 (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake)) { - 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(*pwallet, pblock->nBits, txCoinStake)) - { - pblock->vtx.push_back(txCoinStake); - pblock->vtx[0].vout[0].SetEmpty(); - break; - } + pblock->vtx.push_back(txCoinStake); + pblock->vtx[0].vout[0].SetEmpty(); } + nLastCoinStakeSearchTime = nSearchTime; } pblock->nBits = GetNextTargetRequired(pindexPrev, pblock->IsProofOfStake()); @@ -3956,9 +3944,9 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) 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)) diff --git a/src/wallet.cpp b/src/wallet.cpp index f070d65..de203bc 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1203,7 +1203,7 @@ bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& w } // ppcoin: create coin stake transaction -bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, CTransaction& txNew) +bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64 nSearchInterval, CTransaction& txNew) { // The following split & combine thresholds are important to security // Should not be adjusted if you don't understand the consequences @@ -1252,57 +1252,66 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, CTr int64 nValueIn = pcoin.first->vout[pcoin.second].nValue; CBigNum bnCoinDay = CBigNum(nValueIn) * min(txNew.nTime-pcoin.first->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) << pcoin.first->nTime << pcoin.second << txNew.nTime; - if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) + + bool fKernelFound = false; + for (int n=0; n<5 && !fKernelFound; n++) { - // Found a kernel - if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : kernel found\n"); - vector vSolutions; - txnouttype whichType; - CScript scriptPubKeyOut; - scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey; - if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) + // Randomly pick a timestamp from protocol allowed range + txNew.nTime = GetAdjustedTime() - GetRandInt(60 * 60 * 2 - 60); + // Calculate hash + CDataStream ss(SER_GETHASH, 0); + ss << nBits << block.nTime << (txindex.pos.nTxPos - txindex.pos.nBlockPos) << pcoin.first->nTime << pcoin.second << txNew.nTime; + if (CBigNum(Hash(ss.begin(), ss.end())) <= bnCoinDay * bnTargetPerCoinDay) { + // Found a kernel if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : failed to parse kernel\n", whichType); - continue; - } - if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : parsed kernel type=%d\n", whichType); - if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH) - { + printf("CreateCoinStake : kernel found\n"); + vector vSolutions; + txnouttype whichType; + CScript scriptPubKeyOut; + scriptPubKeyKernel = pcoin.first->vout[pcoin.second].scriptPubKey; + if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) + { + if (fDebug && GetBoolArg("-printcoinstake")) + printf("CreateCoinStake : failed to parse kernel\n", whichType); + break; + } if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : no support for kernel type=%d\n", whichType); - continue; // only support pay to public key and pay to address - } - if (whichType == TX_PUBKEYHASH) // pay to address type - { - // convert to pay to public key type - CKey key; - if (!keystore.GetKey(uint160(vSolutions[0]), key)) + printf("CreateCoinStake : parsed kernel type=%d\n", whichType); + if (whichType != TX_PUBKEY && whichType != TX_PUBKEYHASH) { if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType); - continue; // unable to find corresponding public key + printf("CreateCoinStake : no support for kernel type=%d\n", whichType); + break; // only support pay to public key and pay to address } - scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; + if (whichType == TX_PUBKEYHASH) // pay to address type + { + // convert to pay to public key type + CKey key; + if (!keystore.GetKey(uint160(vSolutions[0]), key)) + { + if (fDebug && GetBoolArg("-printcoinstake")) + printf("CreateCoinStake : failed to get key for kernel type=%d\n", whichType); + break; // unable to find corresponding public key + } + scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; + } + else + scriptPubKeyOut = scriptPubKeyKernel; + + txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); + nCredit += pcoin.first->vout[pcoin.second].nValue; + vwtxPrev.push_back(pcoin.first); + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); + if (block.GetBlockTime() + nStakeSplitAge > txNew.nTime) + txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake + if (fDebug && GetBoolArg("-printcoinstake")) + printf("CreateCoinStake : added kernel type=%d\n", whichType); + fKernelFound = true; } - else - scriptPubKeyOut = scriptPubKeyKernel; - - txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); - nCredit += pcoin.first->vout[pcoin.second].nValue; - vwtxPrev.push_back(pcoin.first); - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); - if (block.GetBlockTime() + nStakeSplitAge > txNew.nTime) - txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake - if (fDebug && GetBoolArg("-printcoinstake")) - printf("CreateCoinStake : added kernel type=%d\n", whichType); - break; } + if (fKernelFound) + break; // if kernel is found stop searching } if (nCredit == 0 || nCredit > nBalance - nReserveBalance) return false; diff --git a/src/wallet.h b/src/wallet.h index c7380e3..4750a6b 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -152,7 +152,7 @@ public: int64 GetNewMint() const; bool CreateTransaction(const std::vector >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet); - bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, CTransaction& txNew); + bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64 nSearchInterval, CTransaction& txNew); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); -- 1.7.1