diff --git a/Stealth.pro b/Stealth.pro index d5d419f..d2347c8 100644 --- a/Stealth.pro +++ b/Stealth.pro @@ -18,7 +18,7 @@ win32 { TEMPLATE = app TARGET = "Stealth Qt" -VERSION = 2.1.0.3 +VERSION = 2.2.0.0 INCLUDEPATH += src src/json src/qt src/tor INCLUDEPATH += src/tor/adapter src/tor/common src/tor/ext INCLUDEPATH += src/tor/ext/curve25519_donna src/tor/ext/ed25519/donna diff --git a/contrib/macdeploy/Info.plist b/contrib/macdeploy/Info.plist index 6f62a31..ba366d1 100644 --- a/contrib/macdeploy/Info.plist +++ b/contrib/macdeploy/Info.plist @@ -9,16 +9,16 @@ CFBundlePackageType APPL CFBundleGetInfoString - Stealth [XST] Complete Anonymity 2.1.0.3 + StealthCoin [XST] Complete Anonymity 2.2.0.0 CFBundleExecutable Stealth Qt CFBundleIdentifier org.stealth.stealth-qt CFBundleShortVersionString - 2.1.0.3 + 2.2.0.0 CFBundleSignature oXST CFBundleVersion - 2.1.0.3 + 2.2.0.0 diff --git a/src/alert.cpp b/src/alert.cpp index 9f3ff0d..2dbc0a6 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -62,8 +62,8 @@ std::string CUnsignedAlert::ToString() const return strprintf( "CAlert(\n" " nVersion = %d\n" - " nRelayUntil = %"PRI64d"\n" - " nExpiration = %"PRI64d"\n" + " nRelayUntil = %" PRI64d "\n" + " nExpiration = %" PRI64d "\n" " nID = %d\n" " nCancel = %d\n" " setCancel = %s\n" diff --git a/src/bignum.h b/src/bignum.h index 9e363aa..1238f5b 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -95,12 +95,12 @@ class CBigNum CBigNum(signed char n) { init(); if (n >= 0) setulong(n); else setint64(n); } CBigNum(short n) { init(); if (n >= 0) setulong(n); else setint64(n); } CBigNum(int n) { init(); if (n >= 0) setulong(n); else setint64(n); } - CBigNum(long n) { init(); if (n >= 0) setulong(n); else setint64(n); } + // CBigNum(long n) { init(); if (n >= 0) setulong(n); else setint64(n); } CBigNum(int64 n) { init(); setint64(n); } CBigNum(unsigned char n) { init(); setulong(n); } CBigNum(unsigned short n) { init(); setulong(n); } CBigNum(unsigned int n) { init(); setulong(n); } - CBigNum(size_t n) { init(); setulong((unsigned int) n); } + // CBigNum(size_t n) { init(); setulong((unsigned int) n); } // CBigNum(unsigned long n) { init(); setulong(n); } CBigNum(uint64 n) { init(); setuint64(n); } explicit CBigNum(uint256 n) { init(); setuint256(n); } diff --git a/src/bitcoinrpc.cpp b/src/bitcoinrpc.cpp index 54bacb9..9b0e5dc 100644 --- a/src/bitcoinrpc.cpp +++ b/src/bitcoinrpc.cpp @@ -403,7 +403,7 @@ static string HTTPReply(int nStatus, const string& strMsg, bool keepalive) "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" "Connection: %s\r\n" - "Content-Length: %"PRIszu"\r\n" + "Content-Length: %" PRIszu "\r\n" "Content-Type: application/json\r\n" "Server: StealthCoin-json-rpc/%s\r\n" "\r\n" @@ -553,25 +553,33 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) bool ClientAllowed(const boost::asio::ip::address& address) { // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses - if (address.is_v6() - && (address.to_v6().is_v4_compatible() - || address.to_v6().is_v4_mapped())) + if (address.is_v6() && + (address.to_v6().is_v4_compatible() || + address.to_v6().is_v4_mapped())) + { return ClientAllowed(address.to_v6().to_v4()); + } - std::string ipv4addr = address.to_string(); + std::string ipv4addr = address.to_string(); - if (address == asio::ip::address_v4::loopback() - || address == asio::ip::address_v6::loopback() - || (address.is_v4() + if ((address == asio::ip::address_v4::loopback()) || + (address == asio::ip::address_v6::loopback()) || + (address.is_v4() && // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) - && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) + (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) + { return true; + } const string strAddress = address.to_string(); const vector& vAllow = mapMultiArgs["-rpcallowip"]; BOOST_FOREACH(string strAllow, vAllow) + { if (WildcardMatch(strAddress, strAllow)) + { return true; + } + } return false; } diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 64fe559..ad72545 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -375,16 +375,6 @@ namespace Checkpoints return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity || pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime()); } - - // Is the sync-checkpoint too old? - bool IsSyncCheckpointTooOld(unsigned int nSeconds) - { - LOCK(cs_hashSyncCheckpoint); - // sync-checkpoint should always be accepted block - assert(mapBlockIndex.count(hashSyncCheckpoint)); - const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; - return (pindexSync->GetBlockTime() + nSeconds < GetAdjustedTime()); - } } // stealth: sync-checkpoint master key (520 bits, 130 hex) diff --git a/src/checkpoints.h b/src/checkpoints.h index 4f5db11..16ec415 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -44,7 +44,6 @@ namespace Checkpoints bool SetCheckpointPrivKey(std::string strPrivKey); bool SendSyncCheckpoint(uint256 hashCheckpoint); bool IsMatureSyncCheckpoint(); - bool IsSyncCheckpointTooOld(unsigned int nSeconds); } // ppcoin: synchronized checkpoint diff --git a/src/clientversion.h b/src/clientversion.h index 55df318..1d3129c 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -7,9 +7,9 @@ // These need to be macros, as version.cpp's and bitcoin-qt.rc's voodoo requires it #define CLIENT_VERSION_MAJOR 2 -#define CLIENT_VERSION_MINOR 1 +#define CLIENT_VERSION_MINOR 2 #define CLIENT_VERSION_REVISION 0 -#define CLIENT_VERSION_BUILD 4 +#define CLIENT_VERSION_BUILD 0 // Converts the parameter X to a string after macro replacement on X has been performed. // Don't merge these into one macro! diff --git a/src/db.cpp b/src/db.cpp index 72b8558..bae597a 100644 --- a/src/db.cpp +++ b/src/db.cpp @@ -462,7 +462,7 @@ void CDBEnv::Flush(bool fShutdown) else mi++; } - printf("DBFlush(%s)%s ended %15"PRI64d"ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart); + printf("DBFlush(%s)%s ended %15" PRI64d "ms\n", fShutdown ? "true" : "false", fDbEnvInit ? "" : " db not started", GetTimeMillis() - nStart); if (fShutdown) { char** listp; diff --git a/src/init.cpp b/src/init.cpp index fc5b680..d361521 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -861,7 +861,7 @@ bool AppInit2() printf("Shutdown requested. Exiting.\n"); return false; } - printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart); + printf(" block index %15" PRI64d "ms\n", GetTimeMillis() - nStart); if (GetBoolArg("-printblockindex") || GetBoolArg("-printblocktree")) { @@ -952,7 +952,7 @@ bool AppInit2() } printf("%s", strErrors.str().c_str()); - printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart); + printf(" wallet %15" PRI64d "ms\n", GetTimeMillis() - nStart); RegisterWallet(pwalletMain); @@ -972,7 +972,7 @@ bool AppInit2() printf("Rescanning last %i blocks (from block %i)...\n", pindexBest->nHeight - pindexRescan->nHeight, pindexRescan->nHeight); nStart = GetTimeMillis(); pwalletMain->ScanForWalletTransactions(pindexRescan, true); - printf(" rescan %15"PRI64d"ms\n", GetTimeMillis() - nStart); + printf(" rescan %15" PRI64d "ms\n", GetTimeMillis() - nStart); } // ********************************************************* Step 9: import blocks @@ -1013,7 +1013,7 @@ bool AppInit2() printf("Invalid or missing peers.dat; recreating\n"); } - printf("Loaded %i addresses from peers.dat %"PRI64d"ms\n", + printf("Loaded %i addresses from peers.dat %" PRI64d "ms\n", addrman.size(), GetTimeMillis() - nStart); // ********************************************************* Step 11: start node @@ -1024,11 +1024,11 @@ bool AppInit2() RandAddSeedPerfmon(); //// debug print - printf("mapBlockIndex.size() = %"PRIszu"\n", mapBlockIndex.size()); + printf("mapBlockIndex.size() = %" PRIszu "\n", mapBlockIndex.size()); printf("nBestHeight = %d\n", nBestHeight); - printf("setKeyPool.size() = %"PRIszu"\n", pwalletMain->setKeyPool.size()); - printf("mapWallet.size() = %"PRIszu"\n", pwalletMain->mapWallet.size()); - printf("mapAddressBook.size() = %"PRIszu"\n", pwalletMain->mapAddressBook.size()); + printf("setKeyPool.size() = %" PRIszu "\n", pwalletMain->setKeyPool.size()); + printf("mapWallet.size() = %" PRIszu "\n", pwalletMain->mapWallet.size()); + printf("mapAddressBook.size() = %" PRIszu "\n", pwalletMain->mapAddressBook.size()); if (!NewThread(StartNode, NULL)) InitError(_("Error: could not start node")); diff --git a/src/irc.cpp b/src/irc.cpp index 22b2834..362331f 100644 --- a/src/irc.cpp +++ b/src/irc.cpp @@ -260,7 +260,7 @@ void ThreadIRCSeed2(void* parg) if (GetLocal(addrLocal, &addrIPv4) && nNameRetry<3) strMyName = EncodeAddress(GetLocalAddress(&addrConnect)); if (strMyName == "") - strMyName = strprintf("x%"PRI64u"", GetRand(1000000000)); + strMyName = strprintf("x%" PRI64u "", GetRand(1000000000)); Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str()); Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str()); diff --git a/src/kernel.cpp b/src/kernel.cpp index 5bb11fe..967a4db 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -130,7 +130,7 @@ static bool SelectBlockFromCandidates( // selected block of a given block group in the past. // The selection of a block is based on a hash of the block's proof-hash and // the previous stake modifier. -// Stake modifier is recomputed at a fixed time interval instead of every +// Stake modifier is recomputed at a fixed time interval instead of every // block. This is to make it difficult for an attacker to gain control of // additional bits in the stake modifier, even after generating a chain of // blocks. @@ -150,7 +150,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif return error("ComputeNextStakeModifier: unable to get last modifier"); if (fDebug) { - printf("ComputeNextStakeModifier: prev modifier=0x%016"PRI64x" time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str()); + printf("ComputeNextStakeModifier: prev modifier=0x%016" PRI64x " time=%s\n", nStakeModifier, DateTimeStrFormat(nModifierTime).c_str()); } if (nModifierTime / nModifierInterval >= pindexPrev->GetBlockTime() / nModifierInterval) return true; @@ -214,7 +214,7 @@ bool ComputeNextStakeModifier(const CBlockIndex* pindexPrev, uint64& nStakeModif } if (fDebug) { - printf("ComputeNextStakeModifier: new modifier=0x%016"PRI64x" time=%s\n", nStakeModifierNew, DateTimeStrFormat(pindexPrev->GetBlockTime()).c_str()); + printf("ComputeNextStakeModifier: new modifier=0x%016" PRI64x " time=%s\n", nStakeModifierNew, DateTimeStrFormat(pindexPrev->GetBlockTime()).c_str()); } nStakeModifier = nStakeModifierNew; @@ -246,7 +246,7 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier else { if(fDebug) - printf(">> nStakeModifierTime = %"PRI64d", pindexFrom->GetBlockTime() = %"PRI64d", nStakeModifierSelectionInterval = %"PRI64d"\n", + printf(">> nStakeModifierTime = %" PRI64d ", pindexFrom->GetBlockTime() = %" PRI64d ", nStakeModifierSelectionInterval = %" PRI64d "\n", nStakeModifierTime, pindexFrom->GetBlockTime(), nStakeModifierSelectionInterval); return false; @@ -274,13 +274,13 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier // this ensures that the chance of getting a coinstake is proportional to the // amount of coin age one owns. // The reason this hash is chosen is the following: -// nStakeModifier: +// nStakeModifier: // (v0.3) scrambles computation to make it very difficult to precompute // future proof-of-stake at the time of the coin's confirmation // (v0.2) nBits (deprecated): encodes all past block timestamps // txPrev.block.nTime: prevent nodes from guessing a good timestamp to // generate transaction for future advantage -// txPrev.offset: offset of txPrev inside block, to reduce the chance of +// txPrev.offset: offset of txPrev inside block, to reduce the chance of // nodes generating coinstake at the same time // txPrev.nTime: reduce the chance of nodes generating coinstake at the same // time @@ -293,9 +293,12 @@ static bool GetKernelStakeModifier(uint256 hashBlockFrom, uint64& nStakeModifier bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned int nTxPrevOffset, const CTransaction& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake) { + unsigned int nTimeTxPrev = txPrev.HasTimestamp() ? + txPrev.GetTxTime() : blockFrom.nTime; + unsigned int nTargetMultiplier = 10; - if (nTimeTx < txPrev.nTime) // Transaction timestamp violation + if (nTimeTx < nTimeTxPrev) // Transaction timestamp violation return error("CheckStakeKernelHash() : nTime violation"); unsigned int nTimeBlockFrom = blockFrom.GetBlockTime(); @@ -309,12 +312,12 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned // v0.3 protocol kernel hash weight starts from 0 at the min age // this change increases active coins participating the hash and helps // to secure the network when proof-of-stake difficulty is low - int64 nTimeWeight = min((int64)nTimeTx - txPrev.nTime, + int64 nTimeWeight = min((int64)nTimeTx - nTimeTxPrev, (int64)nStakeMaxAge + nStakeMinAge) - nStakeMinAge; CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60); - // printf(">>> CheckStakeKernelHash: nTimeWeight = %"PRI64d"\n", nTimeWeight); + // printf(">>> CheckStakeKernelHash: nTimeWeight = %" PRI64d "\n", nTimeWeight); // Calculate hash CDataStream ss(SER_GETHASH, 0); uint64 nStakeModifier = 0; @@ -325,28 +328,28 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned { if(fDebug) printf(">>> CheckStakeKernelHash: GetKernelStakeModifier return false\n"); - + return false; } - + // if(fDebug) { // printf(">>> CheckStakeKernelHash: passed GetKernelStakeModifier\n"); // } ss << nStakeModifier; - ss << nTimeBlockFrom << nTxPrevOffset << txPrev.nTime << prevout.n << nTimeTx; + ss << nTimeBlockFrom << nTxPrevOffset << nTimeTxPrev << prevout.n << nTimeTx; hashProofOfStake = Hash(ss.begin(), ss.end()); if (fPrintProofOfStake) { - printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n", + printf("CheckStakeKernelHash() : using modifier 0x%016" PRI64x " at height=%d timestamp=%s for block from height=%d timestamp=%s\n", nStakeModifier, nStakeModifierHeight, DateTimeStrFormat(nStakeModifierTime).c_str(), mapBlockIndex[blockFrom.GetHash()]->nHeight, DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); - printf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + printf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016" PRI64x " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", "0.3", nStakeModifier, - nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, + nTimeBlockFrom, nTxPrevOffset, nTimeTxPrev, prevout.n, nTimeTx, hashProofOfStake.ToString().c_str()); } @@ -354,25 +357,14 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned // The nTargetMultiplier of 10 is a calibration for stealth CBigNum bnProduct = bnCoinDayWeight * bnTargetPerCoinDay * nTargetMultiplier; - - - // someone minted with beta - /* - if (nTimeBlockFrom <= KERNEL_MODIFIER_TIME_01) { - printf("\n>>> dividing by 256\n"); - hashProofOfStake = hashProofOfStake >> 8; - } - */ - - if (CBigNum(hashProofOfStake) > bnProduct) { if(fDebug) { - printf(">>> bnCoinDayWeight = %s, bnTargetPerCoinDay=%s\n>>> too small:\n", + printf(">>> bnCoinDayWeight = %s, bnTargetPerCoinDay=%s\n>>> too small:\n", bnCoinDayWeight.ToString().c_str(), bnTargetPerCoinDay.ToString().c_str(), - bnProduct.ToString().c_str()); + bnProduct.ToString().c_str()); printf(">>> CheckStakeKernelHash - hashProofOfStake too much\n"); printf(">>> hashProofOfStake too much: %s\n", CBigNum(hashProofOfStake).ToString().c_str()); } @@ -382,27 +374,28 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned if (fDebug && !fPrintProofOfStake) { - printf("CheckStakeKernelHash() : using modifier 0x%016"PRI64x" at height=%d timestamp=%s for block from height=%d timestamp=%s\n", - nStakeModifier, nStakeModifierHeight, + printf("CheckStakeKernelHash() : using modifier 0x%016" PRI64x " at height=%d timestamp=%s for block from height=%d timestamp=%s\n", + nStakeModifier, nStakeModifierHeight, DateTimeStrFormat(nStakeModifierTime).c_str(), mapBlockIndex[blockFrom.GetHash()]->nHeight, DateTimeStrFormat(blockFrom.GetBlockTime()).c_str()); - printf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016"PRI64x" nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", + printf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016" PRI64x " nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n", "0.3", nStakeModifier, - nTimeBlockFrom, nTxPrevOffset, txPrev.nTime, prevout.n, nTimeTx, + nTimeBlockFrom, nTxPrevOffset, nTimeTxPrev, prevout.n, nTimeTx, hashProofOfStake.ToString().c_str()); } return true; } // 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, unsigned int nBlockTime) { if (!tx.IsCoinStake()) return error("CheckProofOfStake() : called on non-coinstake %s", tx.GetHash().ToString().c_str()); - + unsigned int nTimeTx = tx.HasTimestamp() ? tx.GetTxTime() : nBlockTime; // Kernel (input 0) must match the stake hash target per coin age (nBits) const CTxIn& txin = tx.vin[0]; @@ -425,7 +418,7 @@ bool CheckProofOfStake(const CTransaction& tx, unsigned int nBits, uint256& hash 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, nTimeTx, hashProofOfStake, 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; @@ -450,7 +443,7 @@ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex) uint256 hashChecksum = Hash(ss.begin(), ss.end()); hashChecksum >>= (256 - 32); if(fDebug) - printf("stake checksum: 0x%016"PRI64x"\n", hashChecksum.Get64()); + printf("stake checksum: 0x%016" PRI64x "\n", hashChecksum.Get64()); return hashChecksum.Get64(); } diff --git a/src/kernel.h b/src/kernel.h index 631664a..f81dd72 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -23,7 +23,8 @@ bool CheckStakeKernelHash(unsigned int nBits, const CBlock& blockFrom, unsigned // 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, unsigned int nBlockTime); // Check whether the coinstake timestamp meets protocol bool CheckCoinStakeTimestamp(int64 nTimeBlock, int64 nTimeTx); @@ -37,7 +38,4 @@ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierCheck // Get time weight using supplied timestamps int64 GetWeight(int64 nIntervalBeginning, int64 nIntervalEnd); -// shit happens - someone minted with a beta wallet -static const int64 KERNEL_MODIFIER_TIME_01 = 1406227020 + 60 * 60 * 2; - #endif // PPCOIN_KERNEL_H diff --git a/src/key.cpp b/src/key.cpp index a2be4cb..80a3306 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -379,9 +379,9 @@ bool CKey::Sign(uint256 hash, std::vector& vchSig) sig_s_new = BN_new(); // enforce low S values, by negating the value (modulo the order) if above order/2. BN_sub(sig_s_new, order, sig_s); + BN_copy(sig_r_new, sig_r); // no need to free sig_*_new according to OpenSSL docs // https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html - BN_copy(sig_r_new, sig_r); ECDSA_SIG_set0(sig, sig_r_new, sig_s_new); } #else diff --git a/src/main.cpp b/src/main.cpp index a667e9c..e4d796f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -41,11 +41,11 @@ static CBigNum bnProofOfWorkLimit(~uint256(0) >> 20); static CBigNum bnProofOfStakeLimit(~uint256(0) >> 2); static CBigNum bnProofOfWorkLimitTestNet(~uint256(0) >> 16); -static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 30); +static CBigNum bnProofOfStakeLimitTestNet(~uint256(0) >> 2); -unsigned int nStakeMinAge = 60 * 60 * 24 * 3; //minimum age for coin age: 3 day -unsigned int nStakeMaxAge = 60 * 60 * 24 * 9; //stake age of full weight: 9 day -unsigned int nStakeTargetSpacing = 60; // 60 sec block spacing +unsigned int nStakeMinAge = 60 * 60 * 24 * 3; //minimum age for coin age: 3 day +unsigned int nStakeMaxAge = 60 * 60 * 24 * 9; //stake age of full weight: 9 day +unsigned int nStakeTargetSpacing = 60; // 60 sec block spacing int64 nChainStartTime = 1403684997; int nCoinbaseMaturity = 40; @@ -90,27 +90,33 @@ int64 nReserveBalance = 0; int GetFork(int nHeight) { // Make sure Heights are ascending! - const int aForks[TOTAL_FORKS][2] = { - // Height, Fork Number - /* Jul 4 02:47:04 MDT 2014 */ { 1, XST_LAUNCH }, - /* 08/16/2017 */ { 1732201, XST_FORK005 } - }; - - if (fTestNet) - { - return TOTAL_FORKS; - } - + const int aForks[2][TOTAL_FORKS][2] = + { + /* MAIN NET */ { // Height, Fork Number + /* Jul 4 02:47:04 MDT 2014 */ { 0, XST_GENESIS }, + /* Oct 9 00:00:42 MST 2014 */ { 130669, XST_FORK004 }, + /* Aug 16 10:23:28 MDT 2017 */ { 1732201, XST_FORK005 }, + /* Approx Nov 14, MDT 2018 */ { 2378000, XST_FORK006 } + }, + /* TEST NET */ { // Height, Fork Number + { 0, XST_GENESIS }, + { 0, XST_FORK004 }, + { 40, XST_FORK005 }, + { 145, XST_FORK006 } + } + }; + // loop has strange logic, but if fork i height is greater than nHeight // then you are on fork i-1 - int nFork = aForks[0][1]; + const int idx = fTestNet ? 1 : 0; + int nFork = aForks[idx][0][1]; for (int i = 1; i < TOTAL_FORKS; ++i) { - if (aForks[i][0] > nHeight) + if (aForks[idx][i][0] > nHeight) { break; } - nFork = aForks[i][1]; + nFork = aForks[idx][i][1]; } return nFork; } @@ -124,13 +130,14 @@ int GetFork(int nHeight) int GetMinPeerProtoVersion(int nHeight) { // helps to prevent buffer overrun - static const int nVersions = 2; + static const int nVersions = 3; // Make sure forks are ascending! const int aVersions[nVersions][2] = { // Fork, Proto Version - { XST_LAUNCH, 62020 }, - { XST_FORK005, 62100 } + { XST_GENESIS, 62020 }, + { XST_FORK005, 62100 }, + { XST_FORK006, 62200 } }; int nFork = GetFork(nHeight); @@ -187,7 +194,7 @@ bool static IsFromMe(CTransaction& tx) bool static GetTransaction(const uint256& hashTx, CWalletTx& wtx) { BOOST_FOREACH(CWallet* pwallet, setpwalletRegistered) - if (pwallet->GetTransaction(hashTx,wtx)) + if (pwallet->GetTransaction(hashTx, wtx)) return true; return false; } @@ -279,7 +286,7 @@ bool AddOrphanTx(const CDataStream& vMsg) // at most 500 megabytes of orphans: if (pvMsg->size() > 5000) { - printf("ignoring large orphan tx (size: %"PRIszu", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); + printf("ignoring large orphan tx (size: %" PRIszu ", hash: %s)\n", pvMsg->size(), hash.ToString().substr(0,10).c_str()); delete pvMsg; return false; } @@ -288,7 +295,7 @@ bool AddOrphanTx(const CDataStream& vMsg) BOOST_FOREACH(const CTxIn& txin, tx.vin) mapOrphanTransactionsByPrev[txin.prevout.hash].insert(make_pair(hash, pvMsg)); - printf("stored orphan tx %s (mapsz %"PRIszu")\n", hash.ToString().substr(0,10).c_str(), + printf("stored orphan tx %s (mapsz %" PRIszu ")\n", hash.ToString().substr(0,10).c_str(), mapOrphanTransactions.size()); return true; } @@ -364,7 +371,9 @@ bool CTransaction::ReadFromDisk(COutPoint prevout) bool CTransaction::IsStandard() const { if (nVersion > CTransaction::CURRENT_VERSION) + { return false; + } if (GetFork(nBestHeight + 1) >= XST_FORK005) { @@ -380,7 +389,8 @@ bool CTransaction::IsStandard() const // the next block. // // However, IsFinalTx() is confusing... Without arguments, it uses - // chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height() + // chainActive.Height() to evaluate nLockTime; when a block is + // accepted, chainActive.Height() // is set to the value of nHeight in the block. However, when IsFinalTx() // is called within CBlock::AcceptBlock(), the height of the block *being* // evaluated is what is used. Thus if we want to know if a transaction can @@ -393,8 +403,13 @@ bool CTransaction::IsStandard() const if (!IsFinal(nBestHeight + 1)) { return false; } - // nTime has different purpose from nLockTime but can be used in similar attacks - if (nTime > FutureDrift(GetAdjustedTime())) { + + // nTime, aka GetTxTime(), has a different purpose from nLockTime + // but can be used in similar attacks + // CTransaction gets timestamp from block upon NOTXTIME_VERSION + // block timestamp checked elsewhere + if (HasTimestamp() && (GetTxTime() > FutureDrift(GetAdjustedTime()))) + { return false; } @@ -574,8 +589,6 @@ int CMerkleTx::SetMerkleBranch(const CBlock* pblock) } - - bool CTransaction::CheckTransaction() const { // Basic checks that don't depend on any context @@ -595,12 +608,14 @@ bool CTransaction::CheckTransaction() const if (txout.IsEmpty() && !IsCoinBase() && !IsCoinStake()) return DoS(100, error("CTransaction::CheckTransaction() : txout empty for user transaction")); - if (fTestNet || (nTime >= STEALTH_ADDR_KICK_IN)) + if (GetFork(nBestHeight+1) >= XST_FORK004) { if (txout.nValue < 0) return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue negative")); - }else { + } + else + { if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT) return DoS(100, error("CTransaction::CheckTransaction() : txout.nValue below minimum")); @@ -760,7 +775,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, // Don't accept it if it can't get into a block int64 txMinFee = tx.GetMinFee(1000, false, GMF_RELAY, nSize); if (nFees < txMinFee) - return error("CTxMemPool::accept() : not enough fees %s, %"PRI64d" < %"PRI64d, + return error("CTxMemPool::accept() : not enough fees %s, %" PRI64d " < %" PRI64d, hash.ToString().c_str(), nFees, txMinFee); @@ -798,7 +813,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. if (!tx.ConnectInputs(txdb, mapInputs, mapUnused, CDiskTxPos(1,1,1), - pindexBest, false, false, flags)) + pindexBest, false, false, flags)) { return error("CTxMemPool::accept() : ConnectInputs failed %s", hash.ToString().substr(0,10).c_str()); } @@ -820,7 +835,7 @@ bool CTxMemPool::accept(CTxDB& txdb, CTransaction &tx, if (ptxOld) EraseFromWallets(ptxOld->GetHash()); - printf("CTxMemPool::accept() : accepted %s (poolsz %"PRIszu")\n", + printf("CTxMemPool::accept() : accepted %s (poolsz %" PRIszu ")\n", hash.ToString().substr(0,10).c_str(), mapTx.size()); return true; @@ -905,8 +920,6 @@ void CTxMemPool::queryHashes(std::vector& vtxid) } - - int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const { if (hashBlock == 0 || nIndex == -1) @@ -968,8 +981,6 @@ bool CMerkleTx::AcceptToMemoryPool() return AcceptToMemoryPool(txdb); } - - bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) { @@ -990,7 +1001,6 @@ bool CWalletTx::AcceptWalletTransaction(CTxDB& txdb, bool fCheckInputs) return false; } - bool CWalletTx::AcceptWalletTransaction() { CTxDB txdb("r"); @@ -1015,7 +1025,8 @@ int CTxIndex::GetDepthInMainChain() const } // Return transaction in tx, and if it was found inside a block, its hash is placed in hashBlock -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) +bool GetTransaction(const uint256 &hash, CTransaction &tx, + uint256 &hashBlock, unsigned int &nTimeBlock) { { LOCK(cs_main); @@ -1032,7 +1043,10 @@ bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock) { CBlock block; if (block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + { hashBlock = block.GetHash(); + nTimeBlock = block.GetBlockTime(); + } return true; } } @@ -1100,7 +1114,7 @@ uint256 WantedByOrphan(const CBlock* pblockOrphan) int generateMTRandom(unsigned int s, int range) { - random::mt19937 gen(s); + random::mt19937 gen(s); random::uniform_int_distribution<> dist(0, range); return dist(gen); } @@ -1112,58 +1126,44 @@ int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash) { int64 nSubsidy = 0 * COIN; - if (nHeight == 0) - nSubsidy = 16 * COIN; // genesis block coinbase is unspendable - else if (nHeight <= 10) - nSubsidy = 23300 * COIN; // Blocks 1-10 are premine - else if (nHeight <= 260) - nSubsidy = 16 * COIN; // 4 hr Low Reward Period for Fairness - else if (nHeight <= 1700) - nSubsidy = 8000 * COIN; - else if (nHeight <= 3140) - nSubsidy = 4000 * COIN; - else if (nHeight <= 4580) - nSubsidy = 2000 * COIN; - else if (nHeight < CUTOFF_POW_BLOCK) - nSubsidy = 1000 * COIN; // was 1 coin -/* - else if (nHeight <= 6020) - nSubsidy = 1000 * COIN; - else if (nHeight <= 7460) - nSubsidy = 500 * COIN; - else if (nHeight <= 8900) - nSubsidy = 250 * COIN; - else if (nHeight <= 10340) - nSubsidy = 125 * COIN; - else if (nHeight <= 11780) - nSubsidy = 62 * COIN; - else if (nHeight <= 13220) - nSubsidy = 31 * COIN; - else if (nHeight <= 14660) - nSubsidy = 15 * COIN; - else if (nHeight <= 16100) - nSubsidy = 8 * COIN; - else if (nHeight <= 17540) - nSubsidy = 4 * COIN; - else if (nHeight <= 18980) - nSubsidy = 2 * COIN; - else if (nHeight < CUTOFF_POW_BLOCK) - nSubsidy = 1 * COIN; - */ + if (fTestNet) + { + if (nHeight == 0) + nSubsidy = 16 * COIN; + else if (nHeight < GetPoWCutoff()) + nSubsidy = 90000 * COIN; + } + else + { + if (nHeight == 0) + nSubsidy = 16 * COIN; // genesis block coinbase is unspendable + else if (nHeight <= 10) + nSubsidy = 23300 * COIN; // Blocks 1-10 are premine + else if (nHeight <= 260) + nSubsidy = 16 * COIN; // 4 hr Low Reward Period for Fairness + else if (nHeight <= 1700) + nSubsidy = 8000 * COIN; + else if (nHeight <= 3140) + nSubsidy = 4000 * COIN; + else if (nHeight <= 4580) + nSubsidy = 2000 * COIN; + else if (nHeight < GetPoWCutoff()) + nSubsidy = 1000 * COIN; // was 1 coin + } return nSubsidy + nFees; } // miner's coin stake reward based on nBits and coin age spent (coin-days) // simple algorithm, not depend on the diff -int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight) +int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, int nHeight) { int64 nRewardCoinYear; - nRewardCoinYear = MAX_STEALTH_PROOF_OF_STAKE; + nRewardCoinYear = fTestNet ? MAX_STEALTH_PROOF_OF_STAKE_TESTNET : MAX_STEALTH_PROOF_OF_STAKE; int64 nSubsidy = nCoinAge * nRewardCoinYear / 365; if (fDebug && GetBoolArg("-printcreation")) - printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits); + printf("GetProofOfStakeReward(): create=%s nCoinAge=%" PRI64d " nBits=%d\n", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits); return nSubsidy; } @@ -1239,16 +1239,16 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfS return bnTargetLimit.GetCompact(); // second block int64 nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime(); - if(nActualSpacing < 0) - { - // printf(">> nActualSpacing = %"PRI64d" corrected to 1.\n", nActualSpacing); - nActualSpacing = 1; - } - else if(nActualSpacing > nTargetTimespan) - { - // printf(">> nActualSpacing = %"PRI64d" corrected to nTargetTimespan (900).\n", nActualSpacing); - nActualSpacing = nTargetTimespan; - } + if(nActualSpacing < 0) + { + // printf(">> nActualSpacing = %" PRI64d " corrected to 1.\n", nActualSpacing); + nActualSpacing = 1; + } + else if(nActualSpacing > nTargetTimespan) + { + // printf(">> nActualSpacing = %" PRI64d " corrected to nTargetTimespan (900).\n", nActualSpacing); + nActualSpacing = nTargetTimespan; + } // ppcoin: target change every block // ppcoin: retarget with exponential moving toward target spacing @@ -1259,13 +1259,6 @@ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfS int64 nInterval = nTargetTimespan / nTargetSpacing; bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing); bnNew /= ((nInterval + 1) * nTargetSpacing); - - /* - printf(">> Height = %d, fProofOfStake = %d, nInterval = %"PRI64d", nTargetSpacing = %"PRI64d", nActualSpacing = %"PRI64d"\n", - pindexPrev->nHeight, fProofOfStake, nInterval, nTargetSpacing, nActualSpacing); - printf(">> pindexPrev->GetBlockTime() = %"PRI64d", pindexPrev->nHeight = %d, pindexPrevPrev->GetBlockTime() = %"PRI64d", pindexPrevPrev->nHeight = %d\n", - pindexPrev->GetBlockTime(), pindexPrev->nHeight, pindexPrevPrev->GetBlockTime(), pindexPrevPrev->nHeight); - */ if (bnNew > bnTargetLimit) bnNew = bnTargetLimit; @@ -1440,7 +1433,7 @@ bool CTransaction::FetchInputs(CTxDB& txdb, const map& mapTes // Revisit this if/when transaction replacement is implemented and allows // adding inputs: fInvalid = true; - return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + return DoS(100, error("FetchInputs() : %s prevout.n out of range %d %" PRIszu " %" PRIszu " prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); } } @@ -1501,6 +1494,7 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, // fBlock is true when this is called from AcceptBlock when a new best-block is added to the blockchain // fMiner is true when called from the internal bitcoin miner // ... both are false when called from CTransaction::AcceptToMemoryPool + unsigned int nTxTime = HasTimestamp() ? GetTxTime() : pindexBlock->nTime; if (!IsCoinBase()) { int64 nValueIn = 0; @@ -1513,17 +1507,29 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, CTransaction& txPrev = inputs[prevout.hash].second; if (prevout.n >= txPrev.vout.size() || prevout.n >= txindex.vSpent.size()) - return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %"PRIszu" %"PRIszu" prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); + return DoS(100, error("ConnectInputs() : %s prevout.n out of range %d %" PRIszu " %" PRIszu " prev tx %s\n%s", GetHash().ToString().substr(0,10).c_str(), prevout.n, txPrev.vout.size(), txindex.vSpent.size(), prevout.hash.ToString().substr(0,10).c_str(), txPrev.ToString().c_str())); // If prev is coinbase or coinstake, check that it's matured if (txPrev.IsCoinBase() || txPrev.IsCoinStake()) + { for (const CBlockIndex* pindex = pindexBlock; pindex && pindexBlock->nHeight - pindex->nHeight < nCoinbaseMaturity; pindex = pindex->pprev) + { if (pindex->nBlockPos == txindex.pos.nBlockPos && pindex->nFile == txindex.pos.nFile) + { return error("ConnectInputs() : tried to spend %s at depth %d", txPrev.IsCoinBase() ? "coinbase" : "coinstake", pindexBlock->nHeight - pindex->nHeight); + } + } + } - // ppcoin: check transaction timestamp - if (txPrev.nTime > nTime) - return DoS(100, error("ConnectInputs() : transaction timestamp earlier than input transaction")); + // check is meaningless if one or the other has no timestamp + if (txPrev.HasTimestamp() && HasTimestamp()) + { + // ppcoin: check transaction timestamp + if (txPrev.GetTxTime() > nTxTime) + { + return DoS(100, error("ConnectInputs() : transaction timestamp earlier than input transaction")); + } + } if (txPrev.vout[prevout.n].IsEmpty() && (GetFork(nBestHeight + 1) >= XST_FORK005)) { @@ -1579,10 +1585,10 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, { // ppcoin: coin stake tx earns reward instead of paying fee uint64 nCoinAge; - if (!GetCoinAge(txdb, nCoinAge)) + if (!GetCoinAge(txdb, pindexBlock->nTime, nCoinAge)) return error("ConnectInputs() : %s unable to get coin age for coinstake", GetHash().ToString().substr(0,10).c_str()); int64 nStakeReward = GetValueOut() - nValueIn; - if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, nTime, pindexBlock->nHeight) - GetMinFee() + MIN_TX_FEE) + if (nStakeReward > GetProofOfStakeReward(nCoinAge, pindexBlock->nBits, pindexBlock->nHeight) - GetMinFee() + MIN_TX_FEE) return DoS(100, error("ConnectInputs() : %s stake reward exceeded", GetHash().ToString().substr(0,10).c_str())); } else @@ -1607,7 +1613,6 @@ bool CTransaction::ConnectInputs(CTxDB& txdb, MapPrevTx inputs, return true; } - bool CTransaction::ClientConnectInputs() { if (IsCoinBase()) @@ -1629,7 +1634,7 @@ bool CTransaction::ClientConnectInputs() return false; unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS; - if (GetFork(nBestHeight+1) < XST_FORK005) + if (GetFork(nBestHeight + 1) < XST_FORK005) { flags = flags & ~SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } @@ -1638,16 +1643,6 @@ bool CTransaction::ClientConnectInputs() if (!VerifySignature(txPrev, *this, i, flags, 0)) return error("ConnectInputs() : VerifySignature failed"); - ///// this is redundant with the mempool.mapNextTx stuff, - ///// not sure which I want to get rid of - ///// this has to go away now that posNext is gone - // // Check for conflicts - // if (!txPrev.vout[prevout.n].posNext.IsNull()) - // return error("ConnectInputs() : prev tx already used"); - // - // // Flag outpoints as used - // txPrev.vout[prevout.n].posNext = posThisTx; - nValueIn += txPrev.vout[prevout.n].nValue; if (!MoneyRange(txPrev.vout[prevout.n].nValue) || !MoneyRange(nValueIn)) @@ -1688,10 +1683,10 @@ bool CBlock::DisconnectBlock(CTxDB& txdb, CBlockIndex* pindex) bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) { // Check it again in case a previous version let a bad block in - if (!CheckBlock(!fJustCheck, !fJustCheck)) + if (!CheckBlock(pindex->nHeight, !fJustCheck, !fJustCheck)) return false; unsigned int flags = SCRIPT_VERIFY_NOCACHE | STANDARD_SCRIPT_VERIFY_FLAGS; - if (GetFork(nBestHeight+1) < XST_FORK005) + if (GetFork(nBestHeight + 1) < XST_FORK005) { flags = flags & ~SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY; } @@ -1789,7 +1784,7 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) // ppcoin: fees are not collected by miners as in bitcoin // ppcoin: fees are destroyed to compensate the entire network if (fDebug && GetBoolArg("-printcreation")) - printf("ConnectBlock() : destroy=%s nFees=%"PRI64d"\n", FormatMoney(nFees).c_str(), nFees); + printf("ConnectBlock() : destroy=%s nFees=%" PRI64d "\n", FormatMoney(nFees).c_str(), nFees); if (fJustCheck) return true; @@ -1805,13 +1800,8 @@ bool CBlock::ConnectBlock(CTxDB& txdb, CBlockIndex* pindex, bool fJustCheck) if(pindex->pprev) { prevHash = pindex->pprev->GetBlockHash(); - // printf("==> Got prevHash = %s\n", prevHash.ToString().c_str()); } - // if (vtx[0].GetValueOut() > GetProofOfWorkReward( - // (unsigned int) pindex->nHeight, nFees, prevHash)) - // return false; - // Update block index on disk without changing it in memory. // The memory index structure will be changed after the db commits. if (pindex->pprev) @@ -1858,8 +1848,8 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) vConnect.push_back(pindex); reverse(vConnect.begin(), vConnect.end()); - printf("REORGANIZE: Disconnect %"PRIszu" blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); - printf("REORGANIZE: Connect %"PRIszu" blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Disconnect %" PRIszu " blocks; %s..%s\n", vDisconnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexBest->GetBlockHash().ToString().substr(0,20).c_str()); + printf("REORGANIZE: Connect %" PRIszu " blocks; %s..%s\n", vConnect.size(), pfork->GetBlockHash().ToString().substr(0,20).c_str(), pindexNew->GetBlockHash().ToString().substr(0,20).c_str()); // Disconnect shorter branch list vResurrect; @@ -1929,7 +1919,6 @@ bool static Reorganize(CTxDB& txdb, CBlockIndex* pindexNew) return true; } - // Called from inside SetBestChain: attaches a block to the new best chain being built bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew) { @@ -1992,7 +1981,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) } if (!vpindexSecondary.empty()) - printf("Postponing %"PRIszu" reconnects\n", vpindexSecondary.size()); + printf("Postponing %" PRIszu " reconnects\n", vpindexSecondary.size()); // Switch to new best branch if (!Reorganize(txdb, pindexIntermediate)) @@ -2041,7 +2030,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) hashBestChain.ToString().c_str(), nBestHeight, bnBestChainTrust.ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - printf("Stake checkpoint: %x\n", pindexBest->nStakeModifierChecksum); + printf("Stake checkpoint: %x\n", pindexBest->nStakeModifierChecksum); // Check the version of the last 100 blocks to see if we need to upgrade: if (!fIsInitialDownload) @@ -2079,7 +2068,7 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew) // guaranteed to be in main chain by sync-checkpoint. This rule is // introduced to help nodes establish a consistent view of the coin // age (trust score) of competing branches. -bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const +bool CTransaction::GetCoinAge(CTxDB& txdb, unsigned int nBlockTime, uint64& nCoinAge) const { CBigNum bnCentSecond = 0; // coin age in the unit of cent-seconds nCoinAge = 0; @@ -2089,29 +2078,41 @@ bool CTransaction::GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const if (IsCoinBase()) return true; + unsigned int nTxTime = HasTimestamp() ? GetTxTime() : nBlockTime; + BOOST_FOREACH(const CTxIn& txin, vin) { // First try finding the previous transaction in database CTransaction txPrev; CTxIndex txindex; if (!txPrev.ReadFromDisk(txdb, txin.prevout, txindex)) + { continue; // previous transaction not in main chain - if (nTime < txPrev.nTime) - return false; // Transaction timestamp violation - + } // Read block header CBlock block; if (!block.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) + { return false; // unable to read block of previous transaction - if (block.GetBlockTime() + nStakeMinAge > nTime) + } + unsigned int nBlockTime = block.GetBlockTime(); + unsigned int nTxPrevTime = txPrev.HasTimestamp() ? + txPrev.GetTxTime() : nBlockTime; + if (nTxTime < nTxPrevTime) + { + return false; // Transaction timestamp violation + } + + if (nBlockTime + nStakeMinAge > nTxTime) continue; // only count coins meeting min age requirement int64 nValueIn = txPrev.vout[txin.prevout.n].nValue; - bnSeconds = min(CBigNum(nTime-txPrev.nTime), MAX_COIN_SECONDS); + bnSeconds = min(CBigNum(nTxTime - nTxPrevTime), MAX_COIN_SECONDS); bnCentSecond += CBigNum(nValueIn) * bnSeconds / CENT; if (fDebug && GetBoolArg("-printcoinage")) - printf("coin age nValueIn=%"PRI64d" nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nTime - txPrev.nTime, bnCentSecond.ToString().c_str()); + printf("coin age nValueIn=%" PRI64d " nTimeDiff=%d bnCentSecond=%s\n", + nValueIn, nTxTime - nTxPrevTime, bnCentSecond.ToString().c_str()); } @@ -2131,16 +2132,20 @@ bool CBlock::GetCoinAge(uint64& nCoinAge) const BOOST_FOREACH(const CTransaction& tx, vtx) { uint64 nTxCoinAge; - if (tx.GetCoinAge(txdb, nTxCoinAge)) + if (tx.GetCoinAge(txdb, nTime, nTxCoinAge)) + { nCoinAge += nTxCoinAge; + } else + { return false; + } } if (nCoinAge == 0) // block coin age minimum 1 coin-day nCoinAge = 1; if (fDebug && GetBoolArg("-printcoinage")) - printf("block coin age total nCoinDays=%"PRI64d"\n", nCoinAge); + printf("block coin age total nCoinDays=%" PRI64d "\n", nCoinAge); return true; } @@ -2183,7 +2188,7 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u pindexNew->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier); pindexNew->nStakeModifierChecksum = GetStakeModifierChecksum(pindexNew); if (!CheckStakeModifierCheckpoints(pindexNew->nHeight, pindexNew->nStakeModifierChecksum)) - return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindexNew->nHeight, nStakeModifier); + return error("AddToBlockIndex() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016" PRI64x, pindexNew->nHeight, nStakeModifier); // Add to mapBlockIndex map::iterator mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; @@ -2219,90 +2224,137 @@ bool CBlock::AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos, const u } -bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, - bool fCheckSig) const +bool CBlock::CheckBlock(bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSig) const { // These are checks that are independent of context // that can be verified before saving an orphan block. // Size limits - if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + if (vtx.empty() || vtx.size() > MAX_BLOCK_SIZE || + ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + { return DoS(100, error("CheckBlock() : size limits failed")); + } // Check proof of work matches claimed amount if (fCheckPOW && IsProofOfWork() && !CheckProofOfWork(GetHash(), nBits)) + { return DoS(50, error("CheckBlock() : proof of work failed")); + } + + int nFork = GetFork(nBestHeight + 1); // Check timestamp - if (GetFork(nBestHeight + 1) >= XST_FORK005) + if (nFork >= XST_FORK005) { if (GetBlockTime() > FutureDrift(GetAdjustedTime())) + { return error("CheckBlock() : block timestamp too far in the future"); + } } else { if (GetBlockTime() > GetAdjustedTime() + nMaxClockDrift) + { return error("CheckBlock() : block timestamp too far in the future"); + } } // First transaction must be coinbase, the rest must not be if (vtx.empty() || !vtx[0].IsCoinBase()) + { return DoS(100, error("CheckBlock() : first tx is not coinbase")); + } for (unsigned int i = 1; i < vtx.size(); i++) + { if (vtx[i].IsCoinBase()) + { return DoS(100, error("CheckBlock() : more than one coinbase")); - + } + } // Check coinbase timestamp - if (GetFork(nBestHeight + 1) >= XST_FORK005) + if (nFork < XST_FORK005) { - if (GetBlockTime() > FutureDrift((int64)vtx[0].nTime)) - return DoS(50, error("CheckBlock() : coinbase timestamp: %" PRI64d " + 15 sec, " - "is too early for block: %" PRI64d, - (int64)vtx[0].nTime, (int64)GetBlockTime())); + // prior to XST_FORK006 CTransactions have timestamps + if (GetBlockTime() > (int64)vtx[0].GetTxTime() + nMaxClockDrift) + { + return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); + } } - else + // exclude pow because + // (1) testnet usually has too few miners to stay in future drift + // (2) main net mining is done, so there is no need to check drift, + // and also the future drift was much more at the time + // this probably should be fixed "the right way" one day + else if (vtx[0].HasTimestamp() && !IsProofOfWork()) { - if (GetBlockTime() > (int64)vtx[0].nTime + nMaxClockDrift) - return DoS(50, error("CheckBlock() : coinbase timestamp is too early")); + if (GetBlockTime() > FutureDrift((int64)vtx[0].GetTxTime())) + { + return DoS(50, error("CheckBlock() : coinbase timestamp: %" PRI64d " + 15 sec, " + "is too early for block: %" PRI64d, + (int64)vtx[0].GetTxTime(), (int64)GetBlockTime())); + } } if (IsProofOfStake()) { if (vtx[0].vout.size() != 1 || !vtx[0].vout[0].IsEmpty()) + { return DoS(100, error("CheckBlock() : coinbase output not empty for proof-of-stake block")); + } // Second transaction must be coinstake, the rest must not be if (vtx.empty() || !vtx[1].IsCoinStake()) + { return DoS(100, error("CheckBlock() : second tx is not coinstake")); + } for (unsigned int i = 2; i < vtx.size(); i++) + { if (vtx[i].IsCoinStake()) + { return DoS(100, error("CheckBlock() : more than one coinstake")); + } + } - // Check coinstake timestamp -if (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) - return DoS(50, - error("CheckBlock() : coinstake timestamp violation nTimeBlock=%" - PRI64d " nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); + // Check coinstake timestamp + // no check upon XST_FORK006 because tx timestamps eliminated, + // effectivly making tx same as block + if (vtx[1].HasTimestamp() && + (!CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].GetTxTime()))) + { + return DoS(50, + error("CheckBlock() : coinstake timestamp violation nTimeBlock=%" + PRI64d " nTimeTx=%u", GetBlockTime(), vtx[1].GetTxTime())); + } - if ((nTime >= CUTOFF_POW_TIME) && (IsProofOfWork())) - return DoS(100, error("CheckBlock() : Proof of work (%f XST) at t=%d on or after %d.\n", - ((double) vtx[0].GetValueOut() / (double) COIN), - (int) nTime, - (int) CUTOFF_POW_TIME)); - if (fCheckSig & !CheckBlockSignature()) - return DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); + if (((nBestHeight + 1) >= GetPoWCutoff()) && (IsProofOfWork())) + { + return DoS(100, error("CheckBlock() : Proof of work (%f XST) at t=%d on or after block %d.\n", + ((double) vtx[0].GetValueOut() / (double) COIN), + (int) nTime, + (int) GetPoWCutoff())); + } + if (fCheckSig & !CheckBlockSignature()) + { + return DoS(100, error("CheckBlock() : bad proof-of-stake block signature")); + } } // Check transactions BOOST_FOREACH(const CTransaction& tx, vtx) { if (!tx.CheckTransaction()) + { return DoS(tx.nDoS, error("CheckBlock() : CheckTransaction failed")); + } // ppcoin: check transaction timestamp - if (GetBlockTime() < (int64)tx.nTime) + // ignore as of XST_FORK006 as tx timestamps are thereupon eliminated + if (tx.HasTimestamp() && (GetBlockTime() < (int64)tx.GetTxTime())) + { return DoS(50, error("CheckBlock() : block timestamp earlier than transaction timestamp")); + } } // Check for duplicate txids. This is caught by ConnectInputs(), @@ -2345,17 +2397,28 @@ bool CBlock::AcceptBlock() CBlockIndex* pindexPrev = (*mi).second; int nHeight = pindexPrev->nHeight+1; - if (IsProofOfWork() && (nHeight > CUTOFF_POW_BLOCK)) + if (IsProofOfWork() && (nHeight > GetPoWCutoff())) return DoS(100, error("AcceptBlock() : No proof-of-work allowed anymore (height = %d)", nHeight)); if (GetFork(nBestHeight + 1) >= XST_FORK005) { - // Check coinbase timestamp - if (GetBlockTime() > FutureDrift((int64)vtx[0].nTime)) - return DoS(50, error("AcceptBlock() : coinbase timestamp is too early")); - // Check coinstake timestamp - if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].nTime)) - return DoS(50, error("AcceptBlock() : coinstake timestamp violation nTimeBlock=%" PRI64d " nTimeTx=%u", GetBlockTime(), vtx[1].nTime)); + if (vtx[0].HasTimestamp()) + { + // Check coinbase timestamp + if (GetBlockTime() > FutureDrift((int64)vtx[0].GetTxTime())) + { + return DoS(50, error("AcceptBlock() : coinbase timestamp is too early")); + } + } + if (vtx[1].HasTimestamp()) + { + // Check coinstake timestamp + if (IsProofOfStake() && !CheckCoinStakeTimestamp(GetBlockTime(), (int64)vtx[1].GetTxTime())) + { + return DoS(50, error("AcceptBlock() : coinstake timestamp violation nTimeBlock=%" PRI64d + " nTimeTx=%u", GetBlockTime(), vtx[1].GetTxTime())); + } + } } // Check proof-of-work or proof-of-stake @@ -2388,7 +2451,7 @@ bool CBlock::AcceptBlock() if (IsProofOfStake()) { uint256 targetProofOfStake; - if (!CheckProofOfStake(vtx[1], nBits, hashProof)) + if (!CheckProofOfStake(vtx[1], nBits, hashProof, nTime)) { printf("WARNING: AcceptBlock(): 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 @@ -2414,10 +2477,6 @@ bool CBlock::AcceptBlock() } } - // Reject block.nVersion < 3 blocks since 95% threshold on mainNet and always on testNet: - if (nVersion < 3 && ((!fTestNet && nHeight > 14060) || (fTestNet && nHeight > 0))) - return error("CheckBlock() : rejected nVersion < 3 block"); - // Enforce rule that the coinbase starts with serialized block height CScript expect = CScript() << nHeight; if (!std::equal(expect.begin(), expect.end(), vtx[0].vin[0].scriptSig.begin())) @@ -2484,7 +2543,6 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns bool ProcessBlock(CNode* pfrom, CBlock* pblock, bool fIsBootstrap) -// bool ProcessBlock(CNode* pfrom, CBlock* pblock) { // Check for duplicate uint256 hash = pblock->GetHash(); @@ -2500,32 +2558,33 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, bool fIsBootstrap) if (pblock->IsProofOfStake() && setStakeSeen.count(pblock->GetProofOfStake()) && !mapOrphanBlocksByPrev.count(hash) && !Checkpoints::WantedByPendingSyncCheckpoint(hash) & !fIsBootstrap) return error("ProcessBlock() : duplicate proof-of-stake (%s, %d) for block %s", pblock->GetProofOfStake().first.ToString().c_str(), pblock->GetProofOfStake().second, hash.ToString().c_str()); - // Preliminary checks - if (!pblock->CheckBlock()) - return error("ProcessBlock() : CheckBlock FAILED"); CBlockLocator locator; int nHeight = locator.GetBlockIndex()->nHeight; - if (pblock->IsProofOfWork() && (nHeight >= CUTOFF_POW_BLOCK)) { + // Preliminary checks + if (!pblock->CheckBlock(nHeight)) + return error("ProcessBlock() : CheckBlock FAILED"); + + if (pblock->IsProofOfWork() && (nHeight >= GetPoWCutoff())) { if (pfrom) pfrom->Misbehaving(100); - printf("Proof of work on or after block %d.\n", CUTOFF_POW_BLOCK); - return error("Proof of work on or after block %d.\n", CUTOFF_POW_BLOCK); + printf("Proof of work on or after block %d.\n", GetPoWCutoff()); + return error("Proof of work on or after block %d.\n", GetPoWCutoff()); } CBlockIndex* pcheckpoint = Checkpoints::GetLastSyncCheckpoint(); if(pcheckpoint && fDebug) { - const CBlockIndex* pindexLastPos = GetLastBlockIndex(pcheckpoint, true); + const CBlockIndex* pindexLastPos = GetLastBlockIndex(pcheckpoint, true); if(pindexLastPos) - { + { printf("ProcessBlock(): Last POS Block Height: %d \n", pindexLastPos->nHeight); - } - else - { - printf("ProcessBlock(): Previous POS block not found.\n"); - } + } + else + { + printf("ProcessBlock(): Previous POS block not found.\n"); + } } if (pcheckpoint && pblock->hashPrevBlock != hashBestChain && !Checkpoints::WantedByPendingSyncCheckpoint(hash)) @@ -2541,7 +2600,7 @@ bool ProcessBlock(CNode* pfrom, CBlock* pblock, bool fIsBootstrap) if (pblock->IsProofOfStake()) { bnRequired.SetCompact(ComputeMinStake(nLastBits, deltaTime, pblock->nTime)); - if ((nThisHeight < CUTOFF_POW_BLOCK) && (bnNewBlock > bnProofOfStakeLimit)) { + if ((nThisHeight < GetPoWCutoff()) && (bnNewBlock > bnProofOfStakeLimit)) { bnNewBlock = bnNewBlock >> 2; // adjust target for big hashes } } @@ -2816,18 +2875,18 @@ bool LoadBlockIndex(bool fAllowNew) { if (fTestNet) { - pchMessageStart[0] = 0x70; - pchMessageStart[1] = 0x35; - pchMessageStart[2] = 0x22; - pchMessageStart[3] = 0x05; + pchMessageStart[0] = 0xcf; + pchMessageStart[1] = 0xed; + pchMessageStart[2] = 0xff; + pchMessageStart[3] = 0xfd; bnProofOfStakeLimit = bnProofOfStakeLimitTestNet; // 0x00000fff PoS base target is fixed in testnet bnProofOfWorkLimit = bnProofOfWorkLimitTestNet; // 0x0000ffff PoW base target is fixed in testnet - nStakeMinAge = 15 * 60; // test net min age is 20 min - nStakeMaxAge = 60 * 60; // test net min age is 60 min - nModifierInterval = 60; // test modifier interval is 2 minutes + nStakeMinAge = 1 * 60; // test net min age is 1 min + nStakeMaxAge = 40 * 60; // test net min age is 40 min + nModifierInterval = 30; // test modifier interval is 30 seconds nCoinbaseMaturity = 10; // test maturity is 10 blocks - nStakeTargetSpacing = 3 * 60; // test block spacing is 3 minutes + nStakeTargetSpacing = 20; // test block spacing is 20 seconds } // @@ -2849,7 +2908,7 @@ bool LoadBlockIndex(bool fAllowNew) // Genesis block const char* pszTimestamp = "20140615 Stealth proves that pzTimestamp is overkill."; CTransaction txNew; - txNew.nTime = nChainStartTime; + txNew.SetTxTime(nChainStartTime); txNew.vin.resize(1); txNew.vout.resize(1); txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(9999) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp)); @@ -2864,20 +2923,20 @@ bool LoadBlockIndex(bool fAllowNew) block.nBits = bnProofOfWorkLimit.GetCompact(); block.nNonce = 4204204204LL; // perfect nonce - if (false && (block.GetHash() != hashGenesisBlock)) { - - // This will figure out a valid hash and Nonce if you're - // creating a different genesis block: + if (false && (block.GetHash() != hashGenesisBlock)) + { + // This will figure out a valid hash and Nonce if you're + // creating a different genesis block: uint256 hashTarget = CBigNum().SetCompact(block.nBits).getuint256(); while (block.GetHash() > hashTarget) - { - ++block.nNonce; - if (block.nNonce == 0) - { - printf("NONCE WRAPPED, incrementing time"); - ++block.nTime; - } - } + { + ++block.nNonce; + if (block.nNonce == 0) + { + printf("NONCE WRAPPED, incrementing time"); + ++block.nTime; + } + } } //// debug print @@ -2887,8 +2946,11 @@ bool LoadBlockIndex(bool fAllowNew) printf("block.nTime = %u \n", block.nTime); printf("block.nNonce = %u \n", block.nNonce); - assert(block.hashMerkleRoot == uint256("0xe3de7c386d5b82f62ff24c6d2351539c22b17c6ffab0e267b3cdd72fda82bd83")); - assert(block.GetHash() == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)); + uint256 hashMerkleRootMainNet("0xe3de7c386d5b82f62ff24c6d2351539c22b17c6ffab0e267b3cdd72fda82bd83"); + uint256 hashMerkleRootTestNet("0xe3de7c386d5b82f62ff24c6d2351539c22b17c6ffab0e267b3cdd72fda82bd83"); + + assert(block.hashMerkleRoot == (fTestNet ? hashMerkleRootTestNet : hashMerkleRootMainNet)); + assert(block.GetHash() == (fTestNet ? hashGenesisBlockTestNet : hashGenesisBlock)); // Start new block file unsigned int nFile; @@ -2918,14 +2980,11 @@ bool LoadBlockIndex(bool fAllowNew) if ((!fTestNet) && !Checkpoints::ResetSyncCheckpoint()) return error("LoadBlockIndex() : failed to reset sync-checkpoint"); } - //txdb.Close(); } return true; } - - void PrintBlockTree() { // pre-compute tree structure @@ -2934,9 +2993,6 @@ void PrintBlockTree() { CBlockIndex* pindex = (*mi).second; mapNext[pindex->pprev].push_back(pindex); - // test - //while (rand() % 3 == 0) - // mapNext[pindex->pprev].push_back(pindex); } vector > vStack; @@ -2971,7 +3027,7 @@ void PrintBlockTree() // print item CBlock block; block.ReadFromDisk(pindex); - printf("%d (%u,%u) %s %08x %s mint %7s tx %"PRIszu"", + printf("%d (%u,%u) %s %08x %s mint %7s tx %" PRIszu "", pindex->nHeight, pindex->nFile, pindex->nBlockPos, @@ -3057,7 +3113,7 @@ bool LoadExternalBlockFile(FILE* fileIn) __PRETTY_FUNCTION__); } } - printf("Loaded %i blocks from external file in %"PRI64d"ms\n", nLoaded, GetTimeMillis() - nStart); + printf("Loaded %i blocks from external file in %" PRI64d "ms\n", nLoaded, GetTimeMillis() - nStart); if (GetBoolArg("-quitonbootstrap", false)) { exit(EXIT_SUCCESS); @@ -3092,14 +3148,6 @@ string GetWarnings(string strFor) strStatusBar = strMiscWarning; } - // ppcoin: should not enter safe mode for longer invalid chain - // ppcoin: if sync-checkpoint is too old do not enter safe mode - if (Checkpoints::IsSyncCheckpointTooOld(60 * 60 * 24 * 365) && !fTestNet && !IsInitialBlockDownload()) - { - nPriority = 100; - strStatusBar = "WARNING: Checkpoint is too old. Wait for block chain to download, or notify developers."; - } - // ppcoin: if detected invalid checkpoint enter safe mode if (Checkpoints::hashInvalidCheckpoint != 0) { @@ -3181,7 +3229,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) static map mapReuseKey; RandAddSeedPerfmon(); if (fDebug) - printf("received: %s (%"PRIszu" bytes)\n", strCommand.c_str(), vRecv.size()); + printf("received: %s (%" PRIszu " bytes)\n", strCommand.c_str(), vRecv.size()); if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0) { printf("dropmessagestest DROPPING RECV MESSAGE\n"); @@ -3223,7 +3271,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (pfrom->nVersion < GetMinPeerProtoVersion(nBestHeight)) { // disconnect from peers older than this proto version - printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion); + printf("partner %s using obsolete version %i; disconnecting\n", + pfrom->addr.ToString().c_str(), pfrom->nVersion); pfrom->fDisconnect = true; return false; } @@ -3237,13 +3286,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (!vRecv.empty()) vRecv >> pfrom->nStartingHeight; - // if (!vRecv.empty()) - // // set to true after we get the first filter* message - // vRecv >> pfrom->fRelayTxes; - // else - // pfrom->fRelayTxes = true; - - if (pfrom->fInbound && addrMe.IsRoutable()) { pfrom->addrLocal = addrMe; @@ -3376,7 +3418,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vAddr.size() > 1000) { pfrom->Misbehaving(20); - return error("message addr size() = %"PRIszu"", vAddr.size()); + return error("message addr size() = %" PRIszu "", vAddr.size()); } // Store the new addresses @@ -3439,7 +3481,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vInv.size() > MAX_INV_SZ) { pfrom->Misbehaving(20); - return error("message inv size() = %"PRIszu"", vInv.size()); + return error("message inv size() = %" PRIszu "", vInv.size()); } // find last block in inv vector @@ -3489,11 +3531,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (vInv.size() > MAX_INV_SZ) { pfrom->Misbehaving(20); - return error("message getdata size() = %"PRIszu"", vInv.size()); + return error("message getdata size() = %" PRIszu "", vInv.size()); } if (fDebugNet || (vInv.size() != 1)) - printf("received getdata (%"PRIszu" invsz)\n", vInv.size()); + printf("received getdata (%" PRIszu " invsz)\n", vInv.size()); BOOST_FOREACH(const CInv& inv, vInv) { @@ -3894,21 +3936,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) bool ProcessMessages(CNode* pfrom) { - if (fDebug) { - printf("ProcessMessages: %s\n", - pfrom->addr.ToString().c_str()); - } + // if (fDebug) { + // printf("ProcessMessages: %s\n", + // pfrom->addr.ToString().c_str()); + // } CDataStream& vRecv = pfrom->vRecv; if (vRecv.empty()) { - if (fDebug) - { - printf("ProcessMessages: %s [empty]\n", - pfrom->addr.ToString().c_str()); - } + // if (fDebug) + // { + // printf("ProcessMessages: %s [empty]\n", + // pfrom->addr.ToString().c_str()); + // } return true; } - //if (fDebug) - // printf("ProcessMessages(%u bytes)\n", vRecv.size()); // // Message format @@ -3938,7 +3978,7 @@ bool ProcessMessages(CNode* pfrom) break; } if (pstart - vRecv.begin() > 0) - printf("\n\nPROCESSMESSAGE SKIPPED %"PRIpdd" BYTES\n\n", pstart - vRecv.begin()); + printf("\n\nPROCESSMESSAGE SKIPPED %" PRIpdd " BYTES\n\n", pstart - vRecv.begin()); vRecv.erase(vRecv.begin(), pstart); // Read header @@ -4203,7 +4243,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) ////////////////////////////////////////////////////////////////////////////// // -// BitcoinMiner +// StealthMinter // int static FormatHashBlocks(void* pbuffer, unsigned int len) @@ -4222,7 +4262,10 @@ int static FormatHashBlocks(void* pbuffer, unsigned int len) } static const unsigned int pSHA256InitState[8] = -{0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19}; + {0x6a09e667, 0xbb67ae85, + 0x3c6ef372, 0xa54ff53a, + 0x510e527f, 0x9b05688c, + 0x1f83d9ab, 0x5be0cd19}; void SHA256Transform(void* pstate, void* pinput, const void* pinit) { @@ -4302,9 +4345,16 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) CReserveKey reservekey(pwallet); // Create new block - auto_ptr pblock(new CBlock()); + #if __cplusplus >= 201103L + unique_ptr pblock(new CBlock()); + #else + auto_ptr pblock(new CBlock()); + #endif + if (!pblock.get()) + { return NULL; + } CBlockIndex* pindexPrev = pindexBest; @@ -4341,35 +4391,62 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) // cost to you of processing a transaction. int64 nMinTxFee = MIN_TX_FEE; if (mapArgs.count("-mintxfee")) + { ParseMoney(mapArgs["-mintxfee"], nMinTxFee); + } + + int nFork = GetFork(nHeight); // ppcoin: if coinstake available add coinstake tx - static int64 nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup + // only initialized at startup + static unsigned int nLastCoinStakeSearchTime = (unsigned int) GetAdjustedTime(); + + unsigned int nCoinStakeTime = (unsigned int) GetAdjustedTime(); if (fProofOfStake) // attempt to find a coinstake { pblock->nBits = GetNextTargetRequired(pindexPrev, true); CTransaction txCoinStake; - int64 nSearchTime = txCoinStake.nTime; // search to current time + + // Upon XST_FORK006, transactions don't have meaningful timestamps. + // However to use the logic of this function for now, nCoinStakeTime will + // be used to hold the block timestamp. Upon XST_FORK006, the block + // timestamp will be a permanent record of its transaction timestamps. + if (txCoinStake.HasTimestamp()) + { + txCoinStake.SetTxTime(nCoinStakeTime); + } + + unsigned int nSearchTime = nCoinStakeTime; // search to current time if (nSearchTime > nLastCoinStakeSearchTime) { - // printf(">>> OK1\n"); - if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake)) + if (pwallet->CreateCoinStake(*pwallet, pblock->nBits, + nSearchTime - nLastCoinStakeSearchTime, txCoinStake, nCoinStakeTime)) { - int nTimeMax; - if (GetFork(nHeight) >= XST_FORK005) + unsigned int nTimeMax; + if (nFork < XST_FORK005) { - nTimeMax = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime()); + nTimeMax = max(pindexPrev->GetPastTimeLimit()+1, pindexPrev->GetBlockTime() - nMaxClockDrift); } else { - nTimeMax = max(pindexPrev->GetPastTimeLimit()+1, pindexPrev->GetBlockTime() - nMaxClockDrift); + if (nFork >= XST_FORK006) + { + pblock->nTime = nCoinStakeTime; + } + nTimeMax = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime()); } - if (txCoinStake.nTime >= (unsigned int) nTimeMax) + + if (nCoinStakeTime >= nTimeMax) { // 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; + // this test simply marks that assinging tx ntime upon creation + // will be eliminated in the future + if (pblock->vtx[0].HasTimestamp()) + { + pblock->vtx[0].SetTxTime(nCoinStakeTime); + } pblock->vtx.push_back(txCoinStake); } } @@ -4493,8 +4570,16 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) continue; // Timestamp limit - if (tx.nTime > GetAdjustedTime() || (pblock->IsProofOfStake() && tx.nTime > pblock->vtx[1].nTime)) - continue; + if (tx.HasTimestamp()) + { + if ( (tx.GetTxTime() > GetAdjustedTime()) || + ( pblock->IsProofOfStake() && + (pblock->vtx[1].HasTimestamp()) && + (tx.GetTxTime() > pblock->vtx[1].GetTxTime()) ) ) + { + continue; + } + } // ppcoin: simplify transaction fee - allow free = false int64 nMinFee = tx.GetMinFee(nBlockSize, false, GMF_BLOCK); @@ -4571,34 +4656,44 @@ CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake) nLastBlockSize = nBlockSize; if (fDebug && GetBoolArg("-printpriority")) - printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize); + { + printf("CreateNewBlock(): total size %" PRI64u "\n", nBlockSize); + } if (pblock->IsProofOfWork()) + { pblock->vtx[0].vout[0].nValue = GetProofOfWorkReward((unsigned int) nHeight, - nFees, pindexPrev->GetBlockHash()); + nFees, pindexPrev->GetBlockHash()); + } // Fill in header - pblock->hashPrevBlock = pindexPrev->GetBlockHash(); + pblock->hashPrevBlock = pindexPrev->GetBlockHash(); if (pblock->IsProofOfStake()) - pblock->nTime = pblock->vtx[1].nTime; //same as coinstake timestamp - pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, pblock->GetMaxTransactionTime()); - if (GetFork(nHeight) >= XST_FORK005) { - pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime()); + pblock->nTime = nCoinStakeTime; } - else + if (nFork < XST_FORK006) + { + pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, pblock->GetMaxTransactionTime()); + } + if (nFork < XST_FORK005) { pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); } + else + { + pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetPastTimeLimit()+1); + } if (pblock->IsProofOfWork()) + { pblock->UpdateTime(pindexPrev); - pblock->nNonce = 0; + } + pblock->nNonce = 0; } return pblock.release(); } - void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce) { // Update nExtraNonce @@ -4670,10 +4765,10 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); if (hash > hashTarget && pblock->IsProofOfWork()) - return error("BitcoinMiner : proof-of-work not meeting target"); + return error("CheckWork() : proof-of-work not meeting target"); //// debug print - printf("BitcoinMiner:\n"); + printf("CheckWork:\n"); printf("new 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()); @@ -4682,7 +4777,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) { 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(); @@ -4695,31 +4790,31 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // 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; } -void static ThreadBitcoinMiner(void* parg); +void static ThreadStealthMinter(void* parg); -static bool fGenerateBitcoins = false; +static bool fGenerateXST = false; static bool fLimitProcessors = false; static int nLimitProcessors = -1; -void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) +void StealthMinter(CWallet *pwallet, bool fProofOfStake) { - printf("CPUMiner started for proof-of-%s\n", fProofOfStake? "stake" : "work"); + printf("CPUMinter started for proof-of-%s\n", fProofOfStake? "stake" : "work"); SetThreadPriority(THREAD_PRIORITY_LOWEST); // Make this thread recognisable as the mining thread - RenameThread("bitcoin-miner"); + RenameThread("stealth-minter"); // Each thread has its own key and counter CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; - while (fGenerateBitcoins || fProofOfStake) + while (fGenerateXST || fProofOfStake) { if (fShutdown) return; @@ -4730,7 +4825,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) Sleep(1000); if (fShutdown) return; - if (!fGenerateBitcoins && !fProofOfStake) + if (!fGenerateXST && !fProofOfStake) return; } @@ -4746,7 +4841,11 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) int nHeight = pindexPrev->nHeight + 1; // int64_t nFees; - auto_ptr pblock(CreateNewBlock(pwallet, fProofOfStake)); + #if __cplusplus >= 201103L + unique_ptr pblock(CreateNewBlock(pwallet, fProofOfStake)); + #else + auto_ptr pblock(CreateNewBlock(pwallet, fProofOfStake)); + #endif if (!pblock.get()) return; IncrementExtraNonce(pblock.get(), pindexPrev, nExtraNonce); @@ -4768,34 +4867,21 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) continue; } - printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(), + printf("Running StealthMinter with %" PRIszu " transactions in block (%u bytes)\n", pblock->vtx.size(), ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - // - // Pre-build hash buffers - // - //char pmidstatebuf[32+16]; char* pmidstate = alignup<16>(pmidstatebuf); - //char pdatabuf[128+16]; char* pdata = alignup<16>(pdatabuf); - //char phash1buf[64+16]; char* phash1 = alignup<16>(phash1buf); - - //FormatHashBuffers(pblock.get(), pmidstate, pdata, phash1); - - //unsigned int& nBlockTime = *(unsigned int*)(pdata + 64 + 4); - //unsigned int& nBlockNonce = *(unsigned int*)(pdata + 64 + 12); - - // // Search // int64 nStart = GetTime(); uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256(); - uint256 hash; + uint256 hash; LOOP { - hash = pblock->GetHash(); - if (hash <= hashTarget){ - // nHashesDone += pblock->nNonce; + hash = pblock->GetHash(); + if (hash <= hashTarget) + { if (!pblock->SignBlock(*pwalletMain)) break; @@ -4810,7 +4896,6 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) } ++pblock->nNonce; - // Meter hashes/sec static int64 nHashCounter; if (nHPSTimerStart == 0) @@ -4832,7 +4917,7 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) nHPSTimerStart = GetTimeMillis(); nHashCounter = 0; - printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINER], dHashesPerSec/1000.0); + printf("hashmeter %3d CPUs %6.0f khash/s\n", vnThreadsRunning[THREAD_MINTER], dHashesPerSec/1000.0); } } @@ -4841,9 +4926,9 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) // Check for stop or if block needs to be rebuilt if (fShutdown) return; - if (!fGenerateBitcoins) + if (!fGenerateXST) return; - if (fLimitProcessors && vnThreadsRunning[THREAD_MINER] > nLimitProcessors) + if (fLimitProcessors && vnThreadsRunning[THREAD_MINTER] > nLimitProcessors) return; if (vNodes.empty()) break; @@ -4854,60 +4939,66 @@ void BitcoinMiner(CWallet *pwallet, bool fProofOfStake) if (pindexPrev != pindexBest) break; + int nFork = GetFork(nHeight); + // Update nTime every few seconds - pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, pblock->GetMaxTransactionTime()); - if (GetFork(nHeight) >= XST_FORK005) + if (nFork < XST_FORK006) { - pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime()); + pblock->nTime = max(pindexPrev->GetPastTimeLimit()+1, pblock->GetMaxTransactionTime()); } - else + if (nFork < XST_FORK005) { pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - nMaxClockDrift); } + else + { + pblock->nTime = max(pblock->GetBlockTime(), pindexPrev->GetBlockTime()+1); + } pblock->UpdateTime(pindexPrev); - if (GetFork(nHeight) >= XST_FORK005) + // coinbase timestamp is irrelevant upon XST_FORK006 + if (nFork < XST_FORK005) { - if (pblock->GetBlockTime() >= FutureDrift((int64)pblock->vtx[0].nTime)) + if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].GetTxTime() + nMaxClockDrift) break; // need to update coinbase timestamp } - else + else if (nFork < XST_FORK006) { - if (pblock->GetBlockTime() >= (int64)pblock->vtx[0].nTime + nMaxClockDrift) + if (pblock->GetBlockTime() >= FutureDrift((int64)pblock->vtx[0].GetTxTime())) break; // need to update coinbase timestamp } } } } -void static ThreadBitcoinMiner(void* parg) +void static ThreadStealthMinter(void* parg) { CWallet* pwallet = (CWallet*)parg; try { - vnThreadsRunning[THREAD_MINER]++; - BitcoinMiner(pwallet, false); - vnThreadsRunning[THREAD_MINER]--; + vnThreadsRunning[THREAD_MINTER]++; + StealthMinter(pwallet, false); + vnThreadsRunning[THREAD_MINTER]--; } catch (std::exception& e) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(&e, "ThreadBitcoinMiner()"); + vnThreadsRunning[THREAD_MINTER]--; + PrintException(&e, "ThreadStealthMinter()"); } catch (...) { - vnThreadsRunning[THREAD_MINER]--; - PrintException(NULL, "ThreadBitcoinMiner()"); + vnThreadsRunning[THREAD_MINTER]--; + PrintException(NULL, "ThreadStealthMinter()"); } nHPSTimerStart = 0; - if (vnThreadsRunning[THREAD_MINER] == 0) + if (vnThreadsRunning[THREAD_MINTER] == 0) dHashesPerSec = 0; - printf("ThreadBitcoinMiner exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINER]); + printf("ThreadStealthMinter exiting, %d threads remaining\n", vnThreadsRunning[THREAD_MINTER]); } -void GenerateBitcoins(bool fGenerate, CWallet* pwallet) +void GenerateXST(bool fGenerate, CWallet* pwallet) { - fGenerateBitcoins = fGenerate; + fGenerateXST = fGenerate; nLimitProcessors = GetArg("-genproclimit", -1); if (nLimitProcessors == 0) - fGenerateBitcoins = false; + fGenerateXST = false; fLimitProcessors = (nLimitProcessors != -1); if (fGenerate) @@ -4918,12 +5009,12 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet) nProcessors = 1; if (fLimitProcessors && nProcessors > nLimitProcessors) nProcessors = nLimitProcessors; - int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINER]; - printf("Starting %d BitcoinMiner threads\n", nAddThreads); + int nAddThreads = nProcessors - vnThreadsRunning[THREAD_MINTER]; + printf("Starting %d StealthMinter threads\n", nAddThreads); for (int i = 0; i < nAddThreads; i++) { - if (!NewThread(ThreadBitcoinMiner, pwallet)) - printf("Error: NewThread(ThreadBitcoinMiner) failed\n"); + if (!NewThread(ThreadStealthMinter, pwallet)) + printf("Error: NewThread(ThreadStealthMinter) failed\n"); Sleep(10); } } diff --git a/src/main.h b/src/main.h index 0134602..892211f 100644 --- a/src/main.h +++ b/src/main.h @@ -45,14 +45,9 @@ static const int64 MIN_RELAY_TX_FEE = 1 * CENT; static const int64 MAX_MONEY = COIN * 43300000; // 23.3 Million -> 43.3 bumped to be safe static const int64 CIRCULATION_MONEY = MAX_MONEY; static const double TAX_PERCENTAGE = 0.00; //no tax -// 20% annual interest +// main net: 20% annual interest static const int64 MAX_STEALTH_PROOF_OF_STAKE = 0.20 * COIN; -// too many problems with PoW+PoS and big hashes -// static const unsigned int CUTOFF_POW_BLOCK = 20421; -static const int CUTOFF_POW_BLOCK = 5460; -static const unsigned int CUTOFF_POW_TIME = 1405125188; -// Thu Oct 9 00:00:00 2014 MST -static const unsigned int STEALTH_ADDR_KICK_IN = 1412834400; +static const int64 MAX_STEALTH_PROOF_OF_STAKE_TESTNET = 20 * COIN; static const int64 MIN_TXOUT_AMOUNT = MIN_TX_FEE; @@ -69,14 +64,15 @@ static const uint256 hashGenesisBlockOfficial( static const uint256 hashGenesisBlockTestNet ( "0x3dd6302f58a524d7c0bf7a8ee945cab05e2367bed482193eddecbb2a4c3bc634"); - // cloners: add your new forks higher than highest here // keep existing // also, rewrite GetFork enum ForkNumbers { - XST_LAUNCH = 0, + XST_GENESIS = 0, + XST_FORK004, XST_FORK005, + XST_FORK006, TOTAL_FORKS }; @@ -90,6 +86,13 @@ static const int64 nMaxClockDrift = 2 * 60 * 60; // two hours inline int64 FutureDrift(int64 nTime) { return fTestNet ? nTime + 7 : nTime + 17; } // up to 17 sec in the future +inline int GetPoWCutoff() +{ + // too many problems with PoW+PoS and big hashes, was block 20421 + static const int CUTOFF_POW_BLOCK_MNET = 5460; + static const int CUTOFF_POW_BLOCK_TNET = 120; + return fTestNet ? CUTOFF_POW_BLOCK_TNET : CUTOFF_POW_BLOCK_MNET; +} extern CScript COINBASE_FLAGS; @@ -148,23 +151,24 @@ CBlockIndex* FindBlockByHeight(int nHeight); bool ProcessMessages(CNode* pfrom); bool SendMessages(CNode* pto, bool fSendTrickle); bool LoadExternalBlockFile(FILE* fileIn); -void GenerateBitcoins(bool fGenerate, CWallet* pwallet); +void GenerateXST(bool fGenerate, CWallet* pwallet); CBlock* CreateNewBlock(CWallet* pwallet, bool fProofOfStake=false); 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 CheckProofOfWork(uint256 hash, unsigned int nBits); int64 GetProofOfWorkReward(int nHeight, int64 nFees, uint256 prevHash); -int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight); +int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, int nHeight); unsigned int ComputeMinWork(unsigned int nBase, int64 nTime); unsigned int ComputeMinStake(unsigned int nBase, int64 nTime, unsigned int nBlockTime); int GetNumBlocksOfPeers(); bool IsInitialBlockDownload(); std::string GetWarnings(std::string strFor); -bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock); +bool GetTransaction(const uint256 &hash, CTransaction &tx, + uint256 &hashBlock, unsigned int &nTimeBlock); uint256 WantedByOrphan(const CBlock* pblockOrphan); const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake); -void BitcoinMiner(CWallet *pwallet, bool fProofOfStake); +void StealthMinter(CWallet *pwallet, bool fProofOfStake); void ResendWalletTransactions(); @@ -487,11 +491,14 @@ typedef std::map > MapPrevTx; */ class CTransaction { +private: + unsigned int _nTime; public: - static const int CURRENT_VERSION=1; + static const int GENESIS_VERSION=1; + static const int NOTXTIME_VERSION=2; + static const int CURRENT_VERSION=NOTXTIME_VERSION; int nVersion; - unsigned int nTime; std::vector vin; std::vector vout; unsigned int nLockTime; @@ -509,9 +516,9 @@ class CTransaction ( READWRITE(this->nVersion); nVersion = this->nVersion; - if (this->nVersion < 2) + if (this->nVersion < CTransaction::NOTXTIME_VERSION) { - READWRITE(nTime); + READWRITE(_nTime); } READWRITE(vin); READWRITE(vout); @@ -520,8 +527,15 @@ class CTransaction void SetNull() { - nVersion = CTransaction::CURRENT_VERSION; - nTime = GetAdjustedTime(); + if (GetFork(nBestHeight) < XST_FORK006) + { + nVersion = CTransaction::GENESIS_VERSION; + } + else + { + nVersion = CTransaction::CURRENT_VERSION; + } + _nTime = GetAdjustedTime(); vin.clear(); vout.clear(); nLockTime = 0; @@ -533,9 +547,26 @@ class CTransaction return (vin.empty() && vout.empty()); } + // upon XST_FORK006 txid hash does not include signatures + // this allows the tx hash to be signed, + // making the txid immutable without invalidating sigs uint256 GetHash() const { - return SerializeHash(*this); + // mining software expects filled coinbase script sigs + if (HasTimestamp() || IsCoinBase()) + { + return SerializeHash(*this); + } + else + { + CTransaction txTmp(*this); + // Blank the sigs + for (unsigned int i = 0; i < txTmp.vin.size(); i++) + { + txTmp.vin[i].scriptSig = CScript(); + } + return SerializeHash(txTmp); + } } bool IsFinal(int nBlockHeight=0, int64 nBlockTime=0) const @@ -689,13 +720,57 @@ class CTransaction return true; } + bool HasTimestamp() const + { + return (nVersion < CTransaction::NOTXTIME_VERSION); + } + + unsigned int GetTxTime() const + { + return _nTime; + } + + void SetTxTime(unsigned int nNewTime) + { + _nTime = nNewTime; + } + + void AdjustTime(int nAdjustment) + { + // take care not to wrap an unsigned int + if (nAdjustment < 0) + { + if (-nAdjustment >= (int)_nTime) + { + _nTime = 0; + } + else + { + _nTime += nAdjustment; + } + } + // sanity check + else if (nAdjustment <= (int)_nTime) + { + _nTime += nAdjustment; + } + else + { + _nTime += _nTime; + } + } + 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); + if (a.HasTimestamp() && b.HasTimestamp() && + (a.GetTxTime() != b.GetTxTime())) + { + return false; + } + return (a.nVersion == b.nVersion && + a.vin == b.vin && + a.vout == b.vout && + a.nLockTime == b.nLockTime); } friend bool operator!=(const CTransaction& a, const CTransaction& b) @@ -714,9 +789,9 @@ class CTransaction { std::string str; str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction"); - str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%"PRIszu", vout.size=%"PRIszu", nLockTime=%d)\n", + str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%" PRIszu ", vout.size=%" PRIszu ", nLockTime=%d)\n", GetHash().ToString().substr(0,10).c_str(), - nTime, + _nTime, nVersion, vin.size(), vout.size(), @@ -772,7 +847,8 @@ class CTransaction bool ClientConnectInputs(); bool CheckTransaction() const; bool AcceptToMemoryPool(CTxDB& txdb, bool fCheckInputs=true, bool* pfMissingInputs=NULL); - bool GetCoinAge(CTxDB& txdb, uint64& nCoinAge) const; // ppcoin: get transaction coin age + // ppcoin: get transaction coin age + bool GetCoinAge(CTxDB& txdb, unsigned int nBlockTime, uint64& nCoinAge) const; protected: const CTxOut& GetOutputFor(const CTxIn& input, const MapPrevTx& inputs) const; @@ -1017,7 +1093,15 @@ class CBlock std::pair GetProofOfStake() const { - return IsProofOfStake()? std::make_pair(vtx[1].vin[0].prevout, vtx[1].nTime) : std::make_pair(COutPoint(), (unsigned int)0); + if (IsProofOfStake()) + { + unsigned int nTxTime = vtx[1].HasTimestamp() ? vtx[1].GetTxTime() : nTime; + return std::make_pair(vtx[1].vin[0].prevout, nTxTime); + } + else + { + return std::make_pair(COutPoint(), (unsigned int)0); + } } // ppcoin: get max transaction timestamp @@ -1025,7 +1109,17 @@ class CBlock { int64 maxTransactionTime = 0; BOOST_FOREACH(const CTransaction& tx, vtx) - maxTransactionTime = std::max(maxTransactionTime, (int64)tx.nTime); + { + if (tx.HasTimestamp()) + { + maxTransactionTime = std::max(maxTransactionTime, + (int64)tx.GetTxTime()); + } + } + if ((maxTransactionTime == 0) && ((vtx.size() > 0))) + { + maxTransactionTime = nTime; + } return maxTransactionTime; } @@ -1136,7 +1230,7 @@ class CBlock void print() const { - printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%"PRIszu", vchBlockSig=%s)\n", + printf("CBlock(hash=%s, ver=%d, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%" PRIszu ", vchBlockSig=%s)\n", GetHash().ToString().c_str(), nVersion, hashPrevBlock.ToString().c_str(), @@ -1265,7 +1359,14 @@ class CBlockIndex { SetProofOfStake(); prevoutStake = block.vtx[1].vin[0].prevout; - nStakeTime = block.vtx[1].nTime; + if (block.vtx[1].HasTimestamp()) + { + nStakeTime = block.vtx[1].GetTxTime(); + } + else + { + nStakeTime = nTime; + } } else { @@ -1405,7 +1506,7 @@ class CBlockIndex std::string ToString() const { - return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016"PRI64x", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", + return strprintf("CBlockIndex(nprev=%p, pnext=%p, nFile=%u, nBlockPos=%-6d nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016" PRI64x ", nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)", pprev, pnext, nFile, nBlockPos, nHeight, FormatMoney(nMint).c_str(), FormatMoney(nMoneySupply).c_str(), GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW", diff --git a/src/net.cpp b/src/net.cpp index e56c593..48c194c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -509,7 +509,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest, int64 nTimeout) if (fDebug) { printf("ConnectNode(): pszDest: %s\n", pszDest); } - + /// debug print printf("trying connection %s lastseen=%.1fhrs\n", @@ -802,8 +802,8 @@ void ThreadSocketHandler2(void* parg) vNodesUnsecure.push_back(pnode); } } - if ( - 0 > 2 * secured - 3 * unsecured + if (// don't remove unsecure nodes if no secure nodes + (secured > 0) && (0 > 2 * secured - 3 * unsecured) ) { random_shuffle(vNodesUnsecure.begin(), vNodesUnsecure.end(), GetRandInt); printf("removing unsecured connection %s\n", (*vNodesUnsecure.begin())->addr.ToString().c_str()); @@ -894,8 +894,10 @@ void ThreadSocketHandler2(void* parg) int nInbound = 0; if (hSocket != INVALID_SOCKET) + { if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr)) printf("Warning: Unknown socket family\n"); + } { LOCK(cs_vNodes); @@ -914,6 +916,7 @@ void ThreadSocketHandler2(void* parg) { { LOCK(cs_setservAddNodeAddresses); + printf("max connections reached\n"); if (!setservAddNodeAddresses.count(addr)) closesocket(hSocket); } @@ -961,7 +964,7 @@ void ThreadSocketHandler2(void* parg) if (nPos > ReceiveBufferSize()) { if (!pnode->fDisconnect) - printf("socket recv flood control disconnect (%"PRIszu" bytes)\n", vRecv.size()); + printf("socket recv flood control disconnect (%" PRIszu " bytes)\n", vRecv.size()); pnode->CloseSocketDisconnect(); } else { @@ -1268,7 +1271,7 @@ void DumpAddresses() CAddrDB adb; adb.Write(addrman); - printf("Flushed %d addresses to peers.dat %"PRI64d"ms\n", + printf("Flushed %d addresses to peers.dat %" PRI64d "ms\n", addrman.size(), GetTimeMillis() - nStart); } @@ -1347,7 +1350,7 @@ void static ThreadStakeMinter(void* parg) try { vnThreadsRunning[THREAD_STEALTHER]++; - BitcoinMiner(pwallet, true); + StealthMinter(pwallet, true); vnThreadsRunning[THREAD_STEALTHER]--; } catch (std::exception& e) { @@ -1926,7 +1929,7 @@ void StartNode(void* parg) } // Generate coins in the background - GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain); + GenerateXST(GetBoolArg("-gen", false), pwalletMain); } @@ -1954,7 +1957,7 @@ bool StopNode() if (vnThreadsRunning[THREAD_SOCKETHANDLER] > 0) printf("ThreadSocketHandler still running\n"); if (vnThreadsRunning[THREAD_OPENCONNECTIONS] > 0) printf("ThreadOpenConnections still running\n"); if (vnThreadsRunning[THREAD_MESSAGEHANDLER] > 0) printf("ThreadMessageHandler still running\n"); - if (vnThreadsRunning[THREAD_MINER] > 0) printf("ThreadBitcoinMiner still running\n"); + if (vnThreadsRunning[THREAD_MINTER] > 0) printf("ThreadStealthMinter still running\n"); if (vnThreadsRunning[THREAD_RPCLISTENER] > 0) printf("ThreadRPCListener still running\n"); if (vnThreadsRunning[THREAD_RPCHANDLER] > 0) printf("ThreadsRPCServer still running\n"); #ifdef USE_UPNP diff --git a/src/net.h b/src/net.h index 3181763..3fc13cf 100644 --- a/src/net.h +++ b/src/net.h @@ -100,7 +100,7 @@ enum threadId THREAD_SOCKETHANDLER, THREAD_OPENCONNECTIONS, THREAD_MESSAGEHANDLER, - THREAD_MINER, + THREAD_MINTER, THREAD_RPCLISTENER, THREAD_UPNP, THREAD_DNSSEED, @@ -330,7 +330,7 @@ class CNode // the key is the earliest time the request can be sent int64& nRequestTime = mapAlreadyAskedFor[inv]; if (fDebugNet) - printf("askfor %s %"PRI64d" (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); + printf("askfor %s %" PRI64d " (%s)\n", inv.ToString().c_str(), nRequestTime, DateTimeStrFormat("%H:%M:%S", nRequestTime/1000000).c_str()); // Make sure not to reuse time indexes to keep things in the same order int64 nNow = (GetTime() - 1) * 1000000; diff --git a/src/onionseed.h b/src/onionseed.h index 6c0e1df..d66ec62 100644 --- a/src/onionseed.h +++ b/src/onionseed.h @@ -17,6 +17,7 @@ static const char *strMainNetOnionSeed[][1] = { }; static const char *strTestNetOnionSeed[][1] = { + // {"cbakvnfjvpb7hfxe.onion"}, {NULL} }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index a75d105..3b7e8bf 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -922,7 +922,8 @@ void BitcoinGUI::unlockWalletForTxn() { return; } // Unlock wallet when requested by wallet model - if((walletModel->getEncryptionStatus() == WalletModel::Locked) || fWalletUnlockMintOnly) + if ((walletModel->getEncryptionStatus() == WalletModel::Locked) || + fWalletUnlockMintOnly) { AskPassphraseDialog::Mode mode = AskPassphraseDialog::UnlockTxn; AskPassphraseDialog dlg(mode, this); diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index efdba55..b789e6b 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -680,7 +680,7 @@ void CoinControlDialog::updateView() itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly // date - itemOutput->setText(COLUMN_DATE, QDateTime::fromTime_t(out.tx->GetTxTime()).toUTC().toString("yy-MM-dd hh:mm")); + itemOutput->setText(COLUMN_DATE, QDateTime::fromTime_t(out.tx->GetWTxTime()).toUTC().toString("yy-MM-dd hh:mm")); // immature PoS reward if (out.tx->IsCoinStake() && out.tx->GetBlocksToMaturity() > 0 && out.tx->GetDepthInMainChain() > 0) { diff --git a/src/qt/editaddressdialog.cpp b/src/qt/editaddressdialog.cpp index e0f69ed..575f0a8 100644 --- a/src/qt/editaddressdialog.cpp +++ b/src/qt/editaddressdialog.cpp @@ -25,9 +25,12 @@ EditAddressDialog::EditAddressDialog(Mode mode, QWidget *parent) : setWindowTitle(tr("New receiving address")); ui->addressEdit->setEnabled(false); ui->addressEdit->setVisible(false); - if(fTestNet || (pindexBest->nTime >= STEALTH_ADDR_KICK_IN)){ + if (GetFork(pindexBest->nHeight) >= XST_FORK004) + { ui->stealthCB->setEnabled(true); - }else{ + } + else + { ui->stealthCB->setEnabled(false); } ui->stealthCB->setVisible(true); diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index a434102..a07cb3b 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -40,7 +40,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx) strHTML.reserve(4000); strHTML += ""; - int64 nTime = wtx.GetTxTime(); + int64 nTime = wtx.GetWTxTime(); int64 nCredit = wtx.GetCredit(); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index ecd7353..b6f1b22 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -25,7 +25,7 @@ bool TransactionRecord::showTransaction(const CWalletTx &wtx) QList TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList parts; - int64 nTime = wtx.GetTxTime(); + int64 nTime = wtx.GetWTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ec677a7..552a758 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -240,9 +240,9 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(const QListIsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""))); result.push_back(Pair("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex())); result.push_back(Pair("entropybit", (int)blockindex->GetStakeEntropyBit())); - result.push_back(Pair("modifier", strprintf("%016"PRI64x, blockindex->nStakeModifier))); + result.push_back(Pair("modifier", strprintf("%016" PRI64x, blockindex->nStakeModifier))); result.push_back(Pair("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum))); Array txinfo; BOOST_FOREACH (const CTransaction& tx, block.vtx) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 602ff2e..46a1599 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -45,7 +45,7 @@ Value setgenerate(const Array& params, bool fHelp) } mapArgs["-gen"] = (fGenerate ? "1" : "0"); - GenerateBitcoins(fGenerate, pwalletMain); + GenerateXST(fGenerate, pwalletMain); return Value::null; } @@ -434,11 +434,14 @@ Value getblocktemplate(const Array& params, bool fHelp) static CBlockIndex* pindexPrev; static int64 nStart; static CBlock* pblock; + int64 nTxTime = pblock->vtx[0].HasTimestamp() ? + (int64) pblock->vtx[0].GetTxTime() : + (int64) pblock->GetBlockTime(); if ((pindexPrev != pindexBest) || (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 5) || ((GetFork(pindexBest->nHeight + 1) >= XST_FORK005) && // give it 12 seconds for a new getwork (because future drift is only 15 s) - (pblock->GetBlockTime() >= FutureDrift((int64)pblock->vtx[0].nTime) + 12))) + (pblock->GetBlockTime() >= FutureDrift(nTxTime) + 12))) { // Clear pindexPrev so future calls make a new block, despite any failures from here on pindexPrev = NULL; diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 49b99eb..6021e45 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -63,7 +63,7 @@ Value getpeerinfo(const Array& params, bool fHelp) Object obj; obj.push_back(Pair("addr", stats.addrName)); - obj.push_back(Pair("services", strprintf("%08"PRI64x, stats.nServices))); + obj.push_back(Pair("services", strprintf("%08" PRI64x, stats.nServices))); obj.push_back(Pair("lastsend", (boost::int64_t)stats.nLastSend)); obj.push_back(Pair("lastrecv", (boost::int64_t)stats.nLastRecv)); obj.push_back(Pair("conntime", (boost::int64_t)stats.nTimeConnected)); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 3379395..73336c3 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -54,7 +54,10 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry) { entry.push_back(Pair("txid", tx.GetHash().GetHex())); entry.push_back(Pair("version", tx.nVersion)); - entry.push_back(Pair("time", (boost::int64_t)tx.nTime)); + if (tx.HasTimestamp()) + { + entry.push_back(Pair("time", (boost::int64_t)tx.GetTxTime())); + } entry.push_back(Pair("locktime", (boost::int64_t)tx.nLockTime)); Array vin; BOOST_FOREACH(const CTxIn& txin, tx.vin) @@ -127,7 +130,8 @@ Value getrawtransaction(const Array& params, bool fHelp) CTransaction tx; uint256 hashBlock = 0; - if (!GetTransaction(hash, tx, hashBlock)) + unsigned int nTimeBlock; + if (!GetTransaction(hash, tx, hashBlock, nTimeBlock)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); @@ -504,7 +508,13 @@ string sendtoaddresswithtime(string sAddress, int64 nAmount, unsigned int nTime) throw JSONRPCError(-101, "Send amount too small"); CWalletTx wtx; - wtx.nTime = nTime; + + if (!wtx.HasTimestamp()) + { + throw JSONRPCError(RPC_WALLET_ERROR, "Transactions no longer have timestamps."); + } + + wtx.SetTxTime(nTime); if (pwalletMain->IsLocked()) throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, @@ -574,13 +584,22 @@ Value decryptsend(const Array& params, bool fHelp) return string("<>"); } + // StealthText is going to be unsupported upon FORK006 + // because replay prevention relies on timestamps for uids. + // If there seems to be demand, I will work out replay attacks + // probably by including a uid in OP_RETURN. + if (GetFork(nBestHeight) >= XST_FORK006) + { + return string("<>"); + } + // look for existing matching timestamps in wallet (ghetto uid) // should handle replay with scriptsig in future (version 2) LOCK(pwalletMain->cs_wallet); for (map::const_iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (pcoin->nTime == nTime) { + if (pcoin->GetTxTime() == nTime) { return string("<>"); } } @@ -616,7 +635,8 @@ Value sendrawtransaction(const Array& params, bool fHelp) // or in the memory pool: CTransaction existingTx; uint256 hashBlock = 0; - if (GetTransaction(hashTx, existingTx, hashBlock)) + unsigned int nTimeBlock; + if (GetTransaction(hashTx, existingTx, hashBlock, nTimeBlock)) { if (hashBlock != 0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index c9c3546..8d3ac52 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -40,14 +40,16 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry) entry.push_back(Pair("confirmations", confirms)); if (wtx.IsCoinBase() || wtx.IsCoinStake()) entry.push_back(Pair("generated", true)); + unsigned int nBlockTime = 0; if (confirms > 0) { + nBlockTime = mapBlockIndex[wtx.hashBlock]->nTime; entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", (boost::int64_t)(mapBlockIndex[wtx.hashBlock]->nTime))); + entry.push_back(Pair("blocktime", (boost::int64_t)(nBlockTime))); } entry.push_back(Pair("txid", wtx.GetHash().GetHex())); - entry.push_back(Pair("time", (boost::int64_t)wtx.GetTxTime())); + entry.push_back(Pair("time", (boost::int64_t)wtx.GetWTxTime())); entry.push_back(Pair("timereceived", (boost::int64_t)wtx.nTimeReceived)); BOOST_FOREACH(const PAIRTYPE(string,string)& item, wtx.mapValue) entry.push_back(Pair(item.first, item.second)); @@ -792,7 +794,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) if ((int)keys.size() < nRequired) throw runtime_error( strprintf("not enough keys supplied " - "(got %"PRIszu" keys, but need at least %d to redeem)", keys.size(), nRequired)); + "(got %" PRIszu " keys, but need at least %d to redeem)", keys.size(), nRequired)); std::vector pubkeys; pubkeys.resize(keys.size()); for (unsigned int i = 0; i < keys.size(); i++) @@ -1012,34 +1014,14 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe bool fAllAccounts = (strAccount == string("*")); - // Generated blocks assigned to account "" - if ((nGeneratedMature+nGeneratedImmature) != 0 && (fAllAccounts || strAccount == "")) - { - Object entry; - entry.push_back(Pair("account", string(""))); - if (nGeneratedImmature) - { - entry.push_back(Pair("category", wtx.GetDepthInMainChain() ? "immature" : "orphan")); - entry.push_back(Pair("amount", ValueFromAmount(nGeneratedImmature))); - } - else - { - entry.push_back(Pair("category", "generate")); - entry.push_back(Pair("amount", ValueFromAmount(nGeneratedMature))); - } - if (fLong) - WalletTxToJSON(wtx, entry); - ret.push_back(entry); - } - // Sent - if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount)) + if ((!wtx.IsCoinStake()) && (!listSent.empty() || nFee != 0) && + (fAllAccounts || strAccount == strSentAccount)) { BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& s, listSent) { Object entry; entry.push_back(Pair("account", strSentAccount)); - //entry.push_back(Pair("address", CBitcoinAddress(s.first).ToString())); MaybePushAddress(entry, s.first); entry.push_back(Pair("category", "send")); entry.push_back(Pair("amount", ValueFromAmount(-s.second))); @@ -1053,6 +1035,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe // Received if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) { + bool stop = false; BOOST_FOREACH(const PAIRTYPE(CTxDestination, int64)& r, listReceived) { string account; @@ -1062,8 +1045,8 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe { Object entry; entry.push_back(Pair("account", account)); - entry.push_back(Pair("address", CBitcoinAddress(r.first).ToString())); - if (wtx.IsCoinBase()) + MaybePushAddress(entry, r.first); + if (wtx.IsCoinBase() || wtx.IsCoinStake()) { if (wtx.GetDepthInMainChain() < 1) entry.push_back(Pair("category", "orphan")); @@ -1073,12 +1056,22 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe entry.push_back(Pair("category", "generate")); } else + { entry.push_back(Pair("category", "receive")); - entry.push_back(Pair("amount", ValueFromAmount(r.second))); + } + if (!wtx.IsCoinStake()) + entry.push_back(Pair("amount", ValueFromAmount(r.second))); + else + { + entry.push_back(Pair("amount", ValueFromAmount(-nFee))); + stop = true; // only one coinstake output + } if (fLong) WalletTxToJSON(wtx, entry); ret.push_back(entry); } + if (stop) + break; } } } @@ -1320,7 +1313,8 @@ Value gettransaction(const Array& params, bool fHelp) { CTransaction tx; uint256 hashBlock = 0; - if (GetTransaction(hash, tx, hashBlock)) + unsigned int nTimeBlock; + if (GetTransaction(hash, tx, hashBlock, nTimeBlock)) { entry.push_back(Pair("txid", hash.GetHex())); TxToJSON(tx, 0, entry); @@ -1336,7 +1330,10 @@ Value gettransaction(const Array& params, bool fHelp) if (pindex->IsInMainChain()) { entry.push_back(Pair("confirmations", 1 + nBestHeight - pindex->nHeight)); - entry.push_back(Pair("txntime", (boost::int64_t)tx.nTime)); + if (tx.HasTimestamp()) + { + entry.push_back(Pair("txntime", (boost::int64_t)tx.GetTxTime())); + } entry.push_back(Pair("time", (boost::int64_t)pindex->nTime)); } else diff --git a/src/tor/adapter/toradapter.cpp b/src/tor/adapter/toradapter.cpp index 430f8ee..948c66b 100644 --- a/src/tor/adapter/toradapter.cpp +++ b/src/tor/adapter/toradapter.cpp @@ -43,7 +43,11 @@ int check_interrupted( static boost::mutex initializing; +#if __cplusplus >= 201103L +static std::unique_ptr > uninitialized( +#else static std::auto_ptr > uninitialized( +#endif new boost::unique_lock( initializing ) diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index 9fd9418..6dccd73 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -406,7 +406,7 @@ bool CTxDB::LoadBlockIndex() // NovaCoin: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) - return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRI64x, pindex->nHeight, pindex->nStakeModifier); + return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016" PRI64x, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain diff --git a/src/util.cpp b/src/util.cpp index 5d58333..c7b8e38 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -373,7 +373,7 @@ string FormatMoney(int64 n, bool fPlus) int64 n_abs = (n > 0 ? n : -n); int64 quotient = n_abs/COIN; int64 remainder = n_abs%COIN; - string str = strprintf("%"PRI64d".%06"PRI64d, quotient, remainder); + string str = strprintf("%" PRI64d ".%06" PRI64d, quotient, remainder); // Right-trim excess zeros before the decimal point: int nTrim = 0; @@ -1123,7 +1123,7 @@ const boost::filesystem::path &GetDataDir(bool fNetSpecific) path = GetDefaultDataDir(); } if (fNetSpecific && GetBoolArg("-testnet", false)) - path /= "testnet2"; + path /= "testnet"; fs::create_directory(path); @@ -1278,7 +1278,7 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) // Add data vTimeOffsets.input(nOffsetSample); - printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); + printf("Added time data, samples %d, offset %+" PRI64d " (%+" PRI64d " minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) { int64 nMedian = vTimeOffsets.median(); @@ -1313,10 +1313,10 @@ void AddTimeData(const CNetAddr& ip, int64 nTime) } if (fDebug) { BOOST_FOREACH(int64 n, vSorted) - printf("%+"PRI64d" ", n); + printf("%+" PRI64d " ", n); printf("| "); } - printf("nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60); + printf("nTimeOffset = %+" PRI64d " (%+" PRI64d " minutes)\n", nTimeOffset, nTimeOffset/60); } } diff --git a/src/util.h b/src/util.h index dcbbae2..a108b6e 100644 --- a/src/util.h +++ b/src/util.h @@ -248,7 +248,7 @@ void runCommand(std::string strCommand); inline std::string i64tostr(int64 n) { - return strprintf("%"PRI64d, n); + return strprintf("%" PRI64d, n); } inline std::string itostr(int n) diff --git a/src/version.h b/src/version.h index ffe4feb..9ad3599 100644 --- a/src/version.h +++ b/src/version.h @@ -24,23 +24,31 @@ extern const std::string CLIENT_DATE; // display version #define DISPLAY_VERSION_MAJOR 2 -#define DISPLAY_VERSION_MINOR 1 +#define DISPLAY_VERSION_MINOR 2 #define DISPLAY_VERSION_REVISION 0 -#define DISPLAY_VERSION_BUILD 4 +#define DISPLAY_VERSION_BUILD 0 // // network protocol versioning // -// 62009 : New alerts with easier clearing -// Different keys for alerts and hash sync checkpoints -// 62010 : New rule to accept duplicate stake on bootstrap (only!) -// Technically not a network protocol difference -// 62020 : Fixes signature malleability -// 62100 : Clockdrift improvements & Checklocktimeverify (forking) -// Client version: 2.1.0 +// 61001 : [Genesis] +// 61011 : fork 1 +// 1.0.1.1 : Fix PoS difficulty adjustment during PoW period +// 61021 : fork 2 +// 1.0.2.1 : Kill PoW at 5460 to deal with forks on pools +// 61040 : fork 3 +// 1.0.4.0 : Adjust max bits computation for 60s block times +// 61300 : fork 4 +// 1.3.0.0 : Stealth Addresses +// 62100 : fork 5 +// 2.1.0.0 : Clockdrift improvements & Checklocktimeverify (forking) +// 2.1.0.1 : SignSignature fix // 2.1.0.4 : OpenSSL v1.1 compatibility -static const int PROTOCOL_VERSION = 62100; +// 62200 : fork 6 +// 2.2.0.0 : Removing all traces of tx timestamp +// Immaleable transaction IDs +static const int PROTOCOL_VERSION = 62200; // intial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 61300; diff --git a/src/wallet.cpp b/src/wallet.cpp index e5257a5..93fceb1 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -116,7 +116,7 @@ bool CWallet::LoadCScript(const CScript &redeemScript) { if(redeemScript.size() > MAX_SCRIPT_ELEMENT_SIZE){ std::string strAddr = CBitcoinAddress(redeemScript.GetID()).ToString(); - printf("%s: Warning: This wallet contains a redeemScript of size %"PRIszu" which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", + printf("%s: Warning: This wallet contains a redeemScript of size %" PRIszu " which exceeds maximum size %i thus can never be redeemed. Do not use address %s.\n", __func__, redeemScript.size(), MAX_SCRIPT_ELEMENT_SIZE, strAddr.c_str()); return true; } @@ -704,12 +704,35 @@ bool CWallet::IsChange(const CTxOut& txout) const return false; } -int64 CWalletTx::GetTxTime() const +int64 CWalletTx::GetWTxTime() const { int64 n = nTimeSmart; return n ? n : nTimeReceived; } +// FIXME: optimization - set timestamp of CWalletTx when updated with blockindex +unsigned int CWalletTx::GetTxTime() const +{ + if (HasTimestamp()) + { + return CTransaction::GetTxTime(); + } + + map::iterator mi = mapBlockIndex.find(hashBlock); + if (mi == mapBlockIndex.end()) + { + if (fDebug) + { + printf("CWalletTx::GetTxTime(): block not found: %s\n", + hashBlock.ToString().c_str()); + } + // not in a block yet, give an earliest possible time + return pindexBest->nTime + 1; + } + CBlockIndex* pindex = (*mi).second; + return pindex->nTime; +} + int CWalletTx::GetRequestCount() const { // Returns -1 if it wasn't being tracked @@ -769,14 +792,13 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l BOOST_FOREACH(const CTxOut& txout, vout) { if (txout.scriptPubKey.empty()) - continue; + continue; bool fIsMine; if (nDebit > 0) { - // Don't report 'change' txouts - //if (nDebit > 0 && pwallet->IsChange(txout)) - if (pwallet->IsChange(txout)) + // Don't report 'change' txouts + if (pwallet->IsChange(txout) && !IsCoinStake()) continue; fIsMine = pwallet->IsMine(txout); } @@ -795,8 +817,8 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l listSent.push_back(make_pair(address, txout.nValue)); if (fIsMine) - listReceived.push_back(make_pair(address, txout.nValue)); - } + listReceived.push_back(make_pair(address, txout.nValue)); + } } void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGeneratedImmature, int64& nGeneratedMature, int64& nReceived, @@ -913,7 +935,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) LOCK(cs_wallet); while (pindex) { - if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey -7200))){ + if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))){ pindex = pindex->pnext; continue; } @@ -961,7 +983,7 @@ void CWallet::ReacceptWalletTransactions() // Update fSpent if a tx got spent somewhere else by a copy of wallet.dat if (txindex.vSpent.size() != wtx.vout.size()) { - printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %"PRIszu" != wtx.vout.size() %"PRIszu"\n", txindex.vSpent.size(), wtx.vout.size()); + printf("ERROR: ReacceptWalletTransactions() : txindex.vSpent.size() %" PRIszu " != wtx.vout.size() %" PRIszu "\n", txindex.vSpent.size(), wtx.vout.size()); continue; } for (unsigned int i = 0; i < txindex.vSpent.size(); i++) @@ -1256,12 +1278,19 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, unsigned int nSpendTime, in const CWalletTx *pcoin = output.tx; if (output.nDepth < (pcoin->IsFromMe() ? nConfMine : nConfTheirs)) + { continue; + } int i = output.i; - if (pcoin->nTime > nSpendTime) - continue; // ppcoin: timestamp must not exceed spend time + // ppcoin: timestamp must not exceed spend time + // if a tx doesn't have timestamp, then there is no way to set + // it in the future, so ignore this test + if (pcoin->HasTimestamp() && pcoin->GetTxTime() > nSpendTime) + { + continue; + } int64 n = pcoin->vout[i].nValue; @@ -1372,11 +1401,12 @@ void CWallet::AvailableCoinsForStaking(vector& vCoins, unsigned int nSp { const CWalletTx* pcoin = &(*it).second; - // Filtering by tx timestamp instead of block timestamp may give false positives but never false negatives - if (pcoin->nTime + nStakeMinAge > nSpendTime) + if (pcoin->GetBlocksToMaturity() > 0) continue; - if (pcoin->GetBlocksToMaturity() > 0) + // Filtering by tx timestamp instead of block timestamp + // may give false positives but never false negatives + if ((pcoin->GetTxTime() + nStakeMinAge) > nSpendTime) continue; int nDepth = pcoin->GetDepthInMainChain(); @@ -1466,8 +1496,12 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW // Choose coins to use set > setCoins; int64 nValueIn = 0; - if (!SelectCoins(nTotalValue, wtxNew.nTime, setCoins, nValueIn, coinControl)) + int nSpendTime = wtxNew.HasTimestamp() ? wtxNew.GetTxTime() : ::GetAdjustedTime(); + if (!SelectCoins(nTotalValue, nSpendTime, setCoins, nValueIn, coinControl)) + { + printf("CreateTransaction(): could not select coins\n"); return false; + } BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { int64 nCredit = pcoin.first->vout[pcoin.second].nValue; @@ -1520,12 +1554,16 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins) if (SignSignature(*this, *coin.first, wtxNew, nIn++) != 0) { + printf("CreateTransaction(): could not sign tx\n"); return false; } unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); if (nBytes >= MAX_BLOCK_SIZE_GEN/5) + { + printf("CreateTransaction(): too many bytes\n"); return false; + } dPriority /= nBytes; int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000); @@ -2005,9 +2043,9 @@ bool CWallet::SendStealthMoneyToDestination(CStealthAddress& sxAddress, int64 nV if (fDebug) { - printf("Stealth send to generated pubkey %"PRIszu": %s\n", pkSendTo.size(), HexStr(pkSendTo).c_str()); + printf("Stealth send to generated pubkey %" PRIszu ": %s\n", pkSendTo.size(), HexStr(pkSendTo).c_str()); printf("hash %s\n", addrTo.ToString().c_str()); - printf("ephem_pubkey %"PRIszu": %s\n", ephem_pubkey.size(), HexStr(ephem_pubkey).c_str()); + printf("ephem_pubkey %" PRIszu ": %s\n", ephem_pubkey.size(), HexStr(ephem_pubkey).c_str()); }; std::vector vchNarr; @@ -2138,7 +2176,7 @@ bool CWallet::FindStealthTransactions(const CTransaction& tx, mapValue_t& mapNar printf("StealthSecret failed.\n"); continue; }; - //printf("pkExtracted %"PRIszu": %s\n", pkExtracted.size(), HexStr(pkExtracted).c_str()); + //printf("pkExtracted %" PRIszu ": %s\n", pkExtracted.size(), HexStr(pkExtracted).c_str()); CPubKey cpkE(pkExtracted); @@ -2274,7 +2312,7 @@ bool CWallet::GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint int64 nReserveBalance = 0; if (mapArgs.count("-reservebalance") && !ParseMoney(mapArgs["-reservebalance"], nReserveBalance)) - return error("CreateCoinStake : invalid reserve balance amount"); + return error("GetStakeWeight : invalid reserve balance amount"); if (nBalance <= nReserveBalance) return false; @@ -2298,7 +2336,7 @@ bool CWallet::GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint continue; } - int64 nTimeWeight = GetWeight((int64)pcoin.first->nTime, (int64)GetTime()); + int64 nTimeWeight = GetWeight((int64)pcoin.first->GetTxTime(), (int64)GetTime()); CBigNum bnCoinDayWeight = CBigNum(pcoin.first->vout[pcoin.second].nValue) * nTimeWeight / COIN / (24 * 60 * 60); // Weight is greater than zero @@ -2323,7 +2361,9 @@ bool CWallet::GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint return true; } -bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64 nSearchInterval, CTransaction& txNew) +bool CWallet::CreateCoinStake(const CKeyStore& keystore,unsigned int nBits, + int64 nSearchInterval, CTransaction& txNew, + unsigned int &nCoinStakeTime) { CBlockIndex* pindexPrev = pindexBest; CBigNum bnTargetPerCoinDay; @@ -2346,7 +2386,11 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int set > setCoins; vector vwtxPrev; int64 nValueIn = 0; - if (!SelectCoins(nBalance - nReserveBalance, txNew.nTime, setCoins, nValueIn)) + // upon XST_FORK006, CTransactions do not have dependable timestamps, + // however for the data structure timestamp can be used temporarily + // for now CTransaction timestamp inits as the adjusted time + if (!SelectCoins(nBalance - nReserveBalance, + nCoinStakeTime, setCoins, nValueIn)) return false; if (setCoins.empty()) @@ -2374,7 +2418,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int static int nMaxStakeSearchInterval = 60; - if (block.GetBlockTime() + nStakeMinAge > txNew.nTime - nMaxStakeSearchInterval) + // upon XST_FORK006, CTransactions do not have dependable timestamps, + // however for the data structure timestamp can be used temporarily + // for now CTransaction timestamp inits as the adjusted time + if (block.GetBlockTime() + nStakeMinAge > nCoinStakeTime - nMaxStakeSearchInterval) continue; // only count coins meeting min age requirement bool fKernelFound = false; @@ -2385,7 +2432,13 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int // Search nSearchInterval seconds back up to nMaxStakeSearchInterval uint256 hashProofOfStake = 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, + nCoinStakeTime - n, // re timestamps, see above + hashProofOfStake)) { // Found a kernel if (fDebug && GetBoolArg("-printcoinstake")) @@ -2440,16 +2493,23 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int scriptPubKeyOut = scriptPubKeyKernel; } - txNew.nTime -= n; + nCoinStakeTime -= n; + if (txNew.HasTimestamp()) + { + txNew.AdjustTime(-n); + } txNew.vin.push_back(CTxIn(pcoin.first->GetHash(), pcoin.second)); nCredit += pcoin.first->vout[pcoin.second].nValue; - // printf(">> Wallet: CreateCoinStake: nCredit = %"PRI64d"\n", nCredit); + // printf(">> Wallet: CreateCoinStake: nCredit = %" PRI64d "\n", nCredit); vwtxPrev.push_back(pcoin.first); txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); - if (GetWeight(block.GetBlockTime(), (int64_t)txNew.nTime) < nStakeSplitAge) + // upon XST_FORK006, CTransactions do not have dependable timestamps, + // however for the data structure timestamp can be used temporarily + // for now CTransaction timestamp inits as the adjusted time + if (GetWeight(block.GetBlockTime(), (int64_t)nCoinStakeTime) < nStakeSplitAge) txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake if (fDebug && GetBoolArg("-printcoinstake")) @@ -2463,7 +2523,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int } if (nCredit == 0 || nCredit > nBalance - nReserveBalance) { - // printf(">> Wallet: CreateCoinStake: nCredit = %"PRI64d", nBalance = %"PRI64d", nReserveBalance = %"PRI64d"\n", nCredit, nBalance, nReserveBalance); + // printf(">> Wallet: CreateCoinStake: nCredit = %" PRI64d ", nBalance = %" PRI64d ", nReserveBalance = %" PRI64d "\n", nCredit, nBalance, nReserveBalance); return false; } @@ -2474,7 +2534,7 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int if (txNew.vout.size() == 2 && ((pcoin.first->vout[pcoin.second].scriptPubKey == scriptPubKeyKernel || pcoin.first->vout[pcoin.second].scriptPubKey == txNew.vout[1].scriptPubKey)) && pcoin.first->GetHash() != txNew.vin[0].prevout.hash) { - int64_t nTimeWeight = GetWeight((int64_t)pcoin.first->nTime, (int64_t)txNew.nTime); + int64_t nTimeWeight = GetWeight((int64_t)pcoin.first->GetTxTime(), nCoinStakeTime); // Stop adding more inputs if already too many inputs if (txNew.vin.size() >= 100) break; @@ -2501,9 +2561,10 @@ bool CWallet::CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int CTxDB txdb("r"); const CBlockIndex* pIndex0 = GetLastBlockIndex(pindexBest, false); - if (!txNew.GetCoinAge(txdb, nCoinAge)) + // nCoinStakeTime will be block time after FORK006 + if (!txNew.GetCoinAge(txdb, nCoinStakeTime, nCoinAge)) return error("CreateCoinStake : failed to calculate coin age"); - int64 nReward = GetProofOfStakeReward(nCoinAge, nBits, txNew.nTime, pIndex0->nHeight); + int64 nReward = GetProofOfStakeReward(nCoinAge, nBits, pIndex0->nHeight); if (nReward <= 0) { return false; } @@ -2739,12 +2800,12 @@ void CWallet::PrintWallet(const CBlock& block) if (block.IsProofOfWork() && mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + printf(" mine: %d %d %" PRI64d "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } if (block.IsProofOfStake() && mapWallet.count(block.vtx[1].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[1].GetHash()]; - printf(" stake: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + printf(" stake: %d %d %" PRI64d "", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } } @@ -2807,7 +2868,7 @@ bool CWallet::NewKeyPool() walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); setKeyPool.insert(nIndex); } - printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys); + printf("CWallet::NewKeyPool wrote %" PRI64d " new keys\n", nKeys); } return true; } @@ -2837,7 +2898,7 @@ bool CWallet::TopUpKeyPool(unsigned int nSize) if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - printf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size()); + printf("keypool added key %" PRI64d ", size=%" PRIszu "\n", nEnd, setKeyPool.size()); } } return true; @@ -2867,7 +2928,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); assert(keypool.vchPubKey.IsValid()); if (fDebug && GetBoolArg("-printkeypool")) - printf("keypool reserve %"PRI64d"\n", nIndex); + printf("keypool reserve %" PRI64d "\n", nIndex); } } @@ -2895,7 +2956,7 @@ void CWallet::KeepKey(int64 nIndex) walletdb.ErasePool(nIndex); } if(fDebug) - printf("keypool keep %"PRI64d"\n", nIndex); + printf("keypool keep %" PRI64d "\n", nIndex); } void CWallet::ReturnKey(int64 nIndex) @@ -2906,7 +2967,7 @@ void CWallet::ReturnKey(int64 nIndex) setKeyPool.insert(nIndex); } //if(fDebug) - //printf("keypool return %"PRI64d"\n", nIndex); + //printf("keypool return %" PRI64d "\n", nIndex); } bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse) diff --git a/src/wallet.h b/src/wallet.h index 0c56605..3a0b466 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -196,7 +196,9 @@ class CWallet : public CCryptoKeyStore int64 GetNewMint() const; bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); bool GetStakeWeight(const CKeyStore& keystore, uint64& nMinWeight, uint64& nMaxWeight, uint64& nWeight); - bool CreateCoinStake(const CKeyStore& keystore, unsigned int nBits, int64 nSearchInterval, CTransaction& txNew); + bool CreateCoinStake(const CKeyStore& keystore,unsigned int nBits, + int64 nSearchInterval, CTransaction& txNew, + unsigned int &nCoinStakeTime); std::string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); std::string SendMoneyToDestination(const CTxDestination &address, int64 nValue, CWalletTx& wtxNew, bool fAskFee=false); @@ -702,7 +704,9 @@ class CWalletTx : public CMerkleTx bool WriteToDisk(); - int64 GetTxTime() const; + unsigned int GetTxTime() const; + + int64 GetWTxTime() const; int GetRequestCount() const; void AddSupportingTransactions(CTxDB& txdb); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 61c92c0..88cd5bd 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -256,7 +256,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, //// debug print //printf("LoadWallet %s\n", wtx.GetHash().ToString().c_str()); - //printf(" %12"PRI64d" %s %s %s\n", + //printf(" %12" PRI64d " %s %s %s\n", // wtx.vout[0].nValue, // DateTimeStrFormat("%x %H:%M:%S", wtx.GetBlockTime()).c_str(), // wtx.hashBlock.ToString().substr(0,20).c_str(), @@ -608,7 +608,7 @@ void ThreadFlushWalletDB(void* parg) bitdb.CheckpointLSN(strFile); bitdb.mapFileUseCount.erase(mi++); - printf("Flushed wallet.dat %"PRI64d"ms\n", GetTimeMillis() - nStart); + printf("Flushed wallet.dat %" PRI64d "ms\n", GetTimeMillis() - nStart); } } } @@ -669,7 +669,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) // Set -rescan so any missing transactions will be // found. int64 now = GetTime(); - std::string newFilename = strprintf("wallet.%"PRI64d".bak", now); + std::string newFilename = strprintf("wallet.%" PRI64d ".bak", now); int result = dbenv.dbenv.dbrename(NULL, filename.c_str(), NULL, newFilename.c_str(), DB_AUTO_COMMIT); @@ -688,7 +688,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) printf("Salvage(aggressive) found no records in %s.\n", newFilename.c_str()); return false; } - printf("Salvage(aggressive) found %"PRIszu" records\n", salvagedData.size()); + printf("Salvage(aggressive) found %" PRIszu " records\n", salvagedData.size()); bool fSuccess = allOK; Db* pdbCopy = new Db(&dbenv.dbenv, 0);