From 32ad4f4212782434bdb1b3dd3172414e8d75c7d8 Mon Sep 17 00:00:00 2001 From: Sunny King Date: Tue, 27 Dec 2011 03:33:11 +0000 Subject: [PATCH] PPCoin: coin age; main chain protocol switches to sum(coin age spent) --- src/bignum.h | 15 +++++++++++ src/db.cpp | 31 +++++++---------------- src/db.h | 5 ++- src/main.cpp | 77 ++++++++++++++++++++++++++++++++++++++++++++++++---------- src/main.h | 24 ++++++++---------- 5 files changed, 102 insertions(+), 50 deletions(-) diff --git a/src/bignum.h b/src/bignum.h index 1a2406b..5c08c58 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -182,6 +182,21 @@ public: BN_mpi2bn(pch, p - pch, this); } + uint64 getuint64() + { + unsigned int nSize = BN_bn2mpi(this, NULL); + if (nSize < 4) + return 0; + std::vector vch(nSize); + BN_bn2mpi(this, &vch[0]); + if (vch.size() > 4) + vch[4] &= 0x7f; + uint64 n = 0; + for (int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--) + ((unsigned char*)&n)[i] = vch[j]; + return n; + } + void setuint256(uint256 n) { unsigned char pch[sizeof(n) + 6]; diff --git a/src/db.cpp b/src/db.cpp index 9ac93b3..bb3c3b0 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 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. @@ -458,14 +459,14 @@ bool CTxDB::WriteHashBestChain(uint256 hashBestChain) return Write(string("hashBestChain"), hashBestChain); } -bool CTxDB::ReadBestInvalidWork(CBigNum& bnBestInvalidWork) +bool CTxDB::ReadBestInvalidTrust(uint64& nBestInvalidTrust) { - return Read(string("bnBestInvalidWork"), bnBestInvalidWork); + return Read(string("nBestInvalidTrust"), nBestInvalidTrust); } -bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork) +bool CTxDB::WriteBestInvalidTrust(uint64 nBestInvalidTrust) { - return Write(string("bnBestInvalidWork"), bnBestInvalidWork); + return Write(string("nBestInvalidTrust"), nBestInvalidTrust); } CBlockIndex static * InsertBlockIndex(uint256 hash) @@ -525,6 +526,7 @@ bool CTxDB::LoadBlockIndex() pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; + pindexNew->nChainTrust = diskindex.nChainTrust; pindexNew->nHeight = diskindex.nHeight; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; @@ -546,21 +548,6 @@ bool CTxDB::LoadBlockIndex() } pcursor->close(); - // Calculate bnChainWork - vector > vSortedByHeight; - vSortedByHeight.reserve(mapBlockIndex.size()); - BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) - { - CBlockIndex* pindex = item.second; - vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); - } - sort(vSortedByHeight.begin(), vSortedByHeight.end()); - BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) - { - CBlockIndex* pindex = item.second; - pindex->bnChainWork = (pindex->pprev ? pindex->pprev->bnChainWork : 0) + pindex->GetBlockWork(); - } - // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { @@ -572,11 +559,11 @@ bool CTxDB::LoadBlockIndex() return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexBest->bnChainWork; + nBestChainTrust = pindexBest->nChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight); - // Load bnBestInvalidWork, OK if it doesn't exist - ReadBestInvalidWork(bnBestInvalidWork); + // Load nBestInvalidTrust, OK if it doesn't exist + ReadBestInvalidTrust(nBestInvalidTrust); // Verify blocks in the best chain CBlockIndex* pindexFork = NULL; diff --git a/src/db.h b/src/db.h index 15bfb29..578a497 100644 --- a/src/db.h +++ b/src/db.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2011 The Bitcoin developers +// Copyright (c) 2011 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_DB_H @@ -288,8 +289,8 @@ public: bool EraseBlockIndex(uint256 hash); bool ReadHashBestChain(uint256& hashBestChain); bool WriteHashBestChain(uint256 hashBestChain); - bool ReadBestInvalidWork(CBigNum& bnBestInvalidWork); - bool WriteBestInvalidWork(CBigNum bnBestInvalidWork); + bool ReadBestInvalidTrust(uint64& nBestInvalidTrust); + bool WriteBestInvalidTrust(uint64 nBestInvalidTrust); bool LoadBlockIndex(); }; diff --git a/src/main.cpp b/src/main.cpp index caeb961..9df7584 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,8 +34,8 @@ static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32); const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download" CBlockIndex* pindexGenesisBlock = NULL; int nBestHeight = -1; -CBigNum bnBestChainWork = 0; -CBigNum bnBestInvalidWork = 0; +uint64 nBestChainTrust = 0; +uint64 nBestInvalidTrust = 0; uint256 hashBestChain = 0; CBlockIndex* pindexBest = NULL; int64 nTimeBestReceived = 0; @@ -744,15 +744,15 @@ bool IsInitialBlockDownload() void static InvalidChainFound(CBlockIndex* pindexNew) { - if (pindexNew->bnChainWork > bnBestInvalidWork) + if (pindexNew->nChainTrust > nBestInvalidTrust) { - bnBestInvalidWork = pindexNew->bnChainWork; - CTxDB().WriteBestInvalidWork(bnBestInvalidWork); + nBestInvalidTrust = pindexNew->nChainTrust; + CTxDB().WriteBestInvalidTrust(nBestInvalidTrust); MainFrameRepaint(); } - printf("InvalidChainFound: invalid block=%s height=%d work=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, pindexNew->bnChainWork.ToString().c_str()); - printf("InvalidChainFound: current best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str()); - if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) + printf("InvalidChainFound: invalid block=%s height=%d trust=%s\n", pindexNew->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->nHeight, CBigNum(pindexNew->nChainTrust).ToString().c_str()); + printf("InvalidChainFound: current best=%s height=%d trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str()); + if (pindexBest && nBestInvalidTrust > nBestChainTrust + pindexBest->GetBlockTrust() * 6) printf("InvalidChainFound: WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade.\n"); } @@ -860,6 +860,10 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, map& mapTestPoo if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) return error("ConnectInputs() : tried to spend coinbase at depth %d", pindexBlock->nHeight - pindex->nHeight); + // ppcoin: check transaction timestamp + if (txPrev.nTime > nTime) + return DoS(100, error("ConnectInputs() : transaction timestamp earlier than input transaction")); + // Skip ECDSA signature verification when connecting blocks (fBlock=true) during initial download // (before the last blockchain checkpoint). This is safe because block merkle hashes are // still computed and checked, and any change will be caught at the next checkpoint. @@ -1178,15 +1182,59 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) hashBestChain = hash; pindexBest = pindexNew; nBestHeight = pindexBest->nHeight; - bnBestChainWork = pindexNew->bnChainWork; + nBestChainTrust = pindexNew->nChainTrust; nTimeBestReceived = GetTime(); nTransactionsUpdated++; - printf("SetBestChain: new best=%s height=%d work=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, bnBestChainWork.ToString().c_str()); + printf("SetBestChain: new best=%s height=%d trust=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str()); return true; } +// ppcoin: total coin age spent in block, in the unit of coin-days. +uint64 CBlock::GetBlockCoinAge() +{ + uint64 nCoinAge = 0; + + BOOST_FOREACH(const CTransaction& tx, vtx) + { + if (tx.IsCoinBase()) + continue; + + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + // First try finding the previous transaction in database + CTransaction txPrev; + if (!txPrev.ReadFromDisk(txin.prevout)) + { + // If database lookup fails try memory pool + CRITICAL_BLOCK(cs_mapTransactions) + { + if (!mapTransactions.count(txin.prevout.hash)) + return 0; // Neither found in database nor memory pool + txPrev = mapTransactions[txin.prevout.hash]; + } + } + + if (tx.nTime < txPrev.nTime) + return 0; // Transaction timestamp violation + + int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; + CBigNum bnTxInCoinAge = CBigNum(nValueIn) * (tx.nTime - txPrev.nTime) / COIN / (24 * 60 * 60); + nCoinAge += bnTxInCoinAge.getuint64(); + + if (fDebug && GetBoolArg("-printcoinage")) + printf("coin age nValueIn=%-12I64d nTimeDiff=%d nCoinAge=%"PRI64d"\n", nValueIn, tx.nTime - txPrev.nTime, nCoinAge); + } + } + + if (!nCoinAge) + nCoinAge = 1; + + return nCoinAge; +} + + bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) { // Check for duplicate @@ -1206,7 +1254,10 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) pindexNew->pprev = (*miPrev).second; pindexNew->nHeight = pindexNew->pprev->nHeight + 1; } - pindexNew->bnChainWork = (pindexNew->pprev ? pindexNew->pprev->bnChainWork : 0) + pindexNew->GetBlockWork(); + uint64 nCoinAge = GetBlockCoinAge(); + if (!nCoinAge) + return error("AddToBlockIndex() : invalid or orphaned transaction in block"); + pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + nCoinAge; CTxDB txdb; txdb.TxnBegin(); @@ -1215,7 +1266,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos) return false; // New best - if (pindexNew->bnChainWork > bnBestChainWork) + if (pindexNew->nChainTrust > nBestChainTrust) if (!SetBestChain(txdb, pindexNew)) return false; @@ -1661,7 +1712,7 @@ string GetWarnings(string strFor) } // Longer invalid proof-of-work chain - if (pindexBest && bnBestInvalidWork > bnBestChainWork + pindexBest->GetBlockWork() * 6) + if (pindexBest && nBestInvalidTrust > nBestChainTrust + pindexBest->GetBlockTrust() * 6) { nPriority = 2000; strStatusBar = strRPC = "WARNING: Displayed transactions may not be correct! You may need to upgrade, or other nodes may need to upgrade."; diff --git a/src/main.h b/src/main.h index c02b5fb..32fbc39 100644 --- a/src/main.h +++ b/src/main.h @@ -56,8 +56,8 @@ extern std::map mapBlockIndex; extern uint256 hashGenesisBlock; 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; @@ -1003,6 +1003,7 @@ public: bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos); bool CheckBlock() const; bool AcceptBlock(); + uint64 GetBlockCoinAge(); // ppcoin: calculate total coin age spent in block }; @@ -1026,8 +1027,8 @@ 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; // block header int nVersion; @@ -1045,7 +1046,7 @@ public: nFile = 0; nBlockPos = 0; nHeight = 0; - bnChainWork = 0; + nChainTrust = 0; nVersion = 0; hashMerkleRoot = 0; @@ -1062,7 +1063,7 @@ public: nFile = nFileIn; nBlockPos = nBlockPosIn; nHeight = 0; - bnChainWork = 0; + nChainTrust = 0; nVersion = block.nVersion; hashMerkleRoot = block.hashMerkleRoot; @@ -1094,13 +1095,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->nChainTrust); } bool IsInMainChain() const @@ -1160,8 +1157,8 @@ public: 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, merkle=%s, hashBlock=%s)", + pprev, pnext, nFile, nBlockPos, nChainTrust, nHeight, hashMerkleRoot.ToString().substr(0,10).c_str(), GetBlockHash().ToString().substr(0,20).c_str()); } @@ -1203,6 +1200,7 @@ public: READWRITE(hashNext); READWRITE(nFile); READWRITE(nBlockPos); + READWRITE(nChainTrust); READWRITE(nHeight); // block header -- 1.7.1