X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fmain.h;h=2811ec17e47a5a53fcaebd9678f111a72613e89a;hb=1459c6b59d0a20e6b0e042c868461f176d4e75f5;hp=411777349a69a65a98995d890db0f02fdfd70e4d;hpb=1512d5ce64b9a53260f5aa695bc79a0e48d6294f;p=novacoin.git diff --git a/src/main.h b/src/main.h index 4117773..2811ec1 100644 --- a/src/main.h +++ b/src/main.h @@ -1,4 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011-2012 The PPCoin developers // Distributed under the MIT/X11 software license, see the accompanying // file license.txt or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_MAIN_H @@ -7,38 +9,45 @@ #include "bignum.h" #include "net.h" #include "key.h" -#include "db.h" #include "script.h" +#include "db.h" #include -class COutPoint; -class CInPoint; -class CDiskTxPos; -class CCoinBase; -class CTxIn; -class CTxOut; -class CTransaction; class CBlock; class CBlockIndex; class CWalletTx; +class CWallet; class CKeyItem; +class CReserveKey; +class CWalletDB; + +class CAddress; +class CInv; +class CRequestTracker; +class CNode; +class CBlockIndex; static const unsigned int MAX_BLOCK_SIZE = 1000000; static const unsigned int MAX_BLOCK_SIZE_GEN = MAX_BLOCK_SIZE/2; static const int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50; -static const int64 COIN = 100000000; -static const int64 CENT = 1000000; -static const int64 MIN_TX_FEE = 50000; -static const int64 MAX_MONEY = 21000000 * COIN; +static const int64 COIN = 1000000; +static const int64 CENT = 10000; +static const int64 MIN_TX_FEE = 10000; +static const int64 MIN_RELAY_TX_FEE = 10000; +static const int64 MAX_MONEY = 2000000000 * COIN; inline bool MoneyRange(int64 nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } static const int COINBASE_MATURITY = 100; +// Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. +static const int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC #ifdef USE_UPNP static const int fHaveUPnP = true; #else static const int fHaveUPnP = false; #endif +static const uint256 hashGenesisBlockOfficial("0x000000007c82d1f0aa2896b01bf533a8cc26a1f44790be4ceb4ecde7bee24add"); +static const uint256 hashGenesisBlockTestNet("0x00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"); @@ -46,32 +55,31 @@ static const int fHaveUPnP = false; extern CCriticalSection cs_main; extern std::map mapBlockIndex; +extern std::set > setStakeSeen; extern uint256 hashGenesisBlock; -extern CBigNum bnProofOfWorkLimit; extern CBlockIndex* pindexGenesisBlock; extern int nBestHeight; -extern CBigNum bnBestChainWork; -extern CBigNum bnBestInvalidWork; +extern uint64 nBestChainTrust; +extern uint64 nBestInvalidTrust; extern uint256 hashBestChain; extern CBlockIndex* pindexBest; extern unsigned int nTransactionsUpdated; -extern std::map mapRequestCount; -extern CCriticalSection cs_mapRequestCount; -extern std::map mapAddressBook; -extern CCriticalSection cs_mapAddressBook; -extern std::vector vchDefaultKey; extern double dHashesPerSec; extern int64 nHPSTimerStart; +extern int64 nTimeBestReceived; +extern CCriticalSection cs_setpwalletRegistered; +extern std::set setpwalletRegistered; +extern std::map mapOrphanBlocks; // Settings extern int fGenerateBitcoins; extern int64 nTransactionFee; -extern CAddress addrIncoming; extern int fLimitProcessors; extern int nLimitProcessors; extern int fMinimizeToTray; extern int fMinimizeOnClose; extern int fUseUPnP; +extern int64 nBalanceReserve; @@ -81,38 +89,30 @@ class CReserveKey; class CTxDB; class CTxIndex; - +void RegisterWallet(CWallet* pwalletIn); +void UnregisterWallet(CWallet* pwalletIn); +bool ProcessBlock(CNode* pfrom, CBlock* pblock); bool CheckDiskSpace(uint64 nAdditionalBytes=0); FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode="rb"); FILE* AppendBlockFile(unsigned int& nFileRet); -bool AddKey(const CKey& key); -std::vector GenerateNewKey(); -bool AddToWallet(const CWalletTx& wtxIn); -void WalletUpdateSpent(const COutPoint& prevout); -int ScanForWalletTransactions(CBlockIndex* pindexStart); -void ReacceptWalletTransactions(); bool LoadBlockIndex(bool fAllowNew=true); void PrintBlockTree(); bool ProcessMessages(CNode* pfrom); -bool ProcessMessage(CNode* pfrom, std::string strCommand, CDataStream& vRecv); bool SendMessages(CNode* pto, bool fSendTrickle); -int64 GetBalance(); -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 CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); -bool BroadcastTransaction(CWalletTx& wtxNew); -std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); -std::string SendMoneyToBitcoinAddress(std::string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); -void GenerateBitcoins(bool fGenerate); -void ThreadBitcoinMiner(void* parg); -CBlock* CreateNewBlock(CReserveKey& reservekey); -void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce, int64& nPrevTime); +void GenerateBitcoins(bool fGenerate, CWallet* pwallet); +CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfWorkOnly=false); +void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce); void FormatHashBuffers(CBlock* pblock, char* pmidstate, char* pdata, char* phash1); -bool CheckWork(CBlock* pblock, CReserveKey& reservekey); -void BitcoinMiner(); +bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey); bool CheckProofOfWork(uint256 hash, unsigned int nBits); +int64 GetProofOfStakeReward(int64 nCoinAge); +unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); +int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); +bool Reorganize(CTxDB& txdb, CBlockIndex* pindexNew); +uint256 WantedByOrphan(const CBlock* pblockOrphan); +const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); @@ -124,6 +124,22 @@ std::string GetWarnings(std::string strFor); +bool GetWalletFile(CWallet* pwallet, std::string &strWalletFileOut); + +template +bool WriteSetting(const std::string& strKey, const T& value) +{ + bool fOk = false; + BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) + { + std::string strWalletFile; + if (!GetWalletFile(pwallet, strWalletFile)) + continue; + fOk |= CWalletDB(strWalletFile).WriteSetting(strKey, value); + } + return fOk; +} + class CDiskTxPos { @@ -307,9 +323,6 @@ public: { printf("%s\n", ToString().c_str()); } - - bool IsMine() const; - int64 GetDebit() const; }; @@ -353,39 +366,20 @@ public: return (nValue == -1); } - uint256 GetHash() const - { - return SerializeHash(*this); - } - - bool IsMine() const + bool SetEmpty() { - return ::IsMine(scriptPubKey); + nValue = 0; + scriptPubKey.clear(); } - int64 GetCredit() const + bool IsEmpty() const { - if (!MoneyRange(nValue)) - throw std::runtime_error("CTxOut::GetCredit() : value out of range"); - return (IsMine() ? nValue : 0); + return (nValue == 0 && scriptPubKey.empty()); } - bool IsChange() const - { - // On a debit transaction, a txout that's mine but isn't in the address book is change - std::vector vchPubKey; - if (ExtractPubKey(scriptPubKey, true, vchPubKey)) - CRITICAL_BLOCK(cs_mapAddressBook) - if (!mapAddressBook.count(PubKeyToAddress(vchPubKey))) - return true; - return false; - } - - int64 GetChange() const + uint256 GetHash() const { - if (!MoneyRange(nValue)) - throw std::runtime_error("CTxOut::GetChange() : value out of range"); - return (IsChange() ? nValue : 0); + return SerializeHash(*this); } friend bool operator==(const CTxOut& a, const CTxOut& b) @@ -401,9 +395,10 @@ public: std::string ToString() const { + if (IsEmpty()) return "CTxOut(empty)"; if (scriptPubKey.size() < 6) return "CTxOut(error)"; - return strprintf("CTxOut(nValue=%"PRI64d".%08"PRI64d", scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30).c_str()); + return strprintf("CTxOut(nValue=%s, scriptPubKey=%s)", FormatMoney(nValue).c_str(), scriptPubKey.ToString().substr(0,30).c_str()); } void print() const @@ -423,10 +418,14 @@ class CTransaction { public: int nVersion; + unsigned int nTime; std::vector vin; std::vector vout; unsigned int nLockTime; + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CTransaction() { @@ -437,6 +436,7 @@ public: ( READWRITE(this->nVersion); nVersion = this->nVersion; + READWRITE(nTime); READWRITE(vin); READWRITE(vout); READWRITE(nLockTime); @@ -445,9 +445,11 @@ public: void SetNull() { nVersion = 1; + nTime = GetAdjustedTime(); vin.clear(); vout.clear(); nLockTime = 0; + nDoS = 0; // Denial-of-service prevention } bool IsNull() const @@ -469,7 +471,7 @@ public: nBlockHeight = nBestHeight; if (nBlockTime == 0) nBlockTime = GetAdjustedTime(); - if ((int64)nLockTime < (nLockTime < 500000000 ? (int64)nBlockHeight : nBlockTime)) + if ((int64)nLockTime < (nLockTime < LOCKTIME_THRESHOLD ? (int64)nBlockHeight : nBlockTime)) return true; BOOST_FOREACH(const CTxIn& txin, vin) if (!txin.IsFinal()) @@ -508,7 +510,13 @@ public: bool IsCoinBase() const { - return (vin.size() == 1 && vin[0].prevout.IsNull()); + return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() == 1); + } + + bool IsCoinStake() const + { + // ppcoin: the coin stake transaction is marked with the first output empty + return (vin.size() > 0 && vout.size() == 2 && vout[0].IsEmpty()); } int GetSigOpCount() const @@ -532,57 +540,6 @@ public: return true; } - bool IsMine() const - { - BOOST_FOREACH(const CTxOut& txout, vout) - if (txout.IsMine()) - return true; - return false; - } - - bool IsFromMe() const - { - return (GetDebit() > 0); - } - - int64 GetDebit() const - { - int64 nDebit = 0; - BOOST_FOREACH(const CTxIn& txin, vin) - { - nDebit += txin.GetDebit(); - if (!MoneyRange(nDebit)) - throw std::runtime_error("CTransaction::GetDebit() : value out of range"); - } - return nDebit; - } - - int64 GetCredit() const - { - int64 nCredit = 0; - BOOST_FOREACH(const CTxOut& txout, vout) - { - nCredit += txout.GetCredit(); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CTransaction::GetCredit() : value out of range"); - } - return nCredit; - } - - int64 GetChange() const - { - if (IsCoinBase()) - return 0; - int64 nChange = 0; - BOOST_FOREACH(const CTxOut& txout, vout) - { - nChange += txout.GetChange(); - if (!MoneyRange(nChange)) - throw std::runtime_error("CTransaction::GetChange() : value out of range"); - } - return nChange; - } - int64 GetValueOut() const { int64 nValueOut = 0; @@ -602,12 +559,14 @@ public: return dPriority > COIN * 144 / 250; } - int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=true) const + int64 GetMinFee(unsigned int nBlockSize=1, bool fAllowFree=false, bool fForRelay=false) const { - // Base fee is 1 cent per kilobyte + // Base fee is either MIN_TX_FEE or MIN_RELAY_TX_FEE + int64 nBaseFee = fForRelay ? MIN_RELAY_TX_FEE : MIN_TX_FEE; + unsigned int nBytes = ::GetSerializeSize(*this, SER_NETWORK); unsigned int nNewBlockSize = nBlockSize + nBytes; - int64 nMinFee = (1 + (int64)nBytes / 1000) * MIN_TX_FEE; + int64 nMinFee = (1 + (int64)nBytes / 1000) * nBaseFee; if (fAllowFree) { @@ -626,11 +585,11 @@ public: } } - // To limit dust spam, require MIN_TX_FEE if any output is less than 0.01 - if (nMinFee < MIN_TX_FEE) + // To limit dust spam, require MIN_TX_FEE/MIN_RELAY_TX_FEE if any output is less than 0.01 + if (nMinFee < nBaseFee) BOOST_FOREACH(const CTxOut& txout, vout) if (txout.nValue < CENT) - nMinFee = MIN_TX_FEE; + nMinFee = nBaseFee; // Raise the price as the block approaches full if (nBlockSize != 1 && nNewBlockSize >= MAX_BLOCK_SIZE_GEN/2) @@ -670,6 +629,7 @@ public: friend bool operator==(const CTransaction& a, const CTransaction& b) { return (a.nVersion == b.nVersion && + a.nTime == b.nTime && a.vin == b.vin && a.vout == b.vout && a.nLockTime == b.nLockTime); @@ -684,8 +644,10 @@ public: std::string ToString() const { std::string str; - str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n", + str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction"); + str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%d, vout.size=%d, nLockTime=%d)\n", GetHash().ToString().substr(0,10).c_str(), + nTime, nVersion, vin.size(), vout.size(), @@ -712,15 +674,13 @@ public: bool ClientConnectInputs(); bool CheckTransaction() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); - bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL) - { - CTxDB txdb("r"); - return AcceptToMemoryPool(txdb, fCheckInputs, pfMissingInputs); - } + bool AcceptToMemoryPool(bool fCheckInputs=true, bool* pfMissingInputs=NULL); protected: bool AddToMemoryPoolUnchecked(); public: bool RemoveFromMemoryPool(); + bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // ppcoin: get transaction coin age + bool CheckProofOfStake(unsigned int nBits) const; }; @@ -775,307 +735,7 @@ public: bool IsInMainChain() const { return GetDepthInMainChain() > 0; } int GetBlocksToMaturity() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true); - bool AcceptToMemoryPool() { CTxDB txdb("r"); return AcceptToMemoryPool(txdb); } -}; - - - - -// -// A transaction with a bunch of additional info that only the owner cares -// about. It includes any unrecorded transactions needed to link it back -// to the block chain. -// -class CWalletTx : public CMerkleTx -{ -public: - std::vector vtxPrev; - std::map mapValue; - std::vector > vOrderForm; - unsigned int fTimeReceivedIsTxTime; - unsigned int nTimeReceived; // time received by this node - char fFromMe; - std::string strFromAccount; - std::vector vfSpent; - - // memory only - mutable char fDebitCached; - mutable char fCreditCached; - mutable char fAvailableCreditCached; - mutable char fChangeCached; - mutable int64 nDebitCached; - mutable int64 nCreditCached; - mutable int64 nAvailableCreditCached; - mutable int64 nChangeCached; - - // memory only UI hints - mutable unsigned int nTimeDisplayed; - mutable int nLinesDisplayed; - mutable char fConfirmedDisplayed; - - - CWalletTx() - { - Init(); - } - - CWalletTx(const CMerkleTx& txIn) : CMerkleTx(txIn) - { - Init(); - } - - CWalletTx(const CTransaction& txIn) : CMerkleTx(txIn) - { - Init(); - } - - void Init() - { - vtxPrev.clear(); - mapValue.clear(); - vOrderForm.clear(); - fTimeReceivedIsTxTime = false; - nTimeReceived = 0; - fFromMe = false; - strFromAccount.clear(); - vfSpent.clear(); - fDebitCached = false; - fCreditCached = false; - fAvailableCreditCached = false; - fChangeCached = false; - nDebitCached = 0; - nCreditCached = 0; - nAvailableCreditCached = 0; - nChangeCached = 0; - nTimeDisplayed = 0; - nLinesDisplayed = 0; - fConfirmedDisplayed = false; - } - - IMPLEMENT_SERIALIZE - ( - CWalletTx* pthis = const_cast(this); - if (fRead) - pthis->Init(); - char fSpent = false; - - if (!fRead) - { - pthis->mapValue["fromaccount"] = pthis->strFromAccount; - - std::string str; - BOOST_FOREACH(char f, vfSpent) - { - str += (f ? '1' : '0'); - if (f) - fSpent = true; - } - pthis->mapValue["spent"] = str; - } - - nSerSize += SerReadWrite(s, *(CMerkleTx*)this, nType, nVersion,ser_action); - READWRITE(vtxPrev); - READWRITE(mapValue); - READWRITE(vOrderForm); - READWRITE(fTimeReceivedIsTxTime); - READWRITE(nTimeReceived); - READWRITE(fFromMe); - READWRITE(fSpent); - - if (fRead) - { - pthis->strFromAccount = pthis->mapValue["fromaccount"]; - - if (mapValue.count("spent")) - BOOST_FOREACH(char c, pthis->mapValue["spent"]) - pthis->vfSpent.push_back(c != '0'); - else - pthis->vfSpent.assign(vout.size(), fSpent); - } - - pthis->mapValue.erase("fromaccount"); - pthis->mapValue.erase("version"); - pthis->mapValue.erase("spent"); - ) - - // marks certain txout's as spent - // returns true if any update took place - bool UpdateSpent(const std::vector& vfNewSpent) - { - bool fReturn = false; - for (int i=0; i < vfNewSpent.size(); i++) - { - if (i == vfSpent.size()) - break; - - if (vfNewSpent[i] && !vfSpent[i]) - { - vfSpent[i] = true; - fReturn = true; - fAvailableCreditCached = false; - } - } - return fReturn; - } - - void MarkDirty() - { - fCreditCached = false; - fAvailableCreditCached = false; - fDebitCached = false; - fChangeCached = false; - } - - void MarkSpent(unsigned int nOut) - { - if (nOut >= vout.size()) - throw std::runtime_error("CWalletTx::MarkSpent() : nOut out of range"); - vfSpent.resize(vout.size()); - if (!vfSpent[nOut]) - { - vfSpent[nOut] = true; - fAvailableCreditCached = false; - } - } - - bool IsSpent(unsigned int nOut) const - { - if (nOut >= vout.size()) - throw std::runtime_error("CWalletTx::IsSpent() : nOut out of range"); - if (nOut >= vfSpent.size()) - return false; - return (!!vfSpent[nOut]); - } - - int64 GetDebit() const - { - if (vin.empty()) - return 0; - if (fDebitCached) - return nDebitCached; - nDebitCached = CTransaction::GetDebit(); - fDebitCached = true; - return nDebitCached; - } - - int64 GetCredit(bool fUseCache=true) const - { - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - // GetBalance can assume transactions in mapWallet won't change - if (fUseCache && fCreditCached) - return nCreditCached; - nCreditCached = CTransaction::GetCredit(); - fCreditCached = true; - return nCreditCached; - } - - int64 GetAvailableCredit(bool fUseCache=true) const - { - // Must wait until coinbase is safely deep enough in the chain before valuing it - if (IsCoinBase() && GetBlocksToMaturity() > 0) - return 0; - - if (fUseCache && fAvailableCreditCached) - return nAvailableCreditCached; - - int64 nCredit = 0; - for (int i = 0; i < vout.size(); i++) - { - if (!IsSpent(i)) - { - const CTxOut &txout = vout[i]; - nCredit += txout.GetCredit(); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWalletTx::GetAvailableCredit() : value out of range"); - } - } - - nAvailableCreditCached = nCredit; - fAvailableCreditCached = true; - return nCredit; - } - - - int64 GetChange() const - { - if (fChangeCached) - return nChangeCached; - nChangeCached = CTransaction::GetChange(); - fChangeCached = true; - return nChangeCached; - } - - void GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, std::list >& listReceived, - std::list >& listSent, int64& nFee, std::string& strSentAccount) const; - - void GetAccountAmounts(const std::string& strAccount, int64& nGenerated, int64& nReceived, - int64& nSent, int64& nFee) const; - - bool IsFromMe() const - { - return (GetDebit() > 0); - } - - bool IsConfirmed() const - { - // Quick answer in most cases - if (!IsFinal()) - return false; - if (GetDepthInMainChain() >= 1) - return true; - if (!IsFromMe()) // using wtx's cached debit - return false; - - // If no confirmations but it's from us, we can still - // consider it confirmed if all dependencies are confirmed - std::map mapPrev; - std::vector vWorkQueue; - vWorkQueue.reserve(vtxPrev.size()+1); - vWorkQueue.push_back(this); - for (int i = 0; i < vWorkQueue.size(); i++) - { - const CMerkleTx* ptx = vWorkQueue[i]; - - if (!ptx->IsFinal()) - return false; - if (ptx->GetDepthInMainChain() >= 1) - continue; - if (!ptx->IsFromMe()) - return false; - - if (mapPrev.empty()) - BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) - mapPrev[tx.GetHash()] = &tx; - - BOOST_FOREACH(const CTxIn& txin, ptx->vin) - { - if (!mapPrev.count(txin.prevout.hash)) - return false; - vWorkQueue.push_back(mapPrev[txin.prevout.hash]); - } - } - return true; - } - - bool WriteToDisk() - { - return CWalletDB().WriteTx(GetHash(), *this); - } - - - int64 GetTxTime() const; - int GetRequestCount() const; - - void AddSupportingTransactions(CTxDB& txdb); - - bool AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs=true); - bool AcceptWalletTransaction() { CTxDB txdb("r"); return AcceptWalletTransaction(txdb); } - - void RelayWalletTransaction(CTxDB& txdb); - void RelayWalletTransaction() { CTxDB txdb("r"); RelayWalletTransaction(txdb); } + bool AcceptToMemoryPool(); }; @@ -1164,9 +824,15 @@ public: // network and disk std::vector vtx; + // ppcoin: block signature - signed by coin base txout[0]'s owner + std::vector vchBlockSig; + // memory only mutable std::vector vMerkleTree; + // Denial-of-service detection: + mutable int nDoS; + bool DoS(int nDoSIn, bool fIn) const { nDoS += nDoSIn; return fIn; } CBlock() { @@ -1183,11 +849,17 @@ public: READWRITE(nBits); READWRITE(nNonce); - // ConnectBlock depends on vtx being last so it can calculate offset + // ConnectBlock depends on vtx following header to generate CDiskTxPos if (!(nType & (SER_GETHASH|SER_BLOCKHEADERONLY))) + { READWRITE(vtx); + READWRITE(vchBlockSig); + } else if (fRead) + { const_cast(this)->vtx.clear(); + const_cast(this)->vchBlockSig.clear(); + } ) void SetNull() @@ -1199,7 +871,9 @@ public: nBits = 0; nNonce = 0; vtx.clear(); + vchBlockSig.clear(); vMerkleTree.clear(); + nDoS = 0; } bool IsNull() const @@ -1217,6 +891,31 @@ public: return (int64)nTime; } + // ppcoin: two types of block: proof-of-work or proof-of-stake + bool IsProofOfStake() const + { + return (vtx.size() > 1 && vtx[1].IsCoinStake()); + } + + bool IsProofOfWork() const + { + return !IsProofOfStake(); + } + + std::pair GetProofOfStake() const + { + return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0); + } + + // ppcoin: get max transaction timestamp + int64 GetMaxTransactionTime() const + { + int64 maxTransactionTime = 0; + BOOST_FOREACH(const CTransaction& tx, vtx) + maxTransactionTime = std::max(maxTransactionTime, (int64)tx.nTime); + return maxTransactionTime; + } + int GetSigOpCount() const { int n = 0; @@ -1298,7 +997,7 @@ public: fflush(fileout); if (!IsInitialBlockDownload() || (nBestHeight+1) % 500 == 0) { -#ifdef __WXMSW__ +#ifdef WIN32 _commit(_fileno(fileout)); #else fsync(fileno(fileout)); @@ -1323,7 +1022,7 @@ public: filein >> *this; // Check the header - if (!CheckProofOfWork(GetHash(), nBits)) + if (fReadTransactions && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) return error("CBlock::ReadFromDisk() : errors in block header"); return true; @@ -1333,13 +1032,14 @@ public: void print() const { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d)\n", + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%d, vchBlockSig=%s)\n", GetHash().ToString().substr(0,20).c_str(), nVersion, hashPrevBlock.ToString().substr(0,20).c_str(), hashMerkleRoot.ToString().substr(0,10).c_str(), nTime, nBits, nNonce, - vtx.size()); + vtx.size(), + HexStr(vchBlockSig.begin(), vchBlockSig.end()).c_str()); for (int i = 0; i < vtx.size(); i++) { printf(" "); @@ -1352,6 +1052,56 @@ public: } + bool SignBlock(const CKeyStore& keystore) + { + std::vector > vSolution; + const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0]; + + if (!Solver(txout.scriptPubKey, vSolution)) + return false; + BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) + { + if (item.first == OP_PUBKEY) + { + // Sign + const valtype& vchPubKey = item.second; + CKey key; + if (!keystore.GetKey(Hash160(vchPubKey), key)) + return false; + if (key.GetPubKey() != vchPubKey) + return false; + return key.Sign(GetHash(), vchBlockSig); + } + } + return false; + } + + bool CheckBlockSignature() const + { + if (GetHash() == hashGenesisBlock) + return vchBlockSig.empty(); + + std::vector > vSolution; + const CTxOut& txout = IsProofOfStake()? vtx[1].vout[1] : vtx[0].vout[0]; + + if (!Solver(txout.scriptPubKey, vSolution)) + return false; + BOOST_FOREACH(PAIRTYPE(opcodetype, valtype)& item, vSolution) + { + if (item.first == OP_PUBKEY) + { + const valtype& vchPubKey = item.second; + CKey key; + if (!key.SetPubKey(vchPubKey)) + return false; + if (vchBlockSig.empty()) + return false; + return key.Verify(GetHash(), vchBlockSig); + } + } + return false; + } + bool DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex); bool ConnectBlock(CTxDB& txdb, CBlockIndex* pindex); bool ReadFromDisk(const CBlockIndex* pindex, bool fReadTransactions=true); @@ -1359,6 +1109,7 @@ public: bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); bool CheckBlock() const; bool AcceptBlock(); + bool GetCoinAge(uint64& nCoinAge) const; // ppcoin: calculate total coin age spent in block }; @@ -1382,8 +1133,11 @@ public: CBlockIndex* pnext; unsigned int nFile; unsigned int nBlockPos; + uint64 nChainTrust;// ppcoin: trust score of chain, in the unit of coin-days int nHeight; - CBigNum bnChainWork; + bool fProofOfStake; // ppcoin: is the block of proof-of-stake type + COutPoint prevoutStake; + unsigned int nStakeTime; // block header int nVersion; @@ -1401,7 +1155,10 @@ public: nFile = 0; nBlockPos = 0; nHeight = 0; - bnChainWork = 0; + nChainTrust = 0; + fProofOfStake = true; + prevoutStake.SetNull(); + nStakeTime = 0; nVersion = 0; hashMerkleRoot = 0; @@ -1418,7 +1175,18 @@ public: nFile = nFileIn; nBlockPos = nBlockPosIn; nHeight = 0; - bnChainWork = 0; + nChainTrust = 0; + fProofOfStake = block.IsProofOfStake(); + if (fProofOfStake) + { + prevoutStake = block.vtx[1].vin[0].prevout; + nStakeTime = block.vtx[1].nTime; + } + else + { + prevoutStake.SetNull(); + nStakeTime = 0; + } nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1450,13 +1218,9 @@ public: return (int64)nTime; } - CBigNum GetBlockWork() const + int64 GetBlockTrust() const { - CBigNum bnTarget; - bnTarget.SetCompact(nBits); - if (bnTarget <= 0) - return 0; - return (CBigNum(1)<<256) / (bnTarget+1); + return (nChainTrust - (pprev? pprev->nChainTrust : 0)); } bool IsInMainChain() const @@ -1466,7 +1230,7 @@ public: bool CheckIndex() const { - return CheckProofOfWork(GetBlockHash(), nBits); + return IsProofOfWork() ? CheckProofOfWork(GetBlockHash(), nBits) : true; } bool EraseBlockFromDisk() @@ -1512,12 +1276,21 @@ public: return pindex->GetMedianTimePast(); } + bool IsProofOfWork() const + { + return !fProofOfStake; + } + bool IsProofOfStake() const + { + return fProofOfStake; + } std::string ToString() const { - return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, pnext, nFile, nBlockPos, nHeight, + return strprintf("CBlockIndex(nprev=%08x, pnext=%08x, nFile=%d, nBlockPos=%-6d nChainTrust=%"PRI64d" nHeight=%d, fProofOfStake=%d prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", + pprev, pnext, nFile, nBlockPos, nChainTrust, nHeight, + fProofOfStake, prevoutStake.ToString().c_str(), nStakeTime, hashMerkleRoot.ToString().substr(0,10).c_str(), GetBlockHash().ToString().substr(0,20).c_str()); } @@ -1559,7 +1332,19 @@ public: READWRITE(hashNext); READWRITE(nFile); READWRITE(nBlockPos); + READWRITE(nChainTrust); READWRITE(nHeight); + READWRITE(fProofOfStake); + if (fProofOfStake) + { + READWRITE(prevoutStake); + READWRITE(nStakeTime); + } + else if (fRead) + { + const_cast(this)->prevoutStake.SetNull(); + const_cast(this)->nStakeTime = 0; + } // block header READWRITE(this->nVersion); @@ -1735,114 +1520,6 @@ public: -// -// Private key that includes an expiration date in case it never gets used. -// -class CWalletKey -{ -public: - CPrivKey vchPrivKey; - int64 nTimeCreated; - int64 nTimeExpires; - std::string strComment; - //// todo: add something to note what created it (user, getnewaddress, change) - //// maybe should have a map property map - - CWalletKey(int64 nExpires=0) - { - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vchPrivKey); - READWRITE(nTimeCreated); - READWRITE(nTimeExpires); - READWRITE(strComment); - ) -}; - - - - - - -// -// Account information. -// Stored in wallet with key "acc"+string account name -// -class CAccount -{ -public: - std::vector vchPubKey; - - CAccount() - { - SetNull(); - } - - void SetNull() - { - vchPubKey.clear(); - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - READWRITE(vchPubKey); - ) -}; - - - -// -// Internal transfers. -// Database key is acentry -// -class CAccountingEntry -{ -public: - std::string strAccount; - int64 nCreditDebit; - int64 nTime; - std::string strOtherAccount; - std::string strComment; - - CAccountingEntry() - { - SetNull(); - } - - void SetNull() - { - nCreditDebit = 0; - nTime = 0; - strAccount.clear(); - strOtherAccount.clear(); - strComment.clear(); - } - - IMPLEMENT_SERIALIZE - ( - if (!(nType & SER_GETHASH)) - READWRITE(nVersion); - // Note: strAccount is serialized as part of the key, not here. - READWRITE(nCreditDebit); - READWRITE(nTime); - READWRITE(strOtherAccount); - READWRITE(strComment); - ) -}; - - - - - - @@ -2031,7 +1708,7 @@ public: bool CheckSignature() { CKey key; - if (!key.SetPubKey(ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"))) + if (!key.SetPubKey(ParseHex("0487ca85b6ae9d311f996c7616d20d0c88a5b4f07d25e78f419019f35cce6522acf978b2d99f0e7a58db1f120439e5c1889266927854aa57c93956c2569188a539"))) return error("CAlert::CheckSignature() : SetPubKey failed"); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) return error("CAlert::CheckSignature() : verify signature failed"); @@ -2045,22 +1722,4 @@ public: bool ProcessAlert(); }; - - - - - - - - - -extern std::map mapTransactions; -extern std::map mapWallet; -extern std::vector vWalletUpdated; -extern CCriticalSection cs_mapWallet; -extern std::map, CPrivKey> mapKeys; -extern std::map > mapPubKeys; -extern CCriticalSection cs_mapKeys; -extern CKey keyUser; - #endif