PPCoin: Rework stake minting to use randomized stake timestamp
authorSunny King <sunnyking9999@gmail.com>
Sat, 15 Sep 2012 02:05:18 +0000 (03:05 +0100)
committerSunny King <sunnyking9999@gmail.com>
Sat, 15 Sep 2012 02:05:18 +0000 (03:05 +0100)
src/bitcoinrpc.cpp
src/main.cpp
src/wallet.cpp
src/wallet.h

index e469e4e..3e32295 100644 (file)
@@ -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)
index d9039f8..2d5ee04 100644 (file)
@@ -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))
index f070d65..de203bc 100644 (file)
@@ -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<valtype> 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<valtype> 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;
index c7380e3..4750a6b 100644 (file)
@@ -152,7 +152,7 @@ public:
     int64 GetNewMint() const;
     bool CreateTransaction(const std::vector<std::pair<CScript, int64> >& 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);