diff options
Diffstat (limited to 'src')
155 files changed, 4199 insertions, 2685 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 94a582dfac..155adfef7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -65,8 +65,10 @@ BITCOIN_CORE_H = \ addrman.h \ alert.h \ allocators.h \ + amount.h \ base58.h \ bloom.h \ + chain.h \ chainparams.h \ chainparamsbase.h \ chainparamsseeds.h \ @@ -101,6 +103,7 @@ BITCOIN_CORE_H = \ script/compressor.h \ script/interpreter.h \ script/script.h \ + script/sigcache.h \ script/sign.h \ script/standard.h \ serialize.h \ @@ -145,6 +148,7 @@ libbitcoin_server_a_SOURCES = \ addrman.cpp \ alert.cpp \ bloom.cpp \ + chain.cpp \ checkpoints.cpp \ init.cpp \ leveldbwrapper.cpp \ @@ -215,6 +219,7 @@ libbitcoin_common_a_SOURCES = \ script/compressor.cpp \ script/interpreter.cpp \ script/script.cpp \ + script/sigcache.cpp \ script/sign.cpp \ script/standard.cpp \ $(BITCOIN_CORE_H) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 1ea039adb3..872a0cf1c5 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -178,6 +178,7 @@ BITCOIN_QT_H = \ qt/macdockiconhandler.h \ qt/macnotificationhandler.h \ qt/monitoreddatamapper.h \ + qt/networkstyle.h \ qt/notificator.h \ qt/openuridialog.h \ qt/optionsdialog.h \ @@ -269,6 +270,7 @@ BITCOIN_QT_CPP = \ qt/guiutil.cpp \ qt/intro.cpp \ qt/monitoreddatamapper.cpp \ + qt/networkstyle.cpp \ qt/notificator.cpp \ qt/optionsdialog.cpp \ qt/optionsmodel.cpp \ diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include index 2cba5b7e1e..23375bef82 100644 --- a/src/Makefile.qttest.include +++ b/src/Makefile.qttest.include @@ -13,7 +13,7 @@ TEST_QT_H = \ qt/test/paymentservertests.h qt_test_test_bitcoin_qt_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_TEST_INCLUDES) + $(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS) qt_test_test_bitcoin_qt_SOURCES = \ qt/test/test_main.cpp \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index ab449f3e71..b20e226c3d 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -40,10 +40,10 @@ BITCOIN_TESTS =\ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bloom_tests.cpp \ - test/canonical_tests.cpp \ test/checkblock_tests.cpp \ test/Checkpoints_tests.cpp \ test/compress_tests.cpp \ + test/coins_tests.cpp \ test/crypto_tests.cpp \ test/DoS_tests.cpp \ test/getarg_tests.cpp \ diff --git a/src/alert.cpp b/src/alert.cpp index 3271ecfbfd..d495849206 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -233,25 +233,30 @@ bool CAlert::ProcessAlert(bool fThread) if(AppliesToMe()) { uiInterface.NotifyAlertChanged(GetHash(), CT_NEW); - std::string strCmd = GetArg("-alertnotify", ""); - if (!strCmd.empty()) - { - // Alert text should be plain ascii coming from a trusted source, but to - // be safe we first strip anything not in safeChars, then add single quotes around - // the whole string before passing it to the shell: - std::string singleQuote("'"); - std::string safeStatus = SanitizeString(strStatusBar); - safeStatus = singleQuote+safeStatus+singleQuote; - boost::replace_all(strCmd, "%s", safeStatus); - - if (fThread) - boost::thread t(runCommand, strCmd); // thread runs free - else - runCommand(strCmd); - } + Notify(strStatusBar, fThread); } } LogPrint("alert", "accepted alert %d, AppliesToMe()=%d\n", nID, AppliesToMe()); return true; } + +void +CAlert::Notify(const std::string& strMessage, bool fThread) +{ + std::string strCmd = GetArg("-alertnotify", ""); + if (strCmd.empty()) return; + + // Alert text should be plain ascii coming from a trusted source, but to + // be safe we first strip anything not in safeChars, then add single quotes around + // the whole string before passing it to the shell: + std::string singleQuote("'"); + std::string safeStatus = SanitizeString(strMessage); + safeStatus = singleQuote+safeStatus+singleQuote; + boost::replace_all(strCmd, "%s", safeStatus); + + if (fThread) + boost::thread t(runCommand, strCmd); // thread runs free + else + runCommand(strCmd); +} diff --git a/src/alert.h b/src/alert.h index 5ecf94cea8..ba3235858d 100644 --- a/src/alert.h +++ b/src/alert.h @@ -101,7 +101,8 @@ public: bool AppliesToMe() const; bool RelayTo(CNode* pnode) const; bool CheckSignature() const; - bool ProcessAlert(bool fThread = true); + bool ProcessAlert(bool fThread = true); // fThread means run -alertnotify in a free-running thread + static void Notify(const std::string& strMessage, bool fThread); /* * Get copy of (active) alert object by hash. Returns a null alert if it is not found. diff --git a/src/amount.h b/src/amount.h new file mode 100644 index 0000000000..831fa1f6ca --- /dev/null +++ b/src/amount.h @@ -0,0 +1,13 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_AMOUNT_H +#define BITCOIN_AMOUNT_H + +#include <stdint.h> + +typedef int64_t CAmount; + +#endif // BITCOIN_AMOUNT_H diff --git a/src/base58.cpp b/src/base58.cpp index 9750f0a161..d94db2c51b 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -288,7 +288,8 @@ void CBitcoinSecret::SetKey(const CKey& vchSecret) CKey CBitcoinSecret::GetKey() { CKey ret; - ret.Set(&vchData[0], &vchData[32], vchData.size() > 32 && vchData[32] == 1); + assert(vchData.size() >= 32); + ret.Set(vchData.begin(), vchData.begin() + 32, vchData.size() > 32 && vchData[32] == 1); return ret; } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index b6e7a6c540..da37e60c7f 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -214,7 +214,7 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput) // extract and validate VALUE string strValue = strInput.substr(0, pos); - int64_t value; + CAmount value; if (!ParseMoney(strValue, value)) throw runtime_error("invalid TX output value"); @@ -242,7 +242,7 @@ static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput // extract and validate VALUE string strValue = strInput.substr(0, pos); - int64_t value; + CAmount value; if (!ParseMoney(strValue, value)) throw runtime_error("invalid TX output value"); @@ -340,7 +340,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) CMutableTransaction mergedTx(txVariants[0]); bool fComplete = true; CCoinsView viewDummy; - CCoinsViewCache view(viewDummy); + CCoinsViewCache view(&viewDummy); if (!registers.count("privatekeys")) throw runtime_error("privatekeys register variable must be set."); @@ -384,21 +384,19 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) vector<unsigned char> pkData(ParseHexUV(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); - CCoins coins; - if (view.GetCoins(txid, coins)) { - if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { + { + CCoinsModifier coins = view.ModifyCoins(txid); + if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { string err("Previous output scriptPubKey mismatch:\n"); - err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ + err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ scriptPubKey.ToString(); throw runtime_error(err); } - // what todo if txid is known, but the actual output isn't? + if ((unsigned int)nOut >= coins->vout.size()) + coins->vout.resize(nOut+1); + coins->vout[nOut].scriptPubKey = scriptPubKey; + coins->vout[nOut].nValue = 0; // we don't know the actual output value } - if ((unsigned int)nOut >= coins.vout.size()) - coins.vout.resize(nOut+1); - coins.vout[nOut].scriptPubKey = scriptPubKey; - coins.vout[nOut].nValue = 0; // we don't know the actual output value - view.SetCoins(txid, coins); // if redeemScript given and private keys given, // add redeemScript to the tempKeystore so it can be signed: @@ -435,7 +433,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) BOOST_FOREACH(const CTransaction& txv, txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS)) + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i))) fComplete = false; } diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 5be8708979..0737b5a83d 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -129,7 +129,6 @@ bool AppInit(int argc, char* argv[]) } if (pid > 0) // Parent process, pid is child process id { - CreatePidFile(GetPidFile(), pid); return true; } // Child process falls through to rest of initialization diff --git a/src/chain.cpp b/src/chain.cpp new file mode 100644 index 0000000000..05427a4569 --- /dev/null +++ b/src/chain.cpp @@ -0,0 +1,59 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "chain.h" + +using namespace std; + +// CChain implementation + +CBlockIndex *CChain::SetTip(CBlockIndex *pindex) { + if (pindex == NULL) { + vChain.clear(); + return NULL; + } + vChain.resize(pindex->nHeight + 1); + while (pindex && vChain[pindex->nHeight] != pindex) { + vChain[pindex->nHeight] = pindex; + pindex = pindex->pprev; + } + return pindex; +} + +CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { + int nStep = 1; + std::vector<uint256> vHave; + vHave.reserve(32); + + if (!pindex) + pindex = Tip(); + while (pindex) { + vHave.push_back(pindex->GetBlockHash()); + // Stop when we have added the genesis block. + if (pindex->nHeight == 0) + break; + // Exponentially larger steps back, plus the genesis block. + int nHeight = std::max(pindex->nHeight - nStep, 0); + if (Contains(pindex)) { + // Use O(1) CChain index if possible. + pindex = (*this)[nHeight]; + } else { + // Otherwise, use O(log n) skiplist. + pindex = pindex->GetAncestor(nHeight); + } + if (vHave.size() > 10) + nStep *= 2; + } + + return CBlockLocator(vHave); +} + +const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { + if (pindex->nHeight > Height()) + pindex = pindex->GetAncestor(Height()); + while (pindex && !Contains(pindex)) + pindex = pindex->pprev; + return pindex; +} diff --git a/src/chain.h b/src/chain.h new file mode 100644 index 0000000000..0aafb40b98 --- /dev/null +++ b/src/chain.h @@ -0,0 +1,390 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef H_BITCOIN_CHAIN +#define H_BITCOIN_CHAIN + +#include "core.h" +#include "pow.h" +#include "uint256.h" + +#include <vector> + +#include <boost/foreach.hpp> + +struct CDiskBlockPos +{ + int nFile; + unsigned int nPos; + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nFile)); + READWRITE(VARINT(nPos)); + } + + CDiskBlockPos() { + SetNull(); + } + + CDiskBlockPos(int nFileIn, unsigned int nPosIn) { + nFile = nFileIn; + nPos = nPosIn; + } + + friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return (a.nFile == b.nFile && a.nPos == b.nPos); + } + + friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { + return !(a == b); + } + + void SetNull() { nFile = -1; nPos = 0; } + bool IsNull() const { return (nFile == -1); } +}; + +enum BlockStatus { + BLOCK_VALID_UNKNOWN = 0, + BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future + BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint + BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root + BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30 + BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok + BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | + BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, + + BLOCK_HAVE_DATA = 8, // full block available in blk*.dat + BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat + BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO, + + BLOCK_FAILED_VALID = 32, // stage after last reached validness failed + BLOCK_FAILED_CHILD = 64, // descends from failed block + BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, +}; + +/** The block chain is a tree shaped structure starting with the + * genesis block at the root, with each block potentially having multiple + * candidates to be the next block. A blockindex may have multiple pprev pointing + * to it, but at most one of them can be part of the currently active branch. + */ +class CBlockIndex +{ +public: + // pointer to the hash of the block, if any. memory is owned by this CBlockIndex + const uint256* phashBlock; + + // pointer to the index of the predecessor of this block + CBlockIndex* pprev; + + // pointer to the index of some further predecessor of this block + CBlockIndex* pskip; + + // height of the entry in the chain. The genesis block has height 0 + int nHeight; + + // Which # file this block is stored in (blk?????.dat) + int nFile; + + // Byte offset within blk?????.dat where this block's data is stored + unsigned int nDataPos; + + // Byte offset within rev?????.dat where this block's undo data is stored + unsigned int nUndoPos; + + // (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block + uint256 nChainWork; + + // Number of transactions in this block. + // Note: in a potential headers-first mode, this number cannot be relied upon + unsigned int nTx; + + // (memory only) Number of transactions in the chain up to and including this block + unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030 + + // Verification status of this block. See enum BlockStatus + unsigned int nStatus; + + // block header + int nVersion; + uint256 hashMerkleRoot; + unsigned int nTime; + unsigned int nBits; + unsigned int nNonce; + + // (memory only) Sequencial id assigned to distinguish order in which blocks are received. + uint32_t nSequenceId; + + void SetNull() + { + phashBlock = NULL; + pprev = NULL; + pskip = NULL; + nHeight = 0; + nFile = 0; + nDataPos = 0; + nUndoPos = 0; + nChainWork = 0; + nTx = 0; + nChainTx = 0; + nStatus = 0; + nSequenceId = 0; + + nVersion = 0; + hashMerkleRoot = 0; + nTime = 0; + nBits = 0; + nNonce = 0; + } + + CBlockIndex() + { + SetNull(); + } + + CBlockIndex(CBlockHeader& block) + { + SetNull(); + + nVersion = block.nVersion; + hashMerkleRoot = block.hashMerkleRoot; + nTime = block.nTime; + nBits = block.nBits; + nNonce = block.nNonce; + } + + CDiskBlockPos GetBlockPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_DATA) { + ret.nFile = nFile; + ret.nPos = nDataPos; + } + return ret; + } + + CDiskBlockPos GetUndoPos() const { + CDiskBlockPos ret; + if (nStatus & BLOCK_HAVE_UNDO) { + ret.nFile = nFile; + ret.nPos = nUndoPos; + } + return ret; + } + + CBlockHeader GetBlockHeader() const + { + CBlockHeader block; + block.nVersion = nVersion; + if (pprev) + block.hashPrevBlock = pprev->GetBlockHash(); + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block; + } + + uint256 GetBlockHash() const + { + return *phashBlock; + } + + int64_t GetBlockTime() const + { + return (int64_t)nTime; + } + + uint256 GetBlockWork() const + { + return GetProofIncrement(nBits); + } + + enum { nMedianTimeSpan=11 }; + + int64_t GetMedianTimePast() const + { + int64_t pmedian[nMedianTimeSpan]; + int64_t* pbegin = &pmedian[nMedianTimeSpan]; + int64_t* pend = &pmedian[nMedianTimeSpan]; + + const CBlockIndex* pindex = this; + for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) + *(--pbegin) = pindex->GetBlockTime(); + + std::sort(pbegin, pend); + return pbegin[(pend - pbegin)/2]; + } + + /** + * Returns true if there are nRequired or more blocks of minVersion or above + * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart + * and going backwards. + */ + static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, + unsigned int nRequired); + + std::string ToString() const + { + return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", + pprev, nHeight, + hashMerkleRoot.ToString(), + GetBlockHash().ToString()); + } + + // Check whether this block index entry is valid up to the passed validity level. + bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); + } + + // Raise the validity level of this block index entry. + // Returns true if the validity was changed. + bool RaiseValidity(enum BlockStatus nUpTo) + { + assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. + if (nStatus & BLOCK_FAILED_MASK) + return false; + if ((nStatus & BLOCK_VALID_MASK) < nUpTo) { + nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo; + return true; + } + return false; + } + + // Build the skiplist pointer for this entry. + void BuildSkip(); + + // Efficiently find an ancestor of this block. + CBlockIndex* GetAncestor(int height); + const CBlockIndex* GetAncestor(int height) const; +}; + +/** Used to marshal pointers into hashes for db storage. */ +class CDiskBlockIndex : public CBlockIndex +{ +public: + uint256 hashPrev; + + CDiskBlockIndex() { + hashPrev = 0; + } + + explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) { + hashPrev = (pprev ? pprev->GetBlockHash() : 0); + } + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + if (!(nType & SER_GETHASH)) + READWRITE(VARINT(nVersion)); + + READWRITE(VARINT(nHeight)); + READWRITE(VARINT(nStatus)); + READWRITE(VARINT(nTx)); + if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) + READWRITE(VARINT(nFile)); + if (nStatus & BLOCK_HAVE_DATA) + READWRITE(VARINT(nDataPos)); + if (nStatus & BLOCK_HAVE_UNDO) + READWRITE(VARINT(nUndoPos)); + + // block header + READWRITE(this->nVersion); + READWRITE(hashPrev); + READWRITE(hashMerkleRoot); + READWRITE(nTime); + READWRITE(nBits); + READWRITE(nNonce); + } + + uint256 GetBlockHash() const + { + CBlockHeader block; + block.nVersion = nVersion; + block.hashPrevBlock = hashPrev; + block.hashMerkleRoot = hashMerkleRoot; + block.nTime = nTime; + block.nBits = nBits; + block.nNonce = nNonce; + return block.GetHash(); + } + + + std::string ToString() const + { + std::string str = "CDiskBlockIndex("; + str += CBlockIndex::ToString(); + str += strprintf("\n hashBlock=%s, hashPrev=%s)", + GetBlockHash().ToString(), + hashPrev.ToString()); + return str; + } +}; + +/** An in-memory indexed chain of blocks. */ +class CChain { +private: + std::vector<CBlockIndex*> vChain; + +public: + /** Returns the index entry for the genesis block of this chain, or NULL if none. */ + CBlockIndex *Genesis() const { + return vChain.size() > 0 ? vChain[0] : NULL; + } + + /** Returns the index entry for the tip of this chain, or NULL if none. */ + CBlockIndex *Tip() const { + return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; + } + + /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ + CBlockIndex *operator[](int nHeight) const { + if (nHeight < 0 || nHeight >= (int)vChain.size()) + return NULL; + return vChain[nHeight]; + } + + /** Compare two chains efficiently. */ + friend bool operator==(const CChain &a, const CChain &b) { + return a.vChain.size() == b.vChain.size() && + a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; + } + + /** Efficiently check whether a block is present in this chain. */ + bool Contains(const CBlockIndex *pindex) const { + return (*this)[pindex->nHeight] == pindex; + } + + /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ + CBlockIndex *Next(const CBlockIndex *pindex) const { + if (Contains(pindex)) + return (*this)[pindex->nHeight + 1]; + else + return NULL; + } + + /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ + int Height() const { + return vChain.size() - 1; + } + + /** Set/initialize a chain with a given tip. Returns the forking point. */ + CBlockIndex *SetTip(CBlockIndex *pindex); + + /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ + CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; + + /** Find the last common block between this chain and a block index entry. */ + const CBlockIndex *FindFork(const CBlockIndex *pindex) const; +}; + +#endif // H_BITCOIN_CHAIN diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 3177266069..dfb4c59d87 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -44,6 +44,57 @@ static void convertSeed6(std::vector<CAddress> &vSeedsOut, const SeedSpec6 *data } } + // What makes a good checkpoint block? + // + Is surrounded by blocks with reasonable timestamps + // (no blocks before with a timestamp after, none after with + // timestamp before) + // + Contains no strange transactions +static Checkpoints::MapCheckpoints mapCheckpoints = + boost::assign::map_list_of + ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) + ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) + ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) + (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) + (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) + (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")) + (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")) + (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")) + (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")) + (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")) + (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")) + (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")) + (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")) + ; +static const Checkpoints::CCheckpointData data = { + &mapCheckpoints, + 1397080064, // * UNIX timestamp of last checkpoint block + 36544669, // * total number of transactions between genesis and last checkpoint + // (the tx=... number in the SetBestChain debug.log lines) + 60000.0 // * estimated number of transactions per day after checkpoint + }; + +static Checkpoints::MapCheckpoints mapCheckpointsTestnet = + boost::assign::map_list_of + ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")) + ; +static const Checkpoints::CCheckpointData dataTestnet = { + &mapCheckpointsTestnet, + 1337966069, + 1488, + 300 + }; + +static Checkpoints::MapCheckpoints mapCheckpointsRegtest = + boost::assign::map_list_of + ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")) + ; +static const Checkpoints::CCheckpointData dataRegtest = { + &mapCheckpointsRegtest, + 0, + 0, + 0 + }; + class CMainParams : public CChainParams { public: CMainParams() { @@ -115,6 +166,13 @@ public: fAllowMinDifficultyBlocks = false; fRequireStandard = true; fMineBlocksOnDemand = false; + fSkipProofOfWorkCheck = false; + fTestnetToBeDeprecatedFieldRPC = false; + } + + const Checkpoints::CCheckpointData& Checkpoints() const + { + return data; } }; static CMainParams mainParams; @@ -171,6 +229,11 @@ public: fAllowMinDifficultyBlocks = true; fRequireStandard = false; fMineBlocksOnDemand = false; + fTestnetToBeDeprecatedFieldRPC = true; + } + const Checkpoints::CCheckpointData& Checkpoints() const + { + return dataTestnet; } }; static CTestNetParams testNetParams; @@ -210,12 +273,61 @@ public: fAllowMinDifficultyBlocks = true; fRequireStandard = false; fMineBlocksOnDemand = true; + fTestnetToBeDeprecatedFieldRPC = false; + } + const Checkpoints::CCheckpointData& Checkpoints() const + { + return dataRegtest; } }; static CRegTestParams regTestParams; +// +// Unit test +// +class CUnitTestParams : public CMainParams, public CModifiableParams { +public: + CUnitTestParams() { + networkID = CBaseChainParams::UNITTEST; + strNetworkID = "unittest"; + nDefaultPort = 18445; + vFixedSeeds.clear(); + vSeeds.clear(); // Regtest mode doesn't have any DNS seeds. + + fRequireRPCPassword = false; + fMiningRequiresPeers = false; + fDefaultCheckMemPool = true; + fAllowMinDifficultyBlocks = false; + fMineBlocksOnDemand = true; + } + + const Checkpoints::CCheckpointData& Checkpoints() const + { + // UnitTest share the same checkpoints as MAIN + return data; + } + + // Published setters to allow changing values in unit test cases + virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) { nSubsidyHalvingInterval=anSubsidyHalvingInterval; } + virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority) { nEnforceBlockUpgradeMajority=anEnforceBlockUpgradeMajority; } + virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority) { nRejectBlockOutdatedMajority=anRejectBlockOutdatedMajority; } + virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority) { nToCheckBlockUpgradeMajority=anToCheckBlockUpgradeMajority; } + virtual void setDefaultCheckMemPool(bool afDefaultCheckMemPool) { fDefaultCheckMemPool=afDefaultCheckMemPool; } + virtual void setAllowMinDifficultyBlocks(bool afAllowMinDifficultyBlocks) { fAllowMinDifficultyBlocks=afAllowMinDifficultyBlocks; } + virtual void setSkipProofOfWorkCheck(bool afSkipProofOfWorkCheck) { fSkipProofOfWorkCheck = afSkipProofOfWorkCheck; } +}; +static CUnitTestParams unitTestParams; + + static CChainParams *pCurrentParams = 0; +CModifiableParams *ModifiableParams() +{ + assert(pCurrentParams); + assert(pCurrentParams==&unitTestParams); + return (CModifiableParams*)&unitTestParams; +} + const CChainParams &Params() { assert(pCurrentParams); return *pCurrentParams; @@ -229,6 +341,8 @@ CChainParams &Params(CBaseChainParams::Network network) { return testNetParams; case CBaseChainParams::REGTEST: return regTestParams; + case CBaseChainParams::UNITTEST: + return unitTestParams; default: assert(false && "Unimplemented network"); return mainParams; diff --git a/src/chainparams.h b/src/chainparams.h index e5dfc87c6d..f157419bb2 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -8,6 +8,7 @@ #include "core.h" #include "chainparamsbase.h" +#include "checkpoints.h" #include "protocol.h" #include "uint256.h" @@ -61,6 +62,8 @@ public: bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; } /* Allow mining of a min-difficulty block */ bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; } + /* Skip proof-of-work check: allow mining of any difficulty block */ + bool SkipProofOfWorkCheck() const { return fSkipProofOfWorkCheck; } /* Make standard checks */ bool RequireStandard() const { return fRequireStandard; } int64_t TargetTimespan() const { return nTargetTimespan; } @@ -69,12 +72,14 @@ public: /* Make miner stop after a block is found. In RPC, don't return * until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } - CBaseChainParams::Network NetworkID() const { return networkID; } + /* In the future use NetworkIDString() for RPC fields */ + bool TestnetToBeDeprecatedFieldRPC() const { return fTestnetToBeDeprecatedFieldRPC; } /* Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; } const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } const std::vector<CAddress>& FixedSeeds() const { return vFixedSeeds; } + virtual const Checkpoints::CCheckpointData& Checkpoints() const = 0; protected: CChainParams() {} @@ -103,8 +108,28 @@ protected: bool fAllowMinDifficultyBlocks; bool fRequireStandard; bool fMineBlocksOnDemand; + bool fSkipProofOfWorkCheck; + bool fTestnetToBeDeprecatedFieldRPC; }; +/** Modifiable parameters interface is used by test cases to adapt the parameters in order +*** to test specific features more easily. Test cases should always restore the previous +*** values after finalization. +**/ + +class CModifiableParams { +public: + // Published setters to allow changing values in unit test cases + virtual void setSubsidyHalvingInterval(int anSubsidyHalvingInterval) =0; + virtual void setEnforceBlockUpgradeMajority(int anEnforceBlockUpgradeMajority)=0; + virtual void setRejectBlockOutdatedMajority(int anRejectBlockOutdatedMajority)=0; + virtual void setToCheckBlockUpgradeMajority(int anToCheckBlockUpgradeMajority)=0; + virtual void setDefaultCheckMemPool(bool aDefaultCheckMemPool)=0; + virtual void setAllowMinDifficultyBlocks(bool aAllowMinDifficultyBlocks)=0; + virtual void setSkipProofOfWorkCheck(bool aSkipProofOfWorkCheck)=0; +}; + + /** * Return the currently selected parameters. This won't change after app startup * outside of the unit tests. @@ -114,6 +139,9 @@ const CChainParams &Params(); /** Return parameters for the given network. */ CChainParams &Params(CBaseChainParams::Network network); +/** Get modifyable network parameters (UNITTEST only) */ +CModifiableParams *ModifiableParams(); + /** Sets the params returned by Params() to those for the given network. */ void SelectParams(CBaseChainParams::Network network); diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index a602d8e30e..5d9ec7927b 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -57,6 +57,20 @@ public: }; static CBaseRegTestParams regTestParams; +// +// Unit test +// +class CBaseUnitTestParams : public CBaseMainParams +{ +public: + CBaseUnitTestParams() + { + networkID = CBaseChainParams::UNITTEST; + strDataDir = "unittest"; + } +}; +static CBaseUnitTestParams unitTestParams; + static CBaseChainParams* pCurrentBaseParams = 0; const CBaseChainParams& BaseParams() @@ -77,6 +91,9 @@ void SelectBaseParams(CBaseChainParams::Network network) case CBaseChainParams::REGTEST: pCurrentBaseParams = ®TestParams; break; + case CBaseChainParams::UNITTEST: + pCurrentBaseParams = &unitTestParams; + break; default: assert(false && "Unimplemented network"); return; diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index ff3e811988..911d1181ac 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -19,6 +19,7 @@ public: MAIN, TESTNET, REGTEST, + UNITTEST, MAX_NETWORK_TYPES }; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index c41deea7ce..fbde47339d 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -4,18 +4,16 @@ #include "checkpoints.h" +#include "chainparams.h" #include "main.h" #include "uint256.h" #include <stdint.h> -#include <boost/assign/list_of.hpp> // for 'map_list_of()' #include <boost/foreach.hpp> namespace Checkpoints { - typedef std::map<int, uint256> MapCheckpoints; - // How many times we expect transactions after the last checkpoint to // be slower. This number is a compromise, as it can't be accurate for // every system. When reindexing from a fast disk with a slow CPU, it @@ -23,81 +21,14 @@ namespace Checkpoints { // fast multicore CPU, it won't be much higher than 1. static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; - struct CCheckpointData { - const MapCheckpoints *mapCheckpoints; - int64_t nTimeLastCheckpoint; - int64_t nTransactionsLastCheckpoint; - double fTransactionsPerDay; - }; - bool fEnabled = true; - // What makes a good checkpoint block? - // + Is surrounded by blocks with reasonable timestamps - // (no blocks before with a timestamp after, none after with - // timestamp before) - // + Contains no strange transactions - static MapCheckpoints mapCheckpoints = - boost::assign::map_list_of - ( 11111, uint256("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")) - ( 33333, uint256("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")) - ( 74000, uint256("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")) - (105000, uint256("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")) - (134444, uint256("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")) - (168000, uint256("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")) - (193000, uint256("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")) - (210000, uint256("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")) - (216116, uint256("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")) - (225430, uint256("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")) - (250000, uint256("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")) - (279000, uint256("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")) - (295000, uint256("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")) - ; - static const CCheckpointData data = { - &mapCheckpoints, - 1397080064, // * UNIX timestamp of last checkpoint block - 36544669, // * total number of transactions between genesis and last checkpoint - // (the tx=... number in the SetBestChain debug.log lines) - 60000.0 // * estimated number of transactions per day after checkpoint - }; - - static MapCheckpoints mapCheckpointsTestnet = - boost::assign::map_list_of - ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")) - ; - static const CCheckpointData dataTestnet = { - &mapCheckpointsTestnet, - 1337966069, - 1488, - 300 - }; - - static MapCheckpoints mapCheckpointsRegtest = - boost::assign::map_list_of - ( 0, uint256("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")) - ; - static const CCheckpointData dataRegtest = { - &mapCheckpointsRegtest, - 0, - 0, - 0 - }; - - const CCheckpointData &Checkpoints() { - if (Params().NetworkID() == CBaseChainParams::TESTNET) - return dataTestnet; - else if (Params().NetworkID() == CBaseChainParams::MAIN) - return data; - else - return dataRegtest; - } - bool CheckBlock(int nHeight, const uint256& hash) { if (!fEnabled) return true; - const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return true; @@ -117,7 +48,7 @@ namespace Checkpoints { // Work is defined as: 1.0 per transaction before the last checkpoint, and // fSigcheckVerificationFactor per transaction after. - const CCheckpointData &data = Checkpoints(); + const CCheckpointData &data = Params().Checkpoints(); if (pindex->nChainTx <= data.nTransactionsLastCheckpoint) { double nCheapBefore = pindex->nChainTx; @@ -141,7 +72,7 @@ namespace Checkpoints { if (!fEnabled) return 0; - const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; return checkpoints.rbegin()->first; } @@ -151,7 +82,7 @@ namespace Checkpoints { if (!fEnabled) return NULL; - const MapCheckpoints& checkpoints = *Checkpoints().mapCheckpoints; + const MapCheckpoints& checkpoints = *Params().Checkpoints().mapCheckpoints; BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints) { diff --git a/src/checkpoints.h b/src/checkpoints.h index fca046559a..b5b620fa6b 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -5,16 +5,26 @@ #ifndef BITCOIN_CHECKPOINT_H #define BITCOIN_CHECKPOINT_H +#include "uint256.h" + #include <map> class CBlockIndex; -class uint256; /** Block-chain checkpoints are compiled-in sanity checks. * They are updated every release or three. */ namespace Checkpoints { +typedef std::map<int, uint256> MapCheckpoints; + +struct CCheckpointData { + const MapCheckpoints *mapCheckpoints; + int64_t nTimeLastCheckpoint; + int64_t nTransactionsLastCheckpoint; + double fTransactionsPerDay; +}; + // Returns true if block passes checkpoint checks bool CheckBlock(int nHeight, const uint256& hash); diff --git a/src/coins.cpp b/src/coins.cpp index 34485db2bd..e4f3e67aeb 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -53,61 +53,72 @@ bool CCoins::Spend(int nPos) { bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } -bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } uint256 CCoinsView::GetBestBlock() const { return uint256(0); } -bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } -CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } +CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } -bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) const { return base->HaveCoins(txid); } uint256 CCoinsViewBacked::GetBestBlock() const { return base->GetBestBlock(); } -bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStats(stats); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} -CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), hashBlock(0) { } +CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), hashBlock(0) { } -bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { - if (cacheCoins.count(txid)) { - coins = cacheCoins[txid]; - return true; - } - if (base->GetCoins(txid, coins)) { - cacheCoins[txid] = coins; - return true; - } - return false; +CCoinsViewCache::~CCoinsViewCache() +{ + assert(!hasModifier); } -CCoinsMap::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { +CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { CCoinsMap::iterator it = cacheCoins.find(txid); if (it != cacheCoins.end()) return it; CCoins tmp; - if (!base->GetCoins(txid,tmp)) + if (!base->GetCoins(txid, tmp)) return cacheCoins.end(); - CCoinsMap::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins())); - tmp.swap(ret->second); + CCoinsMap::iterator ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())).first; + tmp.swap(ret->second.coins); + if (ret->second.coins.IsPruned()) { + // The parent only has an empty entry for this txid; we can consider our + // version as fresh. + ret->second.flags = CCoinsCacheEntry::FRESH; + } return ret; } -CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const { - /* Avoid redundant implementation with the const-cast. */ - return const_cast<CCoinsViewCache*>(this)->FetchCoins(txid); +bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const { + CCoinsMap::const_iterator it = FetchCoins(txid); + if (it != cacheCoins.end()) { + coins = it->second.coins; + return true; + } + return false; } -CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { - CCoinsMap::iterator it = FetchCoins(txid); - assert(it != cacheCoins.end()); - return it->second; +CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) { + assert(!hasModifier); + hasModifier = true; + std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry())); + if (ret.second) { + if (!base->GetCoins(txid, ret.first->second.coins)) { + // The parent view does not have this entry; mark it as fresh. + ret.first->second.coins.Clear(); + ret.first->second.flags = CCoinsCacheEntry::FRESH; + } else if (ret.first->second.coins.IsPruned()) { + // The parent view only has a pruned entry for this; mark it as fresh. + ret.first->second.flags = CCoinsCacheEntry::FRESH; + } + } + // Assume that whenever ModifyCoins is called, the entry will be modified. + ret.first->second.flags |= CCoinsCacheEntry::DIRTY; + return CCoinsModifier(*this, ret.first); } const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const { @@ -115,22 +126,17 @@ const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const { if (it == cacheCoins.end()) { return NULL; } else { - return &it->second; + return &it->second.coins; } } -bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { - cacheCoins[txid] = coins; - return true; -} - bool CCoinsViewCache::HaveCoins(const uint256 &txid) const { CCoinsMap::const_iterator it = FetchCoins(txid); // We're using vtx.empty() instead of IsPruned here for performance reasons, // as we only care about the case where an transaction was replaced entirely // in a reorganization (which wipes vout entirely, as opposed to spending // which just cleans individual outputs). - return (it != cacheCoins.end() && !it->second.vout.empty()); + return (it != cacheCoins.end() && !it->second.coins.vout.empty()); } uint256 CCoinsViewCache::GetBestBlock() const { @@ -139,14 +145,39 @@ uint256 CCoinsViewCache::GetBestBlock() const { return hashBlock; } -bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { +void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { hashBlock = hashBlockIn; - return true; } bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) { + assert(!hasModifier); for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { - cacheCoins[it->first].swap(it->second); + if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). + CCoinsMap::iterator itUs = cacheCoins.find(it->first); + if (itUs == cacheCoins.end()) { + if (!it->second.coins.IsPruned()) { + // The parent cache does not have an entry, while the child + // cache does have (a non-pruned) one. Move the data up, and + // mark it as fresh (if the grandparent did have it, we + // would have pulled it in at first GetCoins). + assert(it->second.flags & CCoinsCacheEntry::FRESH); + CCoinsCacheEntry& entry = cacheCoins[it->first]; + entry.coins.swap(it->second.coins); + entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH; + } + } else { + if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { + // The grandparent does not have an entry, and the child is + // modified and being pruned. This means we can just delete + // it from the parent. + cacheCoins.erase(itUs); + } else { + // A normal modification. + itUs->second.coins.swap(it->second.coins); + itUs->second.flags |= CCoinsCacheEntry::DIRTY; + } + } + } CCoinsMap::iterator itOld = it++; mapCoins.erase(itOld); } @@ -171,12 +202,12 @@ const CTxOut &CCoinsViewCache::GetOutputFor(const CTxIn& input) const return coins->vout[input.prevout.n]; } -int64_t CCoinsViewCache::GetValueIn(const CTransaction& tx) const +CAmount CCoinsViewCache::GetValueIn(const CTransaction& tx) const { if (tx.IsCoinBase()) return 0; - int64_t nResult = 0; + CAmount nResult = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) nResult += GetOutputFor(tx.vin[i]).nValue; @@ -213,3 +244,15 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const } return tx.ComputePriority(dResult); } + +CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {} + +CCoinsModifier::~CCoinsModifier() +{ + assert(cache.hasModifier); + cache.hasModifier = false; + it->second.coins.Cleanup(); + if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) { + cache.cacheCoins.erase(it); + } +} diff --git a/src/coins.h b/src/coins.h index bf61f55aac..b8f1e5bcc5 100644 --- a/src/coins.h +++ b/src/coins.h @@ -83,11 +83,26 @@ public: // as new tx version will probably only be introduced at certain heights int nVersion; - // construct a CCoins from a CTransaction, at a given height - CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { + void FromTx(const CTransaction &tx, int nHeightIn) { + fCoinBase = tx.IsCoinBase(); + vout = tx.vout; + nHeight = nHeightIn; + nVersion = tx.nVersion; ClearUnspendable(); } + // construct a CCoins from a CTransaction, at a given height + CCoins(const CTransaction &tx, int nHeightIn) { + FromTx(tx, nHeightIn); + } + + void Clear() { + fCoinBase = false; + std::vector<CTxOut>().swap(vout); + nHeight = 0; + nVersion = 0; + } + // empty constructor CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { } @@ -256,7 +271,20 @@ public: } }; -typedef boost::unordered_map<uint256, CCoins, CCoinsKeyHasher> CCoinsMap; +struct CCoinsCacheEntry +{ + CCoins coins; // The actual cached data. + unsigned char flags; + + enum Flags { + DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view. + FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned). + }; + + CCoinsCacheEntry() : coins(), flags(0) {} +}; + +typedef boost::unordered_map<uint256, CCoinsCacheEntry, CCoinsKeyHasher> CCoinsMap; struct CCoinsStats { @@ -266,7 +294,7 @@ struct CCoinsStats uint64_t nTransactionOutputs; uint64_t nSerializedSize; uint256 hashSerialized; - int64_t nTotalAmount; + CAmount nTotalAmount; CCoinsStats() : nHeight(0), hashBlock(0), nTransactions(0), nTransactionOutputs(0), nSerializedSize(0), hashSerialized(0), nTotalAmount(0) {} }; @@ -279,9 +307,6 @@ public: // Retrieve the CCoins (unspent transaction outputs) for a given txid virtual bool GetCoins(const uint256 &txid, CCoins &coins) const; - // Modify the CCoins for a given txid - virtual bool SetCoins(const uint256 &txid, const CCoins &coins); - // Just check whether we have data for a given txid. // This may (but cannot always) return true for fully spent transactions virtual bool HaveCoins(const uint256 &txid) const; @@ -289,10 +314,7 @@ public: // Retrieve the block hash whose state this CCoinsView currently represents virtual uint256 GetBestBlock() const; - // Modify the currently active block hash - virtual bool SetBestBlock(const uint256 &hashBlock); - - // Do a bulk modification (multiple SetCoins + one SetBestBlock). + // Do a bulk modification (multiple CCoins changes + BestBlock change). // The passed mapCoins can be modified. virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); @@ -311,22 +333,41 @@ protected: CCoinsView *base; public: - CCoinsViewBacked(CCoinsView &viewIn); + CCoinsViewBacked(CCoinsView *viewIn); bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool SetCoins(const uint256 &txid, const CCoins &coins); bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - bool SetBestBlock(const uint256 &hashBlock); void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats) const; }; +class CCoinsViewCache; + +/** A reference to a mutable cache entry. Encapsulating it allows us to run + * cleanup code after the modification is finished, and keeping track of + * concurrent modifications. */ +class CCoinsModifier +{ +private: + CCoinsViewCache& cache; + CCoinsMap::iterator it; + CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_); + +public: + CCoins* operator->() { return &it->second.coins; } + CCoins& operator*() { return it->second.coins; } + ~CCoinsModifier(); + friend class CCoinsViewCache; +}; + /** CCoinsView that adds a memory cache for transactions to another CCoinsView */ class CCoinsViewCache : public CCoinsViewBacked { protected: + /* Whether this cache has an active modifier. */ + bool hasModifier; /* Make mutable so that we can "fill the cache" even from Get-methods declared as "const". */ @@ -334,14 +375,14 @@ protected: mutable CCoinsMap cacheCoins; public: - CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); + CCoinsViewCache(CCoinsView *baseIn); + ~CCoinsViewCache(); // Standard CCoinsView methods bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool SetCoins(const uint256 &txid, const CCoins &coins); bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - bool SetBestBlock(const uint256 &hashBlock); + void SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Return a pointer to CCoins in the cache, or NULL if not found. This is @@ -349,8 +390,10 @@ public: // allowed while accessing the returned pointer. const CCoins* AccessCoins(const uint256 &txid) const; - // Return a modifiable reference to a CCoins. Check HaveCoins first. - CCoins &GetCoins(const uint256 &txid); + // Return a modifiable reference to a CCoins. If no entry with the given + // txid exists, a new one is created. Simultaneous modifications are not + // allowed. + CCoinsModifier ModifyCoins(const uint256 &txid); // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. @@ -367,7 +410,7 @@ public: @param[in] tx transaction for which we are checking input total @return Sum of value of all inputs (scriptSigs) */ - int64_t GetValueIn(const CTransaction& tx) const; + CAmount GetValueIn(const CTransaction& tx) const; // Check whether all prevouts of the transaction are present in the UTXO set represented by this view bool HaveInputs(const CTransaction& tx) const; @@ -377,6 +420,8 @@ public: const CTxOut &GetOutputFor(const CTxIn& input) const; + friend class CCoinsModifier; + private: CCoinsMap::iterator FetchCoins(const uint256 &txid); CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const; diff --git a/src/compat/glibc_compat.cpp b/src/compat/glibc_compat.cpp index 22f82e4259..f149a08cd5 100644 --- a/src/compat/glibc_compat.cpp +++ b/src/compat/glibc_compat.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) @@ -7,6 +7,7 @@ #endif #include <cstddef> + #if defined(HAVE_SYS_SELECT_H) #include <sys/select.h> #endif @@ -18,11 +19,11 @@ extern "C" void* memcpy(void* a, const void* b, size_t c) return memmove(a, b, c); } -extern "C" void __chk_fail (void) __attribute__((__noreturn__)); +extern "C" void __chk_fail(void) __attribute__((__noreturn__)); extern "C" FDELT_TYPE __fdelt_warn(FDELT_TYPE a) { if (a >= FD_SETSIZE) - __chk_fail (); + __chk_fail(); return a / __NFDBITS; } extern "C" FDELT_TYPE __fdelt_chk(FDELT_TYPE) __attribute__((weak, alias("__fdelt_warn"))); diff --git a/src/compat/glibc_sanity.cpp b/src/compat/glibc_sanity.cpp index d93602e0fe..607e23b568 100644 --- a/src/compat/glibc_sanity.cpp +++ b/src/compat/glibc_sanity.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #if defined(HAVE_CONFIG_H) @@ -7,6 +7,7 @@ #endif #include <cstddef> + #if defined(HAVE_SYS_SELECT_H) #include <sys/select.h> #endif @@ -14,10 +15,11 @@ extern "C" void* memcpy(void* a, const void* b, size_t c); void* memcpy_int(void* a, const void* b, size_t c) { - return memcpy(a,b,c); + return memcpy(a, b, c); } -namespace { +namespace +{ // trigger: Use the memcpy_int wrapper which calls our internal memcpy. // A direct call to memcpy may be optimized away by the compiler. // test: Fill an array with a sequence of integers. memcpy to a new empty array. @@ -31,11 +33,10 @@ bool sanity_test_memcpy() for (unsigned int i = 0; i != T; ++i) memcpy_test[i] = i; - memcpy_int(memcpy_verify,memcpy_test,sizeof(memcpy_test)); + memcpy_int(memcpy_verify, memcpy_test, sizeof(memcpy_test)); - for (unsigned int i = 0; i != T; ++i) - { - if(memcpy_verify[i] != i) + for (unsigned int i = 0; i != T; ++i) { + if (memcpy_verify[i] != i) return false; } return true; @@ -51,7 +52,7 @@ bool sanity_test_fdelt() fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); - return FD_ISSET(0,&fds); + return FD_ISSET(0, &fds); } #endif diff --git a/src/compat/glibcxx_compat.cpp b/src/compat/glibcxx_compat.cpp index cbe059735b..e0b4ac51f5 100644 --- a/src/compat/glibcxx_compat.cpp +++ b/src/compat/glibcxx_compat.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <cstddef> @@ -11,8 +11,8 @@ #define _GLIBCXX_USE_NOEXCEPT throw() #endif -namespace std { - +namespace std +{ const char* bad_exception::what() const throw() { return "std::bad_exception"; @@ -30,9 +30,8 @@ const char* bad_alloc::what() const throw() namespace __detail { -struct _List_node_base -{ - void _M_hook(std::__detail::_List_node_base* const __position) throw () __attribute__((used)) +struct _List_node_base { + void _M_hook(std::__detail::_List_node_base* const __position) throw() __attribute__((used)) { _M_next = __position; _M_prev = __position->_M_prev; @@ -62,9 +61,9 @@ template ostream& __ostream_insert(ostream&, const char*, streamsize); template istream& istream::_M_extract(long&); template istream& istream::_M_extract(unsigned short&); -out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT { } +out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT {} -length_error::~length_error() _GLIBCXX_USE_NOEXCEPT { } +length_error::~length_error() _GLIBCXX_USE_NOEXCEPT {} // Used with permission. // See: https://github.com/madlib/madlib/commit/c3db418c0d34d6813608f2137fef1012ce03043d @@ -85,11 +84,11 @@ void ctype<char>::_M_widen_init() const } } -void __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__)); -void __throw_out_of_range_fmt(const char* err, ...) +void __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__)); +void __throw_out_of_range_fmt(const char* err, ...) { // Safe and over-simplified version. Ignore the format and print it as-is. __throw_out_of_range(err); } -}// namespace std +} // namespace std diff --git a/src/compat/glibcxx_sanity.cpp b/src/compat/glibcxx_sanity.cpp index cd8da4fd67..aafa4a6aef 100644 --- a/src/compat/glibcxx_sanity.cpp +++ b/src/compat/glibcxx_sanity.cpp @@ -1,20 +1,20 @@ // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <list> #include <locale> #include <stdexcept> -namespace{ - +namespace +{ // trigger: use ctype<char>::widen to trigger ctype<char>::_M_widen_init(). // test: convert a char from narrow to wide and back. Verify that the result // matches the original. bool sanity_test_widen(char testchar) { - const std::ctype<char>& test(std::use_facet< std::ctype<char> >(std::locale())); - return test.narrow(test.widen(testchar),'b') == testchar; + const std::ctype<char>& test(std::use_facet<std::ctype<char> >(std::locale())); + return test.narrow(test.widen(testchar), 'b') == testchar; } // trigger: use list::push_back and list::pop_back to trigger _M_hook and @@ -25,14 +25,13 @@ bool sanity_test_list(unsigned int size) { std::list<unsigned int> test; for (unsigned int i = 0; i != size; ++i) - test.push_back(i+1); + test.push_back(i + 1); if (test.size() != size) return false; - while (!test.empty()) - { - if(test.back() != test.size()) + while (!test.empty()) { + if (test.back() != test.size()) return false; test.pop_back(); } @@ -47,15 +46,12 @@ bool sanity_test_list(unsigned int size) bool sanity_test_range_fmt() { std::string test; - try - { + try { test.at(1); - } - catch (const std::out_of_range&) - { + } catch (const std::out_of_range&) { return true; + } catch (...) { } - catch (...){} return false; } diff --git a/src/compat/sanity.h b/src/compat/sanity.h index e7df44307a..7016ac0ab7 100644 --- a/src/compat/sanity.h +++ b/src/compat/sanity.h @@ -1,5 +1,5 @@ // Copyright (c) 2009-2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCON_COMPAT_SANITY_H diff --git a/src/core.cpp b/src/core.cpp index 491e4fa68b..6a7a9ff378 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -7,8 +7,6 @@ #include "tinyformat.h" -#include <boost/foreach.hpp> - std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); @@ -43,7 +41,7 @@ std::string CTxIn::ToString() const return str; } -CTxOut::CTxOut(int64_t nValueIn, CScript scriptPubKeyIn) +CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn) { nValue = nValueIn; scriptPubKey = scriptPubKeyIn; @@ -59,7 +57,7 @@ std::string CTxOut::ToString() const return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, scriptPubKey.ToString().substr(0,30)); } -CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize) +CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize) { if (nSize > 0) nSatoshisPerK = nFeePaid*1000/nSize; @@ -67,9 +65,9 @@ CFeeRate::CFeeRate(int64_t nFeePaid, size_t nSize) nSatoshisPerK = 0; } -int64_t CFeeRate::GetFee(size_t nSize) const +CAmount CFeeRate::GetFee(size_t nSize) const { - int64_t nFee = nSatoshisPerK*nSize / 1000; + CAmount nFee = nSatoshisPerK*nSize / 1000; if (nFee == 0 && nSatoshisPerK > 0) nFee = nSatoshisPerK; @@ -110,13 +108,13 @@ CTransaction& CTransaction::operator=(const CTransaction &tx) { return *this; } -int64_t CTransaction::GetValueOut() const +CAmount CTransaction::GetValueOut() const { - int64_t nValueOut = 0; - BOOST_FOREACH(const CTxOut& txout, vout) + CAmount nValueOut = 0; + for (std::vector<CTxOut>::const_iterator it(vout.begin()); it != vout.end(); ++it) { - nValueOut += txout.nValue; - if (!MoneyRange(txout.nValue) || !MoneyRange(nValueOut)) + nValueOut += it->nValue; + if (!MoneyRange(it->nValue) || !MoneyRange(nValueOut)) throw std::runtime_error("CTransaction::GetValueOut() : value out of range"); } return nValueOut; @@ -139,10 +137,9 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const // risk encouraging people to create junk outputs to redeem later. if (nTxSize == 0) nTxSize = ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); - - BOOST_FOREACH(const CTxIn& txin, vin) + for (std::vector<CTxIn>::const_iterator it(vin.begin()); it != vin.end(); ++it) { - unsigned int offset = 41U + std::min(110U, (unsigned int)txin.scriptSig.size()); + unsigned int offset = 41U + std::min(110U, (unsigned int)it->scriptSig.size()); if (nTxSize > offset) nTxSize -= offset; } @@ -224,22 +221,66 @@ uint256 CBlockHeader::GetHash() const return Hash(BEGIN(nVersion), END(nNonce)); } -uint256 CBlock::BuildMerkleTree() const +uint256 CBlock::BuildMerkleTree(bool* fMutated) const { + /* WARNING! If you're reading this because you're learning about crypto + and/or designing a new system that will use merkle trees, keep in mind + that the following merkle tree algorithm has a serious flaw related to + duplicate txids, resulting in a vulnerability (CVE-2012-2459). + + The reason is that if the number of hashes in the list at a given time + is odd, the last one is duplicated before computing the next level (which + is unusual in Merkle trees). This results in certain sequences of + transactions leading to the same merkle root. For example, these two + trees: + + A A + / \ / \ + B C B C + / \ | / \ / \ + D E F D E F F + / \ / \ / \ / \ / \ / \ / \ + 1 2 3 4 5 6 1 2 3 4 5 6 5 6 + + for transaction lists [1,2,3,4,5,6] and [1,2,3,4,5,6,5,6] (where 5 and + 6 are repeated) result in the same root hash A (because the hash of both + of (F) and (F,F) is C). + + The vulnerability results from being able to send a block with such a + transaction list, with the same merkle root, and the same block hash as + the original without duplication, resulting in failed validation. If the + receiving node proceeds to mark that block as permanently invalid + however, it will fail to accept further unmodified (and thus potentially + valid) versions of the same block. We defend against this by detecting + the case where we would hash two identical hashes at the end of the list + together, and treating that identically to the block having an invalid + merkle root. Assuming no double-SHA256 collisions, this will detect all + known ways of changing the transactions without affecting the merkle + root. + */ vMerkleTree.clear(); - BOOST_FOREACH(const CTransaction& tx, vtx) - vMerkleTree.push_back(tx.GetHash()); + vMerkleTree.reserve(vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. + for (std::vector<CTransaction>::const_iterator it(vtx.begin()); it != vtx.end(); ++it) + vMerkleTree.push_back(it->GetHash()); int j = 0; + bool mutated = false; for (int nSize = vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) { for (int i = 0; i < nSize; i += 2) { int i2 = std::min(i+1, nSize-1); + if (i2 == i + 1 && i2 + 1 == nSize && vMerkleTree[j+i] == vMerkleTree[j+i2]) { + // Two identical hashes at the end of the list at a particular level. + mutated = true; + } vMerkleTree.push_back(Hash(BEGIN(vMerkleTree[j+i]), END(vMerkleTree[j+i]), BEGIN(vMerkleTree[j+i2]), END(vMerkleTree[j+i2]))); } j += nSize; } + if (fMutated) { + *fMutated = mutated; + } return (vMerkleTree.empty() ? 0 : vMerkleTree.back()); } @@ -263,12 +304,12 @@ uint256 CBlock::CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMer { if (nIndex == -1) return 0; - BOOST_FOREACH(const uint256& otherside, vMerkleBranch) + for (std::vector<uint256>::const_iterator it(vMerkleBranch.begin()); it != vMerkleBranch.end(); ++it) { if (nIndex & 1) - hash = Hash(BEGIN(otherside), END(otherside), BEGIN(hash), END(hash)); + hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash)); else - hash = Hash(BEGIN(hash), END(hash), BEGIN(otherside), END(otherside)); + hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it)); nIndex >>= 1; } return hash; diff --git a/src/core.h b/src/core.h index 9a2ac47487..a024dad740 100644 --- a/src/core.h +++ b/src/core.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_CORE_H #define BITCOIN_CORE_H +#include "amount.h" #include "script/compressor.h" #include "script/script.h" #include "serialize.h" @@ -19,8 +20,8 @@ static const int64_t COIN = 100000000; static const int64_t CENT = 1000000; /** No amount larger than this (in satoshi) is valid */ -static const int64_t MAX_MONEY = 21000000 * COIN; -inline bool MoneyRange(int64_t nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } +static const CAmount MAX_MONEY = 21000000 * COIN; +inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } /** An outpoint - a combination of a transaction hash and an index n into its vout */ class COutPoint @@ -60,19 +61,6 @@ public: std::string ToString() const; }; -/** An inpoint - a combination of a transaction and an index n into its vin */ -class CInPoint -{ -public: - const CTransaction* ptx; - uint32_t n; - - CInPoint() { SetNull(); } - CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; } - void SetNull() { ptx = NULL; n = (uint32_t) -1; } - bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } -}; - /** An input of a transaction. It contains the location of the previous * transaction's output that it claims and a signature that matches the * output's public key. @@ -129,15 +117,15 @@ public: class CFeeRate { private: - int64_t nSatoshisPerK; // unit is satoshis-per-1,000-bytes + CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes public: CFeeRate() : nSatoshisPerK(0) { } - explicit CFeeRate(int64_t _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } - CFeeRate(int64_t nFeePaid, size_t nSize); + explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { } + CFeeRate(const CAmount& nFeePaid, size_t nSize); CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; } - int64_t GetFee(size_t size) const; // unit returned is satoshis - int64_t GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes + CAmount GetFee(size_t size) const; // unit returned is satoshis + CAmount GetFeePerK() const { return GetFee(1000); } // satoshis-per-1000-bytes friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; } friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; } @@ -161,7 +149,7 @@ public: class CTxOut { public: - int64_t nValue; + CAmount nValue; CScript scriptPubKey; CTxOut() @@ -169,7 +157,7 @@ public: SetNull(); } - CTxOut(int64_t nValueIn, CScript scriptPubKeyIn); + CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn); ADD_SERIALIZE_METHODS; @@ -276,7 +264,7 @@ public: } // Return sum of txouts. - int64_t GetValueOut() const; + CAmount GetValueOut() const; // GetValueIn() is a method on CCoinsViewCache, because // inputs must be known to compute value in. @@ -528,7 +516,11 @@ public: return block; } - uint256 BuildMerkleTree() const; + // Build the in-memory merkle tree for this block and return the merkle root. + // If non-NULL, *mutated is set to whether mutation was detected in the merkle + // tree (a duplication of transactions in the block leading to an identical + // merkle root). + uint256 BuildMerkleTree(bool* mutated = NULL) const; std::vector<uint256> GetMerkleBranch(int nIndex) const; static uint256 CheckMerkleBranch(uint256 hash, const std::vector<uint256>& vMerkleBranch, int nIndex); diff --git a/src/core_io.h b/src/core_io.h index 6268a3bf58..94848f1c3d 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -20,6 +20,7 @@ extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); // core_write.cpp +extern std::string FormatScript(const CScript& script); extern std::string EncodeHexTx(const CTransaction& tx); extern void ScriptPubKeyToUniv(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); diff --git a/src/core_write.cpp b/src/core_write.cpp index cd64aabf63..40d547fb33 100644 --- a/src/core_write.cpp +++ b/src/core_write.cpp @@ -17,6 +17,41 @@ using namespace std; +string FormatScript(const CScript& script) +{ + string ret; + CScript::const_iterator it = script.begin(); + opcodetype op; + while (it != script.end()) { + CScript::const_iterator it2 = it; + vector<unsigned char> vch; + if (script.GetOp2(it, op, &vch)) { + if (op == OP_0) { + ret += "0 "; + continue; + } else if ((op >= OP_1 && op <= OP_16) || op == OP_1NEGATE) { + ret += strprintf("%i ", op - OP_1NEGATE - 1); + continue; + } else if (op >= OP_NOP && op <= OP_CHECKMULTISIGVERIFY) { + string str(GetOpName(op)); + if (str.substr(0, 3) == string("OP_")) { + ret += str.substr(3, string::npos) + " "; + continue; + } + } + if (vch.size() > 0) { + ret += strprintf("0x%x 0x%x ", HexStr(it2, it - vch.size()), HexStr(it - vch.size(), it)); + } else { + ret += strprintf("0x%x", HexStr(it2, it)); + } + continue; + } + ret += strprintf("0x%x ", HexStr(it2, script.end())); + break; + } + return ret.substr(0, ret.size() - 1); +} + string EncodeHexTx(const CTransaction& tx) { CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); diff --git a/src/crypto/common.h b/src/crypto/common.h index 8f675a16c5..67c30023c3 100644 --- a/src/crypto/common.h +++ b/src/crypto/common.h @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_CRYPTO_COMMON_H @@ -8,12 +8,15 @@ #if defined(HAVE_CONFIG_H) #include "bitcoin-config.h" #endif + #include <stdint.h> + #if defined(HAVE_ENDIAN_H) #include <endian.h> #endif -uint32_t static inline ReadLE32(const unsigned char *ptr) { +uint32_t static inline ReadLE32(const unsigned char* ptr) +{ #if HAVE_DECL_LE32TOH == 1 return le32toh(*((uint32_t*)ptr)); #elif !defined(WORDS_BIGENDIAN) @@ -23,8 +26,8 @@ uint32_t static inline ReadLE32(const unsigned char *ptr) { #endif } -uint64_t static inline ReadLE64(const unsigned char *ptr) { - +uint64_t static inline ReadLE64(const unsigned char* ptr) +{ #if HAVE_DECL_LE64TOH == 1 return le64toh(*((uint64_t*)ptr)); #elif !defined(WORDS_BIGENDIAN) @@ -35,28 +38,40 @@ uint64_t static inline ReadLE64(const unsigned char *ptr) { #endif } -void static inline WriteLE32(unsigned char *ptr, uint32_t x) { +void static inline WriteLE32(unsigned char* ptr, uint32_t x) +{ #if HAVE_DECL_HTOLE32 == 1 *((uint32_t*)ptr) = htole32(x); #elif !defined(WORDS_BIGENDIAN) *((uint32_t*)ptr) = x; #else - ptr[3] = x >> 24; ptr[2] = x >> 16; ptr[1] = x >> 8; ptr[0] = x; + ptr[3] = x >> 24; + ptr[2] = x >> 16; + ptr[1] = x >> 8; + ptr[0] = x; #endif } -void static inline WriteLE64(unsigned char *ptr, uint64_t x) { +void static inline WriteLE64(unsigned char* ptr, uint64_t x) +{ #if HAVE_DECL_HTOLE64 == 1 *((uint64_t*)ptr) = htole64(x); #elif !defined(WORDS_BIGENDIAN) *((uint64_t*)ptr) = x; #else - ptr[7] = x >> 56; ptr[6] = x >> 48; ptr[5] = x >> 40; ptr[4] = x >> 32; - ptr[3] = x >> 24; ptr[2] = x >> 16; ptr[1] = x >> 8; ptr[0] = x; + ptr[7] = x >> 56; + ptr[6] = x >> 48; + ptr[5] = x >> 40; + ptr[4] = x >> 32; + ptr[3] = x >> 24; + ptr[2] = x >> 16; + ptr[1] = x >> 8; + ptr[0] = x; #endif } -uint32_t static inline ReadBE32(const unsigned char *ptr) { +uint32_t static inline ReadBE32(const unsigned char* ptr) +{ #if HAVE_DECL_BE32TOH == 1 return be32toh(*((uint32_t*)ptr)); #else @@ -64,7 +79,8 @@ uint32_t static inline ReadBE32(const unsigned char *ptr) { #endif } -uint64_t static inline ReadBE64(const unsigned char *ptr) { +uint64_t static inline ReadBE64(const unsigned char* ptr) +{ #if HAVE_DECL_BE64TOH == 1 return be64toh(*((uint64_t*)ptr)); #else @@ -73,21 +89,32 @@ uint64_t static inline ReadBE64(const unsigned char *ptr) { #endif } -void static inline WriteBE32(unsigned char *ptr, uint32_t x) { +void static inline WriteBE32(unsigned char* ptr, uint32_t x) +{ #if HAVE_DECL_HTOBE32 == 1 *((uint32_t*)ptr) = htobe32(x); #else - ptr[0] = x >> 24; ptr[1] = x >> 16; ptr[2] = x >> 8; ptr[3] = x; + ptr[0] = x >> 24; + ptr[1] = x >> 16; + ptr[2] = x >> 8; + ptr[3] = x; #endif } -void static inline WriteBE64(unsigned char *ptr, uint64_t x) { +void static inline WriteBE64(unsigned char* ptr, uint64_t x) +{ #if HAVE_DECL_HTOBE64 == 1 *((uint64_t*)ptr) = htobe64(x); #else - ptr[0] = x >> 56; ptr[1] = x >> 48; ptr[2] = x >> 40; ptr[3] = x >> 32; - ptr[4] = x >> 24; ptr[5] = x >> 16; ptr[6] = x >> 8; ptr[7] = x; + ptr[0] = x >> 56; + ptr[1] = x >> 48; + ptr[2] = x >> 40; + ptr[3] = x >> 32; + ptr[4] = x >> 24; + ptr[5] = x >> 16; + ptr[6] = x >> 8; + ptr[7] = x; #endif } -#endif +#endif // BITCOIN_CRYPTO_COMMON_H diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index b5e9f0df49..cb4a94a44d 100644 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "crypto/ripemd160.h" @@ -9,11 +9,11 @@ #include <string.h> // Internal implementation code. -namespace { - +namespace +{ /// Internal RIPEMD-160 implementation. -namespace ripemd160 { - +namespace ripemd160 +{ uint32_t inline f1(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; } uint32_t inline f2(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); } uint32_t inline f3(uint32_t x, uint32_t y, uint32_t z) { return (x | ~y) ^ z; } @@ -21,7 +21,8 @@ uint32_t inline f4(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~ uint32_t inline f5(uint32_t x, uint32_t y, uint32_t z) { return x ^ (y | ~z); } /** Initialize RIPEMD-160 state. */ -void inline Initialize(uint32_t *s) { +void inline Initialize(uint32_t* s) +{ s[0] = 0x67452301ul; s[1] = 0xEFCDAB89ul; s[2] = 0x98BADCFEul; @@ -29,139 +30,223 @@ void inline Initialize(uint32_t *s) { s[4] = 0xC3D2E1F0ul; } -uint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32-i)); } +uint32_t inline rol(uint32_t x, int i) { return (x << i) | (x >> (32 - i)); } -void inline Round(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r) { +void inline Round(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t f, uint32_t x, uint32_t k, int r) +{ a = rol(a + f + x + k, r) + e; c = rol(c, 10); } -void inline R11(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } -void inline R21(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); } -void inline R31(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); } -void inline R41(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); } -void inline R51(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); } +void inline R11(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } +void inline R21(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x5A827999ul, r); } +void inline R31(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6ED9EBA1ul, r); } +void inline R41(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x8F1BBCDCul, r); } +void inline R51(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0xA953FD4Eul, r); } -void inline R12(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); } -void inline R22(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); } -void inline R32(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); } -void inline R42(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); } -void inline R52(uint32_t &a, uint32_t b, uint32_t &c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } +void inline R12(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f5(b, c, d), x, 0x50A28BE6ul, r); } +void inline R22(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f4(b, c, d), x, 0x5C4DD124ul, r); } +void inline R32(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f3(b, c, d), x, 0x6D703EF3ul, r); } +void inline R42(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f2(b, c, d), x, 0x7A6D76E9ul, r); } +void inline R52(uint32_t& a, uint32_t b, uint32_t& c, uint32_t d, uint32_t e, uint32_t x, int r) { Round(a, b, c, d, e, f1(b, c, d), x, 0, r); } /** Perform a RIPEMD-160 transformation, processing a 64-byte chunk. */ -void Transform(uint32_t *s, const unsigned char *chunk) { +void Transform(uint32_t* s, const unsigned char* chunk) +{ uint32_t a1 = s[0], b1 = s[1], c1 = s[2], d1 = s[3], e1 = s[4]; - uint32_t a2 = a1 , b2 = b1 , c2 = c1 , d2 = d1 , e2 = e1 ; - uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12); - uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28); - uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44); + uint32_t a2 = a1, b2 = b1, c2 = c1, d2 = d1, e2 = e1; + uint32_t w0 = ReadLE32(chunk + 0), w1 = ReadLE32(chunk + 4), w2 = ReadLE32(chunk + 8), w3 = ReadLE32(chunk + 12); + uint32_t w4 = ReadLE32(chunk + 16), w5 = ReadLE32(chunk + 20), w6 = ReadLE32(chunk + 24), w7 = ReadLE32(chunk + 28); + uint32_t w8 = ReadLE32(chunk + 32), w9 = ReadLE32(chunk + 36), w10 = ReadLE32(chunk + 40), w11 = ReadLE32(chunk + 44); uint32_t w12 = ReadLE32(chunk + 48), w13 = ReadLE32(chunk + 52), w14 = ReadLE32(chunk + 56), w15 = ReadLE32(chunk + 60); - R11(a1, b1, c1, d1, e1, w0 , 11); R12(a2, b2, c2, d2, e2, w5 , 8); - R11(e1, a1, b1, c1, d1, w1 , 14); R12(e2, a2, b2, c2, d2, w14, 9); - R11(d1, e1, a1, b1, c1, w2 , 15); R12(d2, e2, a2, b2, c2, w7 , 9); - R11(c1, d1, e1, a1, b1, w3 , 12); R12(c2, d2, e2, a2, b2, w0 , 11); - R11(b1, c1, d1, e1, a1, w4 , 5); R12(b2, c2, d2, e2, a2, w9 , 13); - R11(a1, b1, c1, d1, e1, w5 , 8); R12(a2, b2, c2, d2, e2, w2 , 15); - R11(e1, a1, b1, c1, d1, w6 , 7); R12(e2, a2, b2, c2, d2, w11, 15); - R11(d1, e1, a1, b1, c1, w7 , 9); R12(d2, e2, a2, b2, c2, w4 , 5); - R11(c1, d1, e1, a1, b1, w8 , 11); R12(c2, d2, e2, a2, b2, w13, 7); - R11(b1, c1, d1, e1, a1, w9 , 13); R12(b2, c2, d2, e2, a2, w6 , 7); - R11(a1, b1, c1, d1, e1, w10, 14); R12(a2, b2, c2, d2, e2, w15, 8); - R11(e1, a1, b1, c1, d1, w11, 15); R12(e2, a2, b2, c2, d2, w8 , 11); - R11(d1, e1, a1, b1, c1, w12, 6); R12(d2, e2, a2, b2, c2, w1 , 14); - R11(c1, d1, e1, a1, b1, w13, 7); R12(c2, d2, e2, a2, b2, w10, 14); - R11(b1, c1, d1, e1, a1, w14, 9); R12(b2, c2, d2, e2, a2, w3 , 12); - R11(a1, b1, c1, d1, e1, w15, 8); R12(a2, b2, c2, d2, e2, w12, 6); - - R21(e1, a1, b1, c1, d1, w7 , 7); R22(e2, a2, b2, c2, d2, w6 , 9); - R21(d1, e1, a1, b1, c1, w4 , 6); R22(d2, e2, a2, b2, c2, w11, 13); - R21(c1, d1, e1, a1, b1, w13, 8); R22(c2, d2, e2, a2, b2, w3 , 15); - R21(b1, c1, d1, e1, a1, w1 , 13); R22(b2, c2, d2, e2, a2, w7 , 7); - R21(a1, b1, c1, d1, e1, w10, 11); R22(a2, b2, c2, d2, e2, w0 , 12); - R21(e1, a1, b1, c1, d1, w6 , 9); R22(e2, a2, b2, c2, d2, w13, 8); - R21(d1, e1, a1, b1, c1, w15, 7); R22(d2, e2, a2, b2, c2, w5 , 9); - R21(c1, d1, e1, a1, b1, w3 , 15); R22(c2, d2, e2, a2, b2, w10, 11); - R21(b1, c1, d1, e1, a1, w12, 7); R22(b2, c2, d2, e2, a2, w14, 7); - R21(a1, b1, c1, d1, e1, w0 , 12); R22(a2, b2, c2, d2, e2, w15, 7); - R21(e1, a1, b1, c1, d1, w9 , 15); R22(e2, a2, b2, c2, d2, w8 , 12); - R21(d1, e1, a1, b1, c1, w5 , 9); R22(d2, e2, a2, b2, c2, w12, 7); - R21(c1, d1, e1, a1, b1, w2 , 11); R22(c2, d2, e2, a2, b2, w4 , 6); - R21(b1, c1, d1, e1, a1, w14, 7); R22(b2, c2, d2, e2, a2, w9 , 15); - R21(a1, b1, c1, d1, e1, w11, 13); R22(a2, b2, c2, d2, e2, w1 , 13); - R21(e1, a1, b1, c1, d1, w8 , 12); R22(e2, a2, b2, c2, d2, w2 , 11); - - R31(d1, e1, a1, b1, c1, w3 , 11); R32(d2, e2, a2, b2, c2, w15, 9); - R31(c1, d1, e1, a1, b1, w10, 13); R32(c2, d2, e2, a2, b2, w5 , 7); - R31(b1, c1, d1, e1, a1, w14, 6); R32(b2, c2, d2, e2, a2, w1 , 15); - R31(a1, b1, c1, d1, e1, w4 , 7); R32(a2, b2, c2, d2, e2, w3 , 11); - R31(e1, a1, b1, c1, d1, w9 , 14); R32(e2, a2, b2, c2, d2, w7 , 8); - R31(d1, e1, a1, b1, c1, w15, 9); R32(d2, e2, a2, b2, c2, w14, 6); - R31(c1, d1, e1, a1, b1, w8 , 13); R32(c2, d2, e2, a2, b2, w6 , 6); - R31(b1, c1, d1, e1, a1, w1 , 15); R32(b2, c2, d2, e2, a2, w9 , 14); - R31(a1, b1, c1, d1, e1, w2 , 14); R32(a2, b2, c2, d2, e2, w11, 12); - R31(e1, a1, b1, c1, d1, w7 , 8); R32(e2, a2, b2, c2, d2, w8 , 13); - R31(d1, e1, a1, b1, c1, w0 , 13); R32(d2, e2, a2, b2, c2, w12, 5); - R31(c1, d1, e1, a1, b1, w6 , 6); R32(c2, d2, e2, a2, b2, w2 , 14); - R31(b1, c1, d1, e1, a1, w13, 5); R32(b2, c2, d2, e2, a2, w10, 13); - R31(a1, b1, c1, d1, e1, w11, 12); R32(a2, b2, c2, d2, e2, w0 , 13); - R31(e1, a1, b1, c1, d1, w5 , 7); R32(e2, a2, b2, c2, d2, w4 , 7); - R31(d1, e1, a1, b1, c1, w12, 5); R32(d2, e2, a2, b2, c2, w13, 5); - - R41(c1, d1, e1, a1, b1, w1 , 11); R42(c2, d2, e2, a2, b2, w8 , 15); - R41(b1, c1, d1, e1, a1, w9 , 12); R42(b2, c2, d2, e2, a2, w6 , 5); - R41(a1, b1, c1, d1, e1, w11, 14); R42(a2, b2, c2, d2, e2, w4 , 8); - R41(e1, a1, b1, c1, d1, w10, 15); R42(e2, a2, b2, c2, d2, w1 , 11); - R41(d1, e1, a1, b1, c1, w0 , 14); R42(d2, e2, a2, b2, c2, w3 , 14); - R41(c1, d1, e1, a1, b1, w8 , 15); R42(c2, d2, e2, a2, b2, w11, 14); - R41(b1, c1, d1, e1, a1, w12, 9); R42(b2, c2, d2, e2, a2, w15, 6); - R41(a1, b1, c1, d1, e1, w4 , 8); R42(a2, b2, c2, d2, e2, w0 , 14); - R41(e1, a1, b1, c1, d1, w13, 9); R42(e2, a2, b2, c2, d2, w5 , 6); - R41(d1, e1, a1, b1, c1, w3 , 14); R42(d2, e2, a2, b2, c2, w12, 9); - R41(c1, d1, e1, a1, b1, w7 , 5); R42(c2, d2, e2, a2, b2, w2 , 12); - R41(b1, c1, d1, e1, a1, w15, 6); R42(b2, c2, d2, e2, a2, w13, 9); - R41(a1, b1, c1, d1, e1, w14, 8); R42(a2, b2, c2, d2, e2, w9 , 12); - R41(e1, a1, b1, c1, d1, w5 , 6); R42(e2, a2, b2, c2, d2, w7 , 5); - R41(d1, e1, a1, b1, c1, w6 , 5); R42(d2, e2, a2, b2, c2, w10, 15); - R41(c1, d1, e1, a1, b1, w2 , 12); R42(c2, d2, e2, a2, b2, w14, 8); - - R51(b1, c1, d1, e1, a1, w4 , 9); R52(b2, c2, d2, e2, a2, w12, 8); - R51(a1, b1, c1, d1, e1, w0 , 15); R52(a2, b2, c2, d2, e2, w15, 5); - R51(e1, a1, b1, c1, d1, w5 , 5); R52(e2, a2, b2, c2, d2, w10, 12); - R51(d1, e1, a1, b1, c1, w9 , 11); R52(d2, e2, a2, b2, c2, w4 , 9); - R51(c1, d1, e1, a1, b1, w7 , 6); R52(c2, d2, e2, a2, b2, w1 , 12); - R51(b1, c1, d1, e1, a1, w12, 8); R52(b2, c2, d2, e2, a2, w5 , 5); - R51(a1, b1, c1, d1, e1, w2 , 13); R52(a2, b2, c2, d2, e2, w8 , 14); - R51(e1, a1, b1, c1, d1, w10, 12); R52(e2, a2, b2, c2, d2, w7 , 6); - R51(d1, e1, a1, b1, c1, w14, 5); R52(d2, e2, a2, b2, c2, w6 , 8); - R51(c1, d1, e1, a1, b1, w1 , 12); R52(c2, d2, e2, a2, b2, w2 , 13); - R51(b1, c1, d1, e1, a1, w3 , 13); R52(b2, c2, d2, e2, a2, w13, 6); - R51(a1, b1, c1, d1, e1, w8 , 14); R52(a2, b2, c2, d2, e2, w14, 5); - R51(e1, a1, b1, c1, d1, w11, 11); R52(e2, a2, b2, c2, d2, w0 , 15); - R51(d1, e1, a1, b1, c1, w6 , 8); R52(d2, e2, a2, b2, c2, w3 , 13); - R51(c1, d1, e1, a1, b1, w15, 5); R52(c2, d2, e2, a2, b2, w9 , 11); - R51(b1, c1, d1, e1, a1, w13, 6); R52(b2, c2, d2, e2, a2, w11, 11); + R11(a1, b1, c1, d1, e1, w0, 11); + R12(a2, b2, c2, d2, e2, w5, 8); + R11(e1, a1, b1, c1, d1, w1, 14); + R12(e2, a2, b2, c2, d2, w14, 9); + R11(d1, e1, a1, b1, c1, w2, 15); + R12(d2, e2, a2, b2, c2, w7, 9); + R11(c1, d1, e1, a1, b1, w3, 12); + R12(c2, d2, e2, a2, b2, w0, 11); + R11(b1, c1, d1, e1, a1, w4, 5); + R12(b2, c2, d2, e2, a2, w9, 13); + R11(a1, b1, c1, d1, e1, w5, 8); + R12(a2, b2, c2, d2, e2, w2, 15); + R11(e1, a1, b1, c1, d1, w6, 7); + R12(e2, a2, b2, c2, d2, w11, 15); + R11(d1, e1, a1, b1, c1, w7, 9); + R12(d2, e2, a2, b2, c2, w4, 5); + R11(c1, d1, e1, a1, b1, w8, 11); + R12(c2, d2, e2, a2, b2, w13, 7); + R11(b1, c1, d1, e1, a1, w9, 13); + R12(b2, c2, d2, e2, a2, w6, 7); + R11(a1, b1, c1, d1, e1, w10, 14); + R12(a2, b2, c2, d2, e2, w15, 8); + R11(e1, a1, b1, c1, d1, w11, 15); + R12(e2, a2, b2, c2, d2, w8, 11); + R11(d1, e1, a1, b1, c1, w12, 6); + R12(d2, e2, a2, b2, c2, w1, 14); + R11(c1, d1, e1, a1, b1, w13, 7); + R12(c2, d2, e2, a2, b2, w10, 14); + R11(b1, c1, d1, e1, a1, w14, 9); + R12(b2, c2, d2, e2, a2, w3, 12); + R11(a1, b1, c1, d1, e1, w15, 8); + R12(a2, b2, c2, d2, e2, w12, 6); + + R21(e1, a1, b1, c1, d1, w7, 7); + R22(e2, a2, b2, c2, d2, w6, 9); + R21(d1, e1, a1, b1, c1, w4, 6); + R22(d2, e2, a2, b2, c2, w11, 13); + R21(c1, d1, e1, a1, b1, w13, 8); + R22(c2, d2, e2, a2, b2, w3, 15); + R21(b1, c1, d1, e1, a1, w1, 13); + R22(b2, c2, d2, e2, a2, w7, 7); + R21(a1, b1, c1, d1, e1, w10, 11); + R22(a2, b2, c2, d2, e2, w0, 12); + R21(e1, a1, b1, c1, d1, w6, 9); + R22(e2, a2, b2, c2, d2, w13, 8); + R21(d1, e1, a1, b1, c1, w15, 7); + R22(d2, e2, a2, b2, c2, w5, 9); + R21(c1, d1, e1, a1, b1, w3, 15); + R22(c2, d2, e2, a2, b2, w10, 11); + R21(b1, c1, d1, e1, a1, w12, 7); + R22(b2, c2, d2, e2, a2, w14, 7); + R21(a1, b1, c1, d1, e1, w0, 12); + R22(a2, b2, c2, d2, e2, w15, 7); + R21(e1, a1, b1, c1, d1, w9, 15); + R22(e2, a2, b2, c2, d2, w8, 12); + R21(d1, e1, a1, b1, c1, w5, 9); + R22(d2, e2, a2, b2, c2, w12, 7); + R21(c1, d1, e1, a1, b1, w2, 11); + R22(c2, d2, e2, a2, b2, w4, 6); + R21(b1, c1, d1, e1, a1, w14, 7); + R22(b2, c2, d2, e2, a2, w9, 15); + R21(a1, b1, c1, d1, e1, w11, 13); + R22(a2, b2, c2, d2, e2, w1, 13); + R21(e1, a1, b1, c1, d1, w8, 12); + R22(e2, a2, b2, c2, d2, w2, 11); + + R31(d1, e1, a1, b1, c1, w3, 11); + R32(d2, e2, a2, b2, c2, w15, 9); + R31(c1, d1, e1, a1, b1, w10, 13); + R32(c2, d2, e2, a2, b2, w5, 7); + R31(b1, c1, d1, e1, a1, w14, 6); + R32(b2, c2, d2, e2, a2, w1, 15); + R31(a1, b1, c1, d1, e1, w4, 7); + R32(a2, b2, c2, d2, e2, w3, 11); + R31(e1, a1, b1, c1, d1, w9, 14); + R32(e2, a2, b2, c2, d2, w7, 8); + R31(d1, e1, a1, b1, c1, w15, 9); + R32(d2, e2, a2, b2, c2, w14, 6); + R31(c1, d1, e1, a1, b1, w8, 13); + R32(c2, d2, e2, a2, b2, w6, 6); + R31(b1, c1, d1, e1, a1, w1, 15); + R32(b2, c2, d2, e2, a2, w9, 14); + R31(a1, b1, c1, d1, e1, w2, 14); + R32(a2, b2, c2, d2, e2, w11, 12); + R31(e1, a1, b1, c1, d1, w7, 8); + R32(e2, a2, b2, c2, d2, w8, 13); + R31(d1, e1, a1, b1, c1, w0, 13); + R32(d2, e2, a2, b2, c2, w12, 5); + R31(c1, d1, e1, a1, b1, w6, 6); + R32(c2, d2, e2, a2, b2, w2, 14); + R31(b1, c1, d1, e1, a1, w13, 5); + R32(b2, c2, d2, e2, a2, w10, 13); + R31(a1, b1, c1, d1, e1, w11, 12); + R32(a2, b2, c2, d2, e2, w0, 13); + R31(e1, a1, b1, c1, d1, w5, 7); + R32(e2, a2, b2, c2, d2, w4, 7); + R31(d1, e1, a1, b1, c1, w12, 5); + R32(d2, e2, a2, b2, c2, w13, 5); + + R41(c1, d1, e1, a1, b1, w1, 11); + R42(c2, d2, e2, a2, b2, w8, 15); + R41(b1, c1, d1, e1, a1, w9, 12); + R42(b2, c2, d2, e2, a2, w6, 5); + R41(a1, b1, c1, d1, e1, w11, 14); + R42(a2, b2, c2, d2, e2, w4, 8); + R41(e1, a1, b1, c1, d1, w10, 15); + R42(e2, a2, b2, c2, d2, w1, 11); + R41(d1, e1, a1, b1, c1, w0, 14); + R42(d2, e2, a2, b2, c2, w3, 14); + R41(c1, d1, e1, a1, b1, w8, 15); + R42(c2, d2, e2, a2, b2, w11, 14); + R41(b1, c1, d1, e1, a1, w12, 9); + R42(b2, c2, d2, e2, a2, w15, 6); + R41(a1, b1, c1, d1, e1, w4, 8); + R42(a2, b2, c2, d2, e2, w0, 14); + R41(e1, a1, b1, c1, d1, w13, 9); + R42(e2, a2, b2, c2, d2, w5, 6); + R41(d1, e1, a1, b1, c1, w3, 14); + R42(d2, e2, a2, b2, c2, w12, 9); + R41(c1, d1, e1, a1, b1, w7, 5); + R42(c2, d2, e2, a2, b2, w2, 12); + R41(b1, c1, d1, e1, a1, w15, 6); + R42(b2, c2, d2, e2, a2, w13, 9); + R41(a1, b1, c1, d1, e1, w14, 8); + R42(a2, b2, c2, d2, e2, w9, 12); + R41(e1, a1, b1, c1, d1, w5, 6); + R42(e2, a2, b2, c2, d2, w7, 5); + R41(d1, e1, a1, b1, c1, w6, 5); + R42(d2, e2, a2, b2, c2, w10, 15); + R41(c1, d1, e1, a1, b1, w2, 12); + R42(c2, d2, e2, a2, b2, w14, 8); + + R51(b1, c1, d1, e1, a1, w4, 9); + R52(b2, c2, d2, e2, a2, w12, 8); + R51(a1, b1, c1, d1, e1, w0, 15); + R52(a2, b2, c2, d2, e2, w15, 5); + R51(e1, a1, b1, c1, d1, w5, 5); + R52(e2, a2, b2, c2, d2, w10, 12); + R51(d1, e1, a1, b1, c1, w9, 11); + R52(d2, e2, a2, b2, c2, w4, 9); + R51(c1, d1, e1, a1, b1, w7, 6); + R52(c2, d2, e2, a2, b2, w1, 12); + R51(b1, c1, d1, e1, a1, w12, 8); + R52(b2, c2, d2, e2, a2, w5, 5); + R51(a1, b1, c1, d1, e1, w2, 13); + R52(a2, b2, c2, d2, e2, w8, 14); + R51(e1, a1, b1, c1, d1, w10, 12); + R52(e2, a2, b2, c2, d2, w7, 6); + R51(d1, e1, a1, b1, c1, w14, 5); + R52(d2, e2, a2, b2, c2, w6, 8); + R51(c1, d1, e1, a1, b1, w1, 12); + R52(c2, d2, e2, a2, b2, w2, 13); + R51(b1, c1, d1, e1, a1, w3, 13); + R52(b2, c2, d2, e2, a2, w13, 6); + R51(a1, b1, c1, d1, e1, w8, 14); + R52(a2, b2, c2, d2, e2, w14, 5); + R51(e1, a1, b1, c1, d1, w11, 11); + R52(e2, a2, b2, c2, d2, w0, 15); + R51(d1, e1, a1, b1, c1, w6, 8); + R52(d2, e2, a2, b2, c2, w3, 13); + R51(c1, d1, e1, a1, b1, w15, 5); + R52(c2, d2, e2, a2, b2, w9, 11); + R51(b1, c1, d1, e1, a1, w13, 6); + R52(b2, c2, d2, e2, a2, w11, 11); uint32_t t = s[0]; s[0] = s[1] + c1 + d2; s[1] = s[2] + d1 + e2; s[2] = s[3] + e1 + a2; s[3] = s[4] + a1 + b2; - s[4] = t + b1 + c2; + s[4] = t + b1 + c2; } -} // namespace ripemd160 +} // namespace ripemd160 -} // namespace +} // namespace ////// RIPEMD160 -CRIPEMD160::CRIPEMD160() : bytes(0) { +CRIPEMD160::CRIPEMD160() : bytes(0) +{ ripemd160::Initialize(s); } -CRIPEMD160& CRIPEMD160::Write(const unsigned char *data, size_t len) { - const unsigned char *end = data + len; +CRIPEMD160& CRIPEMD160::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; size_t bufsize = bytes % 64; if (bufsize && bufsize + len >= 64) { // Fill the buffer, and process it. @@ -185,20 +270,22 @@ CRIPEMD160& CRIPEMD160::Write(const unsigned char *data, size_t len) { return *this; } -void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE]) { +void CRIPEMD160::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; WriteLE64(sizedesc, bytes << 3); Write(pad, 1 + ((119 - (bytes % 64)) % 64)); Write(sizedesc, 8); WriteLE32(hash, s[0]); - WriteLE32(hash+4, s[1]); - WriteLE32(hash+8, s[2]); - WriteLE32(hash+12, s[3]); - WriteLE32(hash+16, s[4]); + WriteLE32(hash + 4, s[1]); + WriteLE32(hash + 8, s[2]); + WriteLE32(hash + 12, s[3]); + WriteLE32(hash + 16, s[4]); } -CRIPEMD160& CRIPEMD160::Reset() { +CRIPEMD160& CRIPEMD160::Reset() +{ bytes = 0; ripemd160::Initialize(s); return *this; diff --git a/src/crypto/ripemd160.h b/src/crypto/ripemd160.h index 44bd4879a5..902e7ca83f 100644 --- a/src/crypto/ripemd160.h +++ b/src/crypto/ripemd160.h @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_RIPEMD160_H @@ -9,7 +9,8 @@ #include <stdlib.h> /** A hasher class for RIPEMD-160. */ -class CRIPEMD160 { +class CRIPEMD160 +{ private: uint32_t s[5]; unsigned char buf[64]; @@ -19,9 +20,9 @@ public: static const size_t OUTPUT_SIZE = 20; CRIPEMD160(); - CRIPEMD160& Write(const unsigned char *data, size_t len); + CRIPEMD160& Write(const unsigned char* data, size_t len); void Finalize(unsigned char hash[OUTPUT_SIZE]); CRIPEMD160& Reset(); }; -#endif +#endif // BITCOIN_RIPEMD160_H diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 819abab579..7f78fdfc6d 100644 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "crypto/sha1.h" @@ -9,14 +9,14 @@ #include <string.h> // Internal implementation code. -namespace { - +namespace +{ /// Internal SHA-1 implementation. -namespace sha1 { - +namespace sha1 +{ /** One round of SHA-1. */ -void inline Round(uint32_t a, uint32_t &b, uint32_t c, uint32_t d, uint32_t &e, - uint32_t f, uint32_t k, uint32_t w) { +void inline Round(uint32_t a, uint32_t& b, uint32_t c, uint32_t d, uint32_t& e, uint32_t f, uint32_t k, uint32_t w) +{ e += ((a << 5) | (a >> 27)) + f + k + w; b = (b << 30) | (b >> 2); } @@ -28,7 +28,8 @@ uint32_t inline f3(uint32_t b, uint32_t c, uint32_t d) { return (b & c) | (d & ( uint32_t inline left(uint32_t x) { return (x << 1) | (x >> 31); } /** Initialize SHA-1 state. */ -void inline Initialize(uint32_t *s) { +void inline Initialize(uint32_t* s) +{ s[0] = 0x67452301ul; s[1] = 0xEFCDAB89ul; s[2] = 0x98BADCFEul; @@ -42,20 +43,21 @@ const uint32_t k3 = 0x8F1BBCDCul; const uint32_t k4 = 0xCA62C1D6ul; /** Perform a SHA-1 transformation, processing a 64-byte chunk. */ -void Transform(uint32_t *s, const unsigned char *chunk) { +void Transform(uint32_t* s, const unsigned char* chunk) +{ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4]; uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - Round(a, b, c, d, e, f1(b, c, d), k1, w0 = ReadBE32(chunk + 0)); - Round(e, a, b, c, d, f1(a, b, c), k1, w1 = ReadBE32(chunk + 4)); - Round(d, e, a, b, c, f1(e, a, b), k1, w2 = ReadBE32(chunk + 8)); - Round(c, d, e, a, b, f1(d, e, a), k1, w3 = ReadBE32(chunk + 12)); - Round(b, c, d, e, a, f1(c, d, e), k1, w4 = ReadBE32(chunk + 16)); - Round(a, b, c, d, e, f1(b, c, d), k1, w5 = ReadBE32(chunk + 20)); - Round(e, a, b, c, d, f1(a, b, c), k1, w6 = ReadBE32(chunk + 24)); - Round(d, e, a, b, c, f1(e, a, b), k1, w7 = ReadBE32(chunk + 28)); - Round(c, d, e, a, b, f1(d, e, a), k1, w8 = ReadBE32(chunk + 32)); - Round(b, c, d, e, a, f1(c, d, e), k1, w9 = ReadBE32(chunk + 36)); + Round(a, b, c, d, e, f1(b, c, d), k1, w0 = ReadBE32(chunk + 0)); + Round(e, a, b, c, d, f1(a, b, c), k1, w1 = ReadBE32(chunk + 4)); + Round(d, e, a, b, c, f1(e, a, b), k1, w2 = ReadBE32(chunk + 8)); + Round(c, d, e, a, b, f1(d, e, a), k1, w3 = ReadBE32(chunk + 12)); + Round(b, c, d, e, a, f1(c, d, e), k1, w4 = ReadBE32(chunk + 16)); + Round(a, b, c, d, e, f1(b, c, d), k1, w5 = ReadBE32(chunk + 20)); + Round(e, a, b, c, d, f1(a, b, c), k1, w6 = ReadBE32(chunk + 24)); + Round(d, e, a, b, c, f1(e, a, b), k1, w7 = ReadBE32(chunk + 28)); + Round(c, d, e, a, b, f1(d, e, a), k1, w8 = ReadBE32(chunk + 32)); + Round(b, c, d, e, a, f1(c, d, e), k1, w9 = ReadBE32(chunk + 36)); Round(a, b, c, d, e, f1(b, c, d), k1, w10 = ReadBE32(chunk + 40)); Round(e, a, b, c, d, f1(a, b, c), k1, w11 = ReadBE32(chunk + 44)); Round(d, e, a, b, c, f1(e, a, b), k1, w12 = ReadBE32(chunk + 48)); @@ -63,73 +65,73 @@ void Transform(uint32_t *s, const unsigned char *chunk) { Round(b, c, d, e, a, f1(c, d, e), k1, w14 = ReadBE32(chunk + 56)); Round(a, b, c, d, e, f1(b, c, d), k1, w15 = ReadBE32(chunk + 60)); - Round(e, a, b, c, d, f1(a, b, c), k1, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); - Round(d, e, a, b, c, f1(e, a, b), k1, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); - Round(c, d, e, a, b, f1(d, e, a), k1, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); - Round(b, c, d, e, a, f1(c, d, e), k1, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); - Round(a, b, c, d, e, f2(b, c, d), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); - Round(e, a, b, c, d, f2(a, b, c), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); - Round(d, e, a, b, c, f2(e, a, b), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); - Round(c, d, e, a, b, f2(d, e, a), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); - Round(b, c, d, e, a, f2(c, d, e), k2, w8 = left(w8 ^ w5 ^ w0 ^ w10)); - Round(a, b, c, d, e, f2(b, c, d), k2, w9 = left(w9 ^ w6 ^ w1 ^ w11)); - Round(e, a, b, c, d, f2(a, b, c), k2, w10 = left(w10 ^ w7 ^ w2 ^ w12)); - Round(d, e, a, b, c, f2(e, a, b), k2, w11 = left(w11 ^ w8 ^ w3 ^ w13)); - Round(c, d, e, a, b, f2(d, e, a), k2, w12 = left(w12 ^ w9 ^ w4 ^ w14)); - Round(b, c, d, e, a, f2(c, d, e), k2, w13 = left(w13 ^ w10 ^ w5 ^ w15)); - Round(a, b, c, d, e, f2(b, c, d), k2, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); - Round(e, a, b, c, d, f2(a, b, c), k2, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); - - Round(d, e, a, b, c, f2(e, a, b), k2, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); - Round(c, d, e, a, b, f2(d, e, a), k2, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); - Round(b, c, d, e, a, f2(c, d, e), k2, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); - Round(a, b, c, d, e, f2(b, c, d), k2, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); - Round(e, a, b, c, d, f2(a, b, c), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); - Round(d, e, a, b, c, f2(e, a, b), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); - Round(c, d, e, a, b, f2(d, e, a), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); - Round(b, c, d, e, a, f2(c, d, e), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); - Round(a, b, c, d, e, f3(b, c, d), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); - Round(e, a, b, c, d, f3(a, b, c), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); - Round(d, e, a, b, c, f3(e, a, b), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); - Round(c, d, e, a, b, f3(d, e, a), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); - Round(b, c, d, e, a, f3(c, d, e), k3, w12 = left(w12 ^ w9 ^ w4 ^ w14)); - Round(a, b, c, d, e, f3(b, c, d), k3, w13 = left(w13 ^ w10 ^ w5 ^ w15)); - Round(e, a, b, c, d, f3(a, b, c), k3, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); - Round(d, e, a, b, c, f3(e, a, b), k3, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); - - Round(c, d, e, a, b, f3(d, e, a), k3, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); - Round(b, c, d, e, a, f3(c, d, e), k3, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); - Round(a, b, c, d, e, f3(b, c, d), k3, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); - Round(e, a, b, c, d, f3(a, b, c), k3, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); - Round(d, e, a, b, c, f3(e, a, b), k3, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); - Round(c, d, e, a, b, f3(d, e, a), k3, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); - Round(b, c, d, e, a, f3(c, d, e), k3, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); - Round(a, b, c, d, e, f3(b, c, d), k3, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); - Round(e, a, b, c, d, f3(a, b, c), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); - Round(d, e, a, b, c, f3(e, a, b), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); - Round(c, d, e, a, b, f3(d, e, a), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); - Round(b, c, d, e, a, f3(c, d, e), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); - Round(a, b, c, d, e, f2(b, c, d), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); - Round(e, a, b, c, d, f2(a, b, c), k4, w13 = left(w13 ^ w10 ^ w5 ^ w15)); - Round(d, e, a, b, c, f2(e, a, b), k4, w14 = left(w14 ^ w11 ^ w6 ^ w0 )); - Round(c, d, e, a, b, f2(d, e, a), k4, w15 = left(w15 ^ w12 ^ w7 ^ w1 )); - - Round(b, c, d, e, a, f2(c, d, e), k4, w0 = left(w0 ^ w13 ^ w8 ^ w2 )); - Round(a, b, c, d, e, f2(b, c, d), k4, w1 = left(w1 ^ w14 ^ w9 ^ w3 )); - Round(e, a, b, c, d, f2(a, b, c), k4, w2 = left(w2 ^ w15 ^ w10 ^ w4 )); - Round(d, e, a, b, c, f2(e, a, b), k4, w3 = left(w3 ^ w0 ^ w11 ^ w5 )); - Round(c, d, e, a, b, f2(d, e, a), k4, w4 = left(w4 ^ w1 ^ w12 ^ w6 )); - Round(b, c, d, e, a, f2(c, d, e), k4, w5 = left(w5 ^ w2 ^ w13 ^ w7 )); - Round(a, b, c, d, e, f2(b, c, d), k4, w6 = left(w6 ^ w3 ^ w14 ^ w8 )); - Round(e, a, b, c, d, f2(a, b, c), k4, w7 = left(w7 ^ w4 ^ w15 ^ w9 )); - Round(d, e, a, b, c, f2(e, a, b), k4, w8 = left(w8 ^ w5 ^ w0 ^ w10)); - Round(c, d, e, a, b, f2(d, e, a), k4, w9 = left(w9 ^ w6 ^ w1 ^ w11)); - Round(b, c, d, e, a, f2(c, d, e), k4, w10 = left(w10 ^ w7 ^ w2 ^ w12)); - Round(a, b, c, d, e, f2(b, c, d), k4, w11 = left(w11 ^ w8 ^ w3 ^ w13)); - Round(e, a, b, c, d, f2(a, b, c), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); - Round(d, e, a, b, c, f2(e, a, b), k4, left(w13 ^ w10 ^ w5 ^ w15)); - Round(c, d, e, a, b, f2(d, e, a), k4, left(w14 ^ w11 ^ w6 ^ w0 )); - Round(b, c, d, e, a, f2(c, d, e), k4, left(w15 ^ w12 ^ w7 ^ w1 )); + Round(e, a, b, c, d, f1(a, b, c), k1, w0 = left(w0 ^ w13 ^ w8 ^ w2)); + Round(d, e, a, b, c, f1(e, a, b), k1, w1 = left(w1 ^ w14 ^ w9 ^ w3)); + Round(c, d, e, a, b, f1(d, e, a), k1, w2 = left(w2 ^ w15 ^ w10 ^ w4)); + Round(b, c, d, e, a, f1(c, d, e), k1, w3 = left(w3 ^ w0 ^ w11 ^ w5)); + Round(a, b, c, d, e, f2(b, c, d), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6)); + Round(e, a, b, c, d, f2(a, b, c), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7)); + Round(d, e, a, b, c, f2(e, a, b), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8)); + Round(c, d, e, a, b, f2(d, e, a), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9)); + Round(b, c, d, e, a, f2(c, d, e), k2, w8 = left(w8 ^ w5 ^ w0 ^ w10)); + Round(a, b, c, d, e, f2(b, c, d), k2, w9 = left(w9 ^ w6 ^ w1 ^ w11)); + Round(e, a, b, c, d, f2(a, b, c), k2, w10 = left(w10 ^ w7 ^ w2 ^ w12)); + Round(d, e, a, b, c, f2(e, a, b), k2, w11 = left(w11 ^ w8 ^ w3 ^ w13)); + Round(c, d, e, a, b, f2(d, e, a), k2, w12 = left(w12 ^ w9 ^ w4 ^ w14)); + Round(b, c, d, e, a, f2(c, d, e), k2, w13 = left(w13 ^ w10 ^ w5 ^ w15)); + Round(a, b, c, d, e, f2(b, c, d), k2, w14 = left(w14 ^ w11 ^ w6 ^ w0)); + Round(e, a, b, c, d, f2(a, b, c), k2, w15 = left(w15 ^ w12 ^ w7 ^ w1)); + + Round(d, e, a, b, c, f2(e, a, b), k2, w0 = left(w0 ^ w13 ^ w8 ^ w2)); + Round(c, d, e, a, b, f2(d, e, a), k2, w1 = left(w1 ^ w14 ^ w9 ^ w3)); + Round(b, c, d, e, a, f2(c, d, e), k2, w2 = left(w2 ^ w15 ^ w10 ^ w4)); + Round(a, b, c, d, e, f2(b, c, d), k2, w3 = left(w3 ^ w0 ^ w11 ^ w5)); + Round(e, a, b, c, d, f2(a, b, c), k2, w4 = left(w4 ^ w1 ^ w12 ^ w6)); + Round(d, e, a, b, c, f2(e, a, b), k2, w5 = left(w5 ^ w2 ^ w13 ^ w7)); + Round(c, d, e, a, b, f2(d, e, a), k2, w6 = left(w6 ^ w3 ^ w14 ^ w8)); + Round(b, c, d, e, a, f2(c, d, e), k2, w7 = left(w7 ^ w4 ^ w15 ^ w9)); + Round(a, b, c, d, e, f3(b, c, d), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); + Round(e, a, b, c, d, f3(a, b, c), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); + Round(d, e, a, b, c, f3(e, a, b), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); + Round(c, d, e, a, b, f3(d, e, a), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); + Round(b, c, d, e, a, f3(c, d, e), k3, w12 = left(w12 ^ w9 ^ w4 ^ w14)); + Round(a, b, c, d, e, f3(b, c, d), k3, w13 = left(w13 ^ w10 ^ w5 ^ w15)); + Round(e, a, b, c, d, f3(a, b, c), k3, w14 = left(w14 ^ w11 ^ w6 ^ w0)); + Round(d, e, a, b, c, f3(e, a, b), k3, w15 = left(w15 ^ w12 ^ w7 ^ w1)); + + Round(c, d, e, a, b, f3(d, e, a), k3, w0 = left(w0 ^ w13 ^ w8 ^ w2)); + Round(b, c, d, e, a, f3(c, d, e), k3, w1 = left(w1 ^ w14 ^ w9 ^ w3)); + Round(a, b, c, d, e, f3(b, c, d), k3, w2 = left(w2 ^ w15 ^ w10 ^ w4)); + Round(e, a, b, c, d, f3(a, b, c), k3, w3 = left(w3 ^ w0 ^ w11 ^ w5)); + Round(d, e, a, b, c, f3(e, a, b), k3, w4 = left(w4 ^ w1 ^ w12 ^ w6)); + Round(c, d, e, a, b, f3(d, e, a), k3, w5 = left(w5 ^ w2 ^ w13 ^ w7)); + Round(b, c, d, e, a, f3(c, d, e), k3, w6 = left(w6 ^ w3 ^ w14 ^ w8)); + Round(a, b, c, d, e, f3(b, c, d), k3, w7 = left(w7 ^ w4 ^ w15 ^ w9)); + Round(e, a, b, c, d, f3(a, b, c), k3, w8 = left(w8 ^ w5 ^ w0 ^ w10)); + Round(d, e, a, b, c, f3(e, a, b), k3, w9 = left(w9 ^ w6 ^ w1 ^ w11)); + Round(c, d, e, a, b, f3(d, e, a), k3, w10 = left(w10 ^ w7 ^ w2 ^ w12)); + Round(b, c, d, e, a, f3(c, d, e), k3, w11 = left(w11 ^ w8 ^ w3 ^ w13)); + Round(a, b, c, d, e, f2(b, c, d), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); + Round(e, a, b, c, d, f2(a, b, c), k4, w13 = left(w13 ^ w10 ^ w5 ^ w15)); + Round(d, e, a, b, c, f2(e, a, b), k4, w14 = left(w14 ^ w11 ^ w6 ^ w0)); + Round(c, d, e, a, b, f2(d, e, a), k4, w15 = left(w15 ^ w12 ^ w7 ^ w1)); + + Round(b, c, d, e, a, f2(c, d, e), k4, w0 = left(w0 ^ w13 ^ w8 ^ w2)); + Round(a, b, c, d, e, f2(b, c, d), k4, w1 = left(w1 ^ w14 ^ w9 ^ w3)); + Round(e, a, b, c, d, f2(a, b, c), k4, w2 = left(w2 ^ w15 ^ w10 ^ w4)); + Round(d, e, a, b, c, f2(e, a, b), k4, w3 = left(w3 ^ w0 ^ w11 ^ w5)); + Round(c, d, e, a, b, f2(d, e, a), k4, w4 = left(w4 ^ w1 ^ w12 ^ w6)); + Round(b, c, d, e, a, f2(c, d, e), k4, w5 = left(w5 ^ w2 ^ w13 ^ w7)); + Round(a, b, c, d, e, f2(b, c, d), k4, w6 = left(w6 ^ w3 ^ w14 ^ w8)); + Round(e, a, b, c, d, f2(a, b, c), k4, w7 = left(w7 ^ w4 ^ w15 ^ w9)); + Round(d, e, a, b, c, f2(e, a, b), k4, w8 = left(w8 ^ w5 ^ w0 ^ w10)); + Round(c, d, e, a, b, f2(d, e, a), k4, w9 = left(w9 ^ w6 ^ w1 ^ w11)); + Round(b, c, d, e, a, f2(c, d, e), k4, w10 = left(w10 ^ w7 ^ w2 ^ w12)); + Round(a, b, c, d, e, f2(b, c, d), k4, w11 = left(w11 ^ w8 ^ w3 ^ w13)); + Round(e, a, b, c, d, f2(a, b, c), k4, w12 = left(w12 ^ w9 ^ w4 ^ w14)); + Round(d, e, a, b, c, f2(e, a, b), k4, left(w13 ^ w10 ^ w5 ^ w15)); + Round(c, d, e, a, b, f2(d, e, a), k4, left(w14 ^ w11 ^ w6 ^ w0)); + Round(b, c, d, e, a, f2(c, d, e), k4, left(w15 ^ w12 ^ w7 ^ w1)); s[0] += a; s[1] += b; @@ -138,18 +140,20 @@ void Transform(uint32_t *s, const unsigned char *chunk) { s[4] += e; } -} // namespace sha1 +} // namespace sha1 -} // namespace +} // namespace ////// SHA1 -CSHA1::CSHA1() : bytes(0) { +CSHA1::CSHA1() : bytes(0) +{ sha1::Initialize(s); } -CSHA1& CSHA1::Write(const unsigned char *data, size_t len) { - const unsigned char *end = data + len; +CSHA1& CSHA1::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; size_t bufsize = bytes % 64; if (bufsize && bufsize + len >= 64) { // Fill the buffer, and process it. @@ -173,20 +177,22 @@ CSHA1& CSHA1::Write(const unsigned char *data, size_t len) { return *this; } -void CSHA1::Finalize(unsigned char hash[OUTPUT_SIZE]) { +void CSHA1::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; WriteBE64(sizedesc, bytes << 3); Write(pad, 1 + ((119 - (bytes % 64)) % 64)); Write(sizedesc, 8); WriteBE32(hash, s[0]); - WriteBE32(hash+4, s[1]); - WriteBE32(hash+8, s[2]); - WriteBE32(hash+12, s[3]); - WriteBE32(hash+16, s[4]); + WriteBE32(hash + 4, s[1]); + WriteBE32(hash + 8, s[2]); + WriteBE32(hash + 12, s[3]); + WriteBE32(hash + 16, s[4]); } -CSHA1& CSHA1::Reset() { +CSHA1& CSHA1::Reset() +{ bytes = 0; sha1::Initialize(s); return *this; diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h index b16f2c88ce..68bd7ced9f 100644 --- a/src/crypto/sha1.h +++ b/src/crypto/sha1.h @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SHA1_H @@ -9,7 +9,8 @@ #include <stdlib.h> /** A hasher class for SHA1. */ -class CSHA1 { +class CSHA1 +{ private: uint32_t s[5]; unsigned char buf[64]; @@ -19,9 +20,9 @@ public: static const size_t OUTPUT_SIZE = 20; CSHA1(); - CSHA1& Write(const unsigned char *data, size_t len); + CSHA1& Write(const unsigned char* data, size_t len); void Finalize(unsigned char hash[OUTPUT_SIZE]); CSHA1& Reset(); }; -#endif +#endif // BITCOIN_SHA1_H diff --git a/src/crypto/sha2.cpp b/src/crypto/sha2.cpp index 72f191afcd..613aac2d71 100644 --- a/src/crypto/sha2.cpp +++ b/src/crypto/sha2.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "crypto/sha2.h" @@ -9,11 +9,11 @@ #include <string.h> // Internal implementation code. -namespace { - +namespace +{ /// Internal SHA-256 implementation. -namespace sha256 { - +namespace sha256 +{ uint32_t inline Ch(uint32_t x, uint32_t y, uint32_t z) { return z ^ (x & (y ^ z)); } uint32_t inline Maj(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (z & (x | y)); } uint32_t inline Sigma0(uint32_t x) { return (x >> 2 | x << 30) ^ (x >> 13 | x << 19) ^ (x >> 22 | x << 10); } @@ -22,9 +22,8 @@ uint32_t inline sigma0(uint32_t x) { return (x >> 7 | x << 25) ^ (x >> 18 | x << uint32_t inline sigma1(uint32_t x) { return (x >> 17 | x << 15) ^ (x >> 19 | x << 13) ^ (x >> 10); } /** One round of SHA-256. */ -void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t &d, - uint32_t e, uint32_t f, uint32_t g, uint32_t &h, - uint32_t k, uint32_t w) { +void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t& d, uint32_t e, uint32_t f, uint32_t g, uint32_t& h, uint32_t k, uint32_t w) +{ uint32_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w; uint32_t t2 = Sigma0(a) + Maj(a, b, c); d += t1; @@ -32,7 +31,8 @@ void inline Round(uint32_t a, uint32_t b, uint32_t c, uint32_t &d, } /** Initialize SHA-256 state. */ -void inline Initialize(uint32_t *s) { +void inline Initialize(uint32_t* s) +{ s[0] = 0x6a09e667ul; s[1] = 0xbb67ae85ul; s[2] = 0x3c6ef372ul; @@ -44,20 +44,21 @@ void inline Initialize(uint32_t *s) { } /** Perform one SHA-256 transformation, processing a 64-byte chunk. */ -void Transform(uint32_t *s, const unsigned char *chunk) { +void Transform(uint32_t* s, const unsigned char* chunk) +{ uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0)); - Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4)); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8)); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12)); - Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16)); - Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20)); - Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24)); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28)); - Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32)); - Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36)); + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = ReadBE32(chunk + 0)); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = ReadBE32(chunk + 4)); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = ReadBE32(chunk + 8)); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = ReadBE32(chunk + 12)); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = ReadBE32(chunk + 16)); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = ReadBE32(chunk + 20)); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = ReadBE32(chunk + 24)); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = ReadBE32(chunk + 28)); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = ReadBE32(chunk + 32)); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = ReadBE32(chunk + 36)); Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = ReadBE32(chunk + 40)); Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = ReadBE32(chunk + 44)); Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = ReadBE32(chunk + 48)); @@ -65,56 +66,56 @@ void Transform(uint32_t *s, const unsigned char *chunk) { Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = ReadBE32(chunk + 56)); Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = ReadBE32(chunk + 60)); - Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0( w0)); - - Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0( w0)); - - Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0( w0)); + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); s[0] += a; s[1] += b; @@ -126,11 +127,11 @@ void Transform(uint32_t *s, const unsigned char *chunk) { s[7] += h; } -} // namespace sha256 +} // namespace sha256 /// Internal SHA-512 implementation. -namespace sha512 { - +namespace sha512 +{ uint64_t inline Ch(uint64_t x, uint64_t y, uint64_t z) { return z ^ (x & (y ^ z)); } uint64_t inline Maj(uint64_t x, uint64_t y, uint64_t z) { return (x & y) | (z & (x | y)); } uint64_t inline Sigma0(uint64_t x) { return (x >> 28 | x << 36) ^ (x >> 34 | x << 30) ^ (x >> 39 | x << 25); } @@ -139,9 +140,8 @@ uint64_t inline sigma0(uint64_t x) { return (x >> 1 | x << 63) ^ (x >> 8 | x << uint64_t inline sigma1(uint64_t x) { return (x >> 19 | x << 45) ^ (x >> 61 | x << 3) ^ (x >> 6); } /** One round of SHA-512. */ -void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t &d, - uint64_t e, uint64_t f, uint64_t g, uint64_t &h, - uint64_t k, uint64_t w) { +void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t& d, uint64_t e, uint64_t f, uint64_t g, uint64_t& h, uint64_t k, uint64_t w) +{ uint64_t t1 = h + Sigma1(e) + Ch(e, f, g) + k + w; uint64_t t2 = Sigma0(a) + Maj(a, b, c); d += t1; @@ -149,7 +149,8 @@ void inline Round(uint64_t a, uint64_t b, uint64_t c, uint64_t &d, } /** Initialize SHA-256 state. */ -void inline Initialize(uint64_t *s) { +void inline Initialize(uint64_t* s) +{ s[0] = 0x6a09e667f3bcc908ull; s[1] = 0xbb67ae8584caa73bull; s[2] = 0x3c6ef372fe94f82bull; @@ -161,20 +162,21 @@ void inline Initialize(uint64_t *s) { } /** Perform one SHA-512 transformation, processing a 128-byte chunk. */ -void Transform(uint64_t *s, const unsigned char *chunk) { +void Transform(uint64_t* s, const unsigned char* chunk) +{ uint64_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; uint64_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; - Round(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22ull, w0 = ReadBE64(chunk + 0)); - Round(h, a, b, c, d, e, f, g, 0x7137449123ef65cdull, w1 = ReadBE64(chunk + 8)); - Round(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2full, w2 = ReadBE64(chunk + 16)); - Round(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbcull, w3 = ReadBE64(chunk + 24)); - Round(e, f, g, h, a, b, c, d, 0x3956c25bf348b538ull, w4 = ReadBE64(chunk + 32)); - Round(d, e, f, g, h, a, b, c, 0x59f111f1b605d019ull, w5 = ReadBE64(chunk + 40)); - Round(c, d, e, f, g, h, a, b, 0x923f82a4af194f9bull, w6 = ReadBE64(chunk + 48)); - Round(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118ull, w7 = ReadBE64(chunk + 56)); - Round(a, b, c, d, e, f, g, h, 0xd807aa98a3030242ull, w8 = ReadBE64(chunk + 64)); - Round(h, a, b, c, d, e, f, g, 0x12835b0145706fbeull, w9 = ReadBE64(chunk + 72)); + Round(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22ull, w0 = ReadBE64(chunk + 0)); + Round(h, a, b, c, d, e, f, g, 0x7137449123ef65cdull, w1 = ReadBE64(chunk + 8)); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2full, w2 = ReadBE64(chunk + 16)); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbcull, w3 = ReadBE64(chunk + 24)); + Round(e, f, g, h, a, b, c, d, 0x3956c25bf348b538ull, w4 = ReadBE64(chunk + 32)); + Round(d, e, f, g, h, a, b, c, 0x59f111f1b605d019ull, w5 = ReadBE64(chunk + 40)); + Round(c, d, e, f, g, h, a, b, 0x923f82a4af194f9bull, w6 = ReadBE64(chunk + 48)); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118ull, w7 = ReadBE64(chunk + 56)); + Round(a, b, c, d, e, f, g, h, 0xd807aa98a3030242ull, w8 = ReadBE64(chunk + 64)); + Round(h, a, b, c, d, e, f, g, 0x12835b0145706fbeull, w9 = ReadBE64(chunk + 72)); Round(g, h, a, b, c, d, e, f, 0x243185be4ee4b28cull, w10 = ReadBE64(chunk + 80)); Round(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2ull, w11 = ReadBE64(chunk + 88)); Round(e, f, g, h, a, b, c, d, 0x72be5d74f27b896full, w12 = ReadBE64(chunk + 96)); @@ -182,73 +184,73 @@ void Transform(uint64_t *s, const unsigned char *chunk) { Round(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235ull, w14 = ReadBE64(chunk + 112)); Round(b, c, d, e, f, g, h, a, 0xc19bf174cf692694ull, w15 = ReadBE64(chunk + 120)); - Round(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65ull, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275ull, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483ull, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x76f988da831153b5ull, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0x983e5152ee66dfabull, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0xa831c66d2db43210ull, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xb00327c898fb213full, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4ull, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0( w0)); - - Round(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aedull, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x53380d139d95b3dfull, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x650a73548baf63deull, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8ull, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6ull, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x92722c851482353bull, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364ull, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0xa81a664bbc423001ull, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791ull, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0xc76c51a30654be30ull, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0( w0)); - - Round(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99ull, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8ull, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63ull, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acbull, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373ull, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fcull, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0x78a5636f43172f60ull, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72ull, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x8cc702081a6439ecull, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0( w0)); - - Round(a, b, c, d, e, f, g, h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0( w1)); - Round(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0( w2)); - Round(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1eull, w2 += sigma1( w0) + w11 + sigma0( w3)); - Round(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178ull, w3 += sigma1( w1) + w12 + sigma0( w4)); - Round(e, f, g, h, a, b, c, d, 0x06f067aa72176fbaull, w4 += sigma1( w2) + w13 + sigma0( w5)); - Round(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6ull, w5 += sigma1( w3) + w14 + sigma0( w6)); - Round(c, d, e, f, g, h, a, b, 0x113f9804bef90daeull, w6 += sigma1( w4) + w15 + sigma0( w7)); - Round(b, c, d, e, f, g, h, a, 0x1b710b35131c471bull, w7 += sigma1( w5) + w0 + sigma0( w8)); - Round(a, b, c, d, e, f, g, h, 0x28db77f523047d84ull, w8 += sigma1( w6) + w1 + sigma0( w9)); - Round(h, a, b, c, d, e, f, g, 0x32caab7b40c72493ull, w9 += sigma1( w7) + w2 + sigma0(w10)); - Round(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebcull, w10 += sigma1( w8) + w3 + sigma0(w11)); - Round(f, g, h, a, b, c, d, e, 0x431d67c49c100d4cull, w11 += sigma1( w9) + w4 + sigma0(w12)); - Round(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13)); - Round(d, e, f, g, h, a, b, c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14)); - Round(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faecull, w14 += sigma1(w12) + w7 + sigma0(w15)); - Round(b, c, d, e, f, g, h, a, 0x6c44198c4a475817ull, w15 += sigma1(w13) + w8 + sigma0( w0)); + Round(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2ull, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3ull, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5ull, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65ull, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275ull, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483ull, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4ull, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da831153b5ull, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152ee66dfabull, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d2db43210ull, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c898fb213full, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4ull, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2ull, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147930aa725ull, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351e003826full, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x142929670a0e6e70ull, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffcull, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926ull, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aedull, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d139d95b3dfull, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a73548baf63deull, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8ull, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6ull, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c851482353bull, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364ull, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664bbc423001ull, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791ull, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a30654be30ull, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218ull, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd69906245565a910ull, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e35855771202aull, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8ull, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8ull, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c085141ab53ull, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99ull, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8ull, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63ull, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acbull, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373ull, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3ull, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fcull, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f43172f60ull, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72ull, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc702081a6439ecull, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa23631e28ull, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9ull, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915ull, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2e372532bull, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0xca273eceea26619cull, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207ull, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1eull, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178ull, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x06f067aa72176fbaull, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6ull, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x113f9804bef90daeull, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x1b710b35131c471bull, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x28db77f523047d84ull, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x32caab7b40c72493ull, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebcull, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x431d67c49c100d4cull, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6ull, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0x597f299cfc657e2aull, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faecull, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x6c44198c4a475817ull, w15 += sigma1(w13) + w8 + sigma0(w0)); s[0] += a; s[1] += b; @@ -260,19 +262,21 @@ void Transform(uint64_t *s, const unsigned char *chunk) { s[7] += h; } -} // namespace sha512 +} // namespace sha512 -} // namespace +} // namespace ////// SHA-256 -CSHA256::CSHA256() : bytes(0) { +CSHA256::CSHA256() : bytes(0) +{ sha256::Initialize(s); } -CSHA256& CSHA256::Write(const unsigned char *data, size_t len) { - const unsigned char *end = data + len; +CSHA256& CSHA256::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; size_t bufsize = bytes % 64; if (bufsize && bufsize + len >= 64) { // Fill the buffer, and process it. @@ -296,23 +300,25 @@ CSHA256& CSHA256::Write(const unsigned char *data, size_t len) { return *this; } -void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE]) { +void CSHA256::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ static const unsigned char pad[64] = {0x80}; unsigned char sizedesc[8]; WriteBE64(sizedesc, bytes << 3); Write(pad, 1 + ((119 - (bytes % 64)) % 64)); Write(sizedesc, 8); WriteBE32(hash, s[0]); - WriteBE32(hash+4, s[1]); - WriteBE32(hash+8, s[2]); - WriteBE32(hash+12, s[3]); - WriteBE32(hash+16, s[4]); - WriteBE32(hash+20, s[5]); - WriteBE32(hash+24, s[6]); - WriteBE32(hash+28, s[7]); + WriteBE32(hash + 4, s[1]); + WriteBE32(hash + 8, s[2]); + WriteBE32(hash + 12, s[3]); + WriteBE32(hash + 16, s[4]); + WriteBE32(hash + 20, s[5]); + WriteBE32(hash + 24, s[6]); + WriteBE32(hash + 28, s[7]); } -CSHA256& CSHA256::Reset() { +CSHA256& CSHA256::Reset() +{ bytes = 0; sha256::Initialize(s); return *this; @@ -320,12 +326,14 @@ CSHA256& CSHA256::Reset() { ////// SHA-512 -CSHA512::CSHA512() : bytes(0) { +CSHA512::CSHA512() : bytes(0) +{ sha512::Initialize(s); } -CSHA512& CSHA512::Write(const unsigned char *data, size_t len) { - const unsigned char *end = data + len; +CSHA512& CSHA512::Write(const unsigned char* data, size_t len) +{ + const unsigned char* end = data + len; size_t bufsize = bytes % 128; if (bufsize && bufsize + len >= 128) { // Fill the buffer, and process it. @@ -349,23 +357,25 @@ CSHA512& CSHA512::Write(const unsigned char *data, size_t len) { return *this; } -void CSHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) { +void CSHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ static const unsigned char pad[128] = {0x80}; unsigned char sizedesc[16] = {0x00}; - WriteBE64(sizedesc+8, bytes << 3); + WriteBE64(sizedesc + 8, bytes << 3); Write(pad, 1 + ((239 - (bytes % 128)) % 128)); Write(sizedesc, 16); WriteBE64(hash, s[0]); - WriteBE64(hash+8, s[1]); - WriteBE64(hash+16, s[2]); - WriteBE64(hash+24, s[3]); - WriteBE64(hash+32, s[4]); - WriteBE64(hash+40, s[5]); - WriteBE64(hash+48, s[6]); - WriteBE64(hash+56, s[7]); + WriteBE64(hash + 8, s[1]); + WriteBE64(hash + 16, s[2]); + WriteBE64(hash + 24, s[3]); + WriteBE64(hash + 32, s[4]); + WriteBE64(hash + 40, s[5]); + WriteBE64(hash + 48, s[6]); + WriteBE64(hash + 56, s[7]); } -CSHA512& CSHA512::Reset() { +CSHA512& CSHA512::Reset() +{ bytes = 0; sha512::Initialize(s); return *this; @@ -373,7 +383,8 @@ CSHA512& CSHA512::Reset() { ////// HMAC-SHA-512 -CHMAC_SHA512::CHMAC_SHA512(const unsigned char *key, size_t keylen) { +CHMAC_SHA512::CHMAC_SHA512(const unsigned char* key, size_t keylen) +{ unsigned char rkey[128]; if (keylen <= 128) { memcpy(rkey, key, keylen); @@ -383,16 +394,17 @@ CHMAC_SHA512::CHMAC_SHA512(const unsigned char *key, size_t keylen) { memset(rkey + 64, 0, 64); } - for (int n=0; n<128; n++) + for (int n = 0; n < 128; n++) rkey[n] ^= 0x5c; outer.Write(rkey, 128); - for (int n=0; n<128; n++) + for (int n = 0; n < 128; n++) rkey[n] ^= 0x5c ^ 0x36; inner.Write(rkey, 128); } -void CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) { +void CHMAC_SHA512::Finalize(unsigned char hash[OUTPUT_SIZE]) +{ unsigned char temp[64]; inner.Finalize(temp); outer.Write(temp, 64).Finalize(hash); diff --git a/src/crypto/sha2.h b/src/crypto/sha2.h index 088d5e194c..a6cbe58554 100644 --- a/src/crypto/sha2.h +++ b/src/crypto/sha2.h @@ -1,5 +1,5 @@ // Copyright (c) 2014 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_SHA2_H @@ -9,7 +9,8 @@ #include <stdlib.h> /** A hasher class for SHA-256. */ -class CSHA256 { +class CSHA256 +{ private: uint32_t s[8]; unsigned char buf[64]; @@ -19,13 +20,14 @@ public: static const size_t OUTPUT_SIZE = 32; CSHA256(); - CSHA256& Write(const unsigned char *data, size_t len); + CSHA256& Write(const unsigned char* data, size_t len); void Finalize(unsigned char hash[OUTPUT_SIZE]); CSHA256& Reset(); }; /** A hasher class for SHA-512. */ -class CSHA512 { +class CSHA512 +{ private: uint64_t s[8]; unsigned char buf[128]; @@ -35,13 +37,14 @@ public: static const size_t OUTPUT_SIZE = 64; CSHA512(); - CSHA512& Write(const unsigned char *data, size_t len); + CSHA512& Write(const unsigned char* data, size_t len); void Finalize(unsigned char hash[OUTPUT_SIZE]); CSHA512& Reset(); }; /** A hasher class for HMAC-SHA-512. */ -class CHMAC_SHA512 { +class CHMAC_SHA512 +{ private: CSHA512 outer; CSHA512 inner; @@ -49,12 +52,13 @@ private: public: static const size_t OUTPUT_SIZE = 64; - CHMAC_SHA512(const unsigned char *key, size_t keylen); - CHMAC_SHA512& Write(const unsigned char *data, size_t len) { + CHMAC_SHA512(const unsigned char* key, size_t keylen); + CHMAC_SHA512& Write(const unsigned char* data, size_t len) + { inner.Write(data, len); return *this; } void Finalize(unsigned char hash[OUTPUT_SIZE]); }; -#endif +#endif // BITCOIN_SHA2_H diff --git a/src/hash.cpp b/src/hash.cpp index 4ce4da4c30..218607a6fd 100644 --- a/src/hash.cpp +++ b/src/hash.cpp @@ -9,45 +9,48 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char { // The following is MurmurHash3 (x86_32), see http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp uint32_t h1 = nHashSeed; - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; + if (vDataToHash.size() > 0) + { + const uint32_t c1 = 0xcc9e2d51; + const uint32_t c2 = 0x1b873593; - const int nblocks = vDataToHash.size() / 4; + const int nblocks = vDataToHash.size() / 4; - //---------- - // body - const uint32_t* blocks = (const uint32_t*)(&vDataToHash[0] + nblocks * 4); + //---------- + // body + const uint32_t* blocks = (const uint32_t*)(&vDataToHash[0] + nblocks * 4); - for (int i = -nblocks; i; i++) { - uint32_t k1 = blocks[i]; + for (int i = -nblocks; i; i++) { + uint32_t k1 = blocks[i]; - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; - h1 ^= k1; - h1 = ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } + h1 ^= k1; + h1 = ROTL32(h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } - //---------- - // tail - const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4); - - uint32_t k1 = 0; - - switch (vDataToHash.size() & 3) { - case 3: - k1 ^= tail[2] << 16; - case 2: - k1 ^= tail[1] << 8; - case 1: - k1 ^= tail[0]; - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; + //---------- + // tail + const uint8_t* tail = (const uint8_t*)(&vDataToHash[0] + nblocks * 4); + + uint32_t k1 = 0; + + switch (vDataToHash.size() & 3) { + case 3: + k1 ^= tail[2] << 16; + case 2: + k1 ^= tail[1] << 8; + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32(k1, 15); + k1 *= c2; + h1 ^= k1; + }; + } //---------- // finalization diff --git a/src/init.cpp b/src/init.cpp index 67f53e044c..8772be5539 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -45,8 +45,9 @@ using namespace boost; using namespace std; #ifdef ENABLE_WALLET -CWallet* pwalletMain; +CWallet* pwalletMain = NULL; #endif +bool fFeeEstimatesInitialized = false; #ifdef WIN32 // Win32 LevelDB doesn't use filedescriptors, and the ones used for @@ -109,7 +110,7 @@ bool ShutdownRequested() return fRequestShutdown; } -static CCoinsViewDB *pcoinsdbview; +static CCoinsViewDB *pcoinsdbview = NULL; void Shutdown() { @@ -119,6 +120,10 @@ void Shutdown() if (!lockShutdown) return; + /// Note: Shutdown() must be able to handle cases in which AppInit2() failed part of the way, + /// for example if the data directory was found to be locked. + /// Be sure that anything that writes files or flushes caches only does this if the respective + /// module was initialized. RenameThread("bitcoin-shutoff"); mempool.AddTransactionsUpdated(1); StopRPCThreads(); @@ -130,6 +135,7 @@ void Shutdown() StopNode(); UnregisterNodeSignals(GetNodeSignals()); + if (fFeeEstimatesInitialized) { boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_fileout(fopen(est_path.string().c_str(), "wb"), SER_DISK, CLIENT_VERSION); @@ -137,6 +143,7 @@ void Shutdown() mempool.WriteFeeEstimates(est_fileout); else LogPrintf("%s: Failed to write fee estimates to %s\n", __func__, est_path.string()); + fFeeEstimatesInitialized = false; } { @@ -160,11 +167,13 @@ void Shutdown() if (pwalletMain) bitdb.Flush(true); #endif +#ifndef WIN32 boost::filesystem::remove(GetPidFile()); +#endif UnregisterAllWallets(); #ifdef ENABLE_WALLET - if (pwalletMain) - delete pwalletMain; + delete pwalletMain; + pwalletMain = NULL; #endif LogPrintf("%s: done\n", __func__); } @@ -228,12 +237,14 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -maxorphanblocks=<n> " + strprintf(_("Keep at most <n> unconnectable blocks in memory (default: %u)"), DEFAULT_MAX_ORPHAN_BLOCKS) + "\n"; strUsage += " -maxorphantx=<n> " + strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS) + "\n"; strUsage += " -par=<n> " + strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS) + "\n"; +#ifndef WIN32 strUsage += " -pid=<file> " + _("Specify pid file (default: bitcoind.pid)") + "\n"; +#endif strUsage += " -reindex " + _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup") + "\n"; #if !defined(WIN32) strUsage += " -sysperms " + _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)") + "\n"; #endif - strUsage += " -txindex " + _("Maintain a full transaction index (default: 0)") + "\n"; + strUsage += " -txindex " + _("Maintain a full transaction index, used by the getrawtransaction rpc call (default: 0)") + "\n"; strUsage += "\n" + _("Connection options:") + "\n"; strUsage += " -addnode=<ip> " + _("Add a node to connect to and attempt to keep the connection open") + "\n"; @@ -256,7 +267,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -port=<port> " + _("Listen for connections on <port> (default: 8333 or testnet: 18333)") + "\n"; strUsage += " -proxy=<ip:port> " + _("Connect through SOCKS5 proxy") + "\n"; strUsage += " -seednode=<ip> " + _("Connect to a node to retrieve peer addresses, and disconnect") + "\n"; - strUsage += " -timeout=<n> " + _("Specify connection timeout in milliseconds (default: 5000)") + "\n"; + strUsage += " -timeout=<n> " + strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT) + "\n"; #ifdef USE_UPNP #if USE_UPNP strUsage += " -upnp " + _("Use UPnP to map the listening port (default: 1 when listening)") + "\n"; @@ -276,7 +287,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += " -mintxfee=<amt> " + strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"), FormatMoney(CWallet::minTxFee.GetFeePerK())) + "\n"; strUsage += " -paytxfee=<amt> " + strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())) + "\n"; strUsage += " -rescan " + _("Rescan the block chain for missing wallet transactions") + " " + _("on startup") + "\n"; - strUsage += " -respendnotify=<cmd> " + _("Execute command when a network tx respends wallet tx input (%s=respend TxID, %t=wallet TxID)") + "\n"; strUsage += " -salvagewallet " + _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup") + "\n"; strUsage += " -spendzeroconfchange " + _("Spend unconfirmed change when sending transactions (default: 1)") + "\n"; strUsage += " -txconfirmtarget=<n> " + _("If paytxfee is not set, include enough fee so transactions are confirmed on average within n blocks (default: 1)") + "\n"; @@ -637,12 +647,9 @@ bool AppInit2(boost::thread_group& threadGroup) bool fDisableWallet = GetBoolArg("-disablewallet", false); #endif - if (mapArgs.count("-timeout")) - { - int nNewTimeout = GetArg("-timeout", 5000); - if (nNewTimeout > 0 && nNewTimeout < 600000) - nConnectTimeout = nNewTimeout; - } + nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); + if (nConnectTimeout <= 0) + nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; // Continue to put "/P2SH/" in the coinbase to monitor // BIP16 support. @@ -658,7 +665,7 @@ bool AppInit2(boost::thread_group& threadGroup) // cost to you of processing a transaction. if (mapArgs.count("-minrelaytxfee")) { - int64_t n = 0; + CAmount n = 0; if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0) ::minRelayTxFee = CFeeRate(n); else @@ -668,7 +675,7 @@ bool AppInit2(boost::thread_group& threadGroup) #ifdef ENABLE_WALLET if (mapArgs.count("-mintxfee")) { - int64_t n = 0; + CAmount n = 0; if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0) CWallet::minTxFee = CFeeRate(n); else @@ -676,7 +683,7 @@ bool AppInit2(boost::thread_group& threadGroup) } if (mapArgs.count("-paytxfee")) { - int64_t nFeePerK = 0; + CAmount nFeePerK = 0; if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK)) return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"])); if (nFeePerK > nHighTransactionFeeWarning) @@ -697,6 +704,7 @@ bool AppInit2(boost::thread_group& threadGroup) fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0; // ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log + // Sanity check if (!InitSanityCheck()) return InitError(_("Initialization sanity check failed. Bitcoin Core is shutting down.")); @@ -714,7 +722,9 @@ bool AppInit2(boost::thread_group& threadGroup) static boost::interprocess::file_lock lock(pathLockFile.string().c_str()); if (!lock.try_lock()) return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running."), strDataDir)); - +#ifndef WIN32 + CreatePidFile(GetPidFile(), getpid()); +#endif if (GetBoolArg("-shrinkdebugfile", !fDebug)) ShrinkDebugFile(); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); @@ -952,7 +962,7 @@ bool AppInit2(boost::thread_group& threadGroup) pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex); - pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); if (fReindex) pblocktree->WriteReindexing(true); @@ -1052,10 +1062,11 @@ bool AppInit2(boost::thread_group& threadGroup) } boost::filesystem::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; - CAutoFile est_filein = CAutoFile(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); + CAutoFile est_filein(fopen(est_path.string().c_str(), "rb"), SER_DISK, CLIENT_VERSION); // Allowed to fail as this file IS missing on first startup. if (est_filein) mempool.ReadFeeEstimates(est_filein); + fFeeEstimatesInitialized = true; // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET @@ -1153,7 +1164,7 @@ bool AppInit2(boost::thread_group& threadGroup) CWalletDB walletdb(strWalletFile); CBlockLocator locator; if (walletdb.ReadBestBlock(locator)) - pindexRescan = chainActive.FindFork(locator); + pindexRescan = FindForkInGlobalIndex(chainActive, locator); else pindexRescan = chainActive.Genesis(); } @@ -1212,22 +1223,7 @@ bool AppInit2(boost::thread_group& threadGroup) } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - // ********************************************************* Step 10: load peers - - uiInterface.InitMessage(_("Loading addresses...")); - - nStart = GetTimeMillis(); - - { - CAddrDB adb; - if (!adb.Read(addrman)) - LogPrintf("Invalid or missing peers.dat; recreating\n"); - } - - LogPrintf("Loaded %i addresses from peers.dat %dms\n", - addrman.size(), GetTimeMillis() - nStart); - - // ********************************************************* Step 11: start node + // ********************************************************* Step 10: start node if (!CheckDiskSpace()) return false; @@ -1256,7 +1252,7 @@ bool AppInit2(boost::thread_group& threadGroup) GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", -1)); #endif - // ********************************************************* Step 12: finished + // ********************************************************* Step 11: finished uiInterface.InitMessage(_("Done loading")); diff --git a/src/key.cpp b/src/key.cpp index 8ed787654a..079e2c6540 100644 --- a/src/key.cpp +++ b/src/key.cpp @@ -179,19 +179,17 @@ public: BN_clear_free(&bn); } - void GetPrivKey(CPrivKey &privkey, bool fCompressed) { + int GetPrivKeySize(bool fCompressed) { EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); - int nSize = i2d_ECPrivateKey(pkey, NULL); - assert(nSize); - privkey.resize(nSize); - unsigned char* pbegin = &privkey[0]; - int nSize2 = i2d_ECPrivateKey(pkey, &pbegin); - assert(nSize == nSize2); + return i2d_ECPrivateKey(pkey, NULL); + } + int GetPrivKey(unsigned char* privkey, bool fCompressed) { + EC_KEY_set_conv_form(pkey, fCompressed ? POINT_CONVERSION_COMPRESSED : POINT_CONVERSION_UNCOMPRESSED); + return i2d_ECPrivateKey(pkey, &privkey); } - bool SetPrivKey(const CPrivKey &privkey, bool fSkipCheck=false) { - const unsigned char* pbegin = &privkey[0]; - if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) { + bool SetPrivKey(const unsigned char* privkey, size_t size, bool fSkipCheck=false) { + if (d2i_ECPrivateKey(&pkey, &privkey, size)) { if(fSkipCheck) return true; @@ -220,7 +218,7 @@ public: return o2i_ECPublicKey(&pkey, &pbegin, pubkey.size()) != NULL; } - bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) { + bool Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) { vchSig.clear(); ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); if (sig == NULL) @@ -232,7 +230,7 @@ public: BIGNUM *halforder = BN_CTX_get(ctx); EC_GROUP_get_order(group, order, ctx); BN_rshift1(halforder, order); - if (BN_cmp(sig->s, halforder) > 0) { + if (lowS && BN_cmp(sig->s, halforder) > 0) { // enforce low S values, by negating the value (modulo the order) if above order/2. BN_sub(sig->s, order, sig->s); } @@ -424,7 +422,7 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { return false; #else CECKey key; - if (!key.SetPrivKey(privkey)) + if (!key.SetPrivKey(&privkey[0], privkey.size())) return false; key.GetSecretBytes(vch); #endif @@ -436,16 +434,21 @@ bool CKey::SetPrivKey(const CPrivKey &privkey, bool fCompressedIn) { CPrivKey CKey::GetPrivKey() const { assert(fValid); CPrivKey privkey; + int privkeylen, ret; #ifdef USE_SECP256K1 privkey.resize(279); - int privkeylen = 279; - int ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); + privkeylen = 279; + ret = secp256k1_ecdsa_privkey_export(begin(), (unsigned char*)&privkey[0], &privkeylen, fCompressed); assert(ret); privkey.resize(privkeylen); #else CECKey key; key.SetSecretBytes(vch); - key.GetPrivKey(privkey, fCompressed); + privkeylen = key.GetPrivKeySize(fCompressed); + assert(privkeylen); + privkey.resize(privkeylen); + ret = key.GetPrivKey(&privkey[0], fCompressed); + assert(ret == (int)privkey.size()); #endif return privkey; } @@ -467,7 +470,7 @@ CPubKey CKey::GetPubKey() const { return pubkey; } -bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const { +bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig, bool lowS) const { if (!fValid) return false; #ifdef USE_SECP256K1 @@ -484,7 +487,7 @@ bool CKey::Sign(const uint256 &hash, std::vector<unsigned char>& vchSig) const { #else CECKey key; key.SetSecretBytes(vch); - return key.Sign(hash, vchSig); + return key.Sign(hash, vchSig, lowS); #endif } @@ -517,7 +520,7 @@ bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) { return false; #else CECKey key; - if (!key.SetPrivKey(privkey, fSkipCheck)) + if (!key.SetPrivKey(&privkey[0], privkey.size(), fSkipCheck)) return false; key.GetSecretBytes(vch); #endif @@ -276,7 +276,7 @@ public: CPubKey GetPubKey() const; // Create a DER-serialized signature. - bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig) const; + bool Sign(const uint256& hash, std::vector<unsigned char>& vchSig, bool lowS = true) const; // Create a compact signature (65 bytes), which allows reconstructing the used public key. // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. diff --git a/src/keystore.cpp b/src/keystore.cpp index 98bc0e9e28..755defa26d 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -67,6 +67,13 @@ bool CBasicKeyStore::AddWatchOnly(const CScript &dest) return true; } +bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest) +{ + LOCK(cs_KeyStore); + setWatchOnly.erase(dest); + return true; +} + bool CBasicKeyStore::HaveWatchOnly(const CScript &dest) const { LOCK(cs_KeyStore); diff --git a/src/keystore.h b/src/keystore.h index 3b49e282d9..d3478f7672 100644 --- a/src/keystore.h +++ b/src/keystore.h @@ -40,6 +40,7 @@ public: // Support for Watch-only addresses virtual bool AddWatchOnly(const CScript &dest) =0; + virtual bool RemoveWatchOnly(const CScript &dest) =0; virtual bool HaveWatchOnly(const CScript &dest) const =0; virtual bool HaveWatchOnly() const =0; }; @@ -98,6 +99,7 @@ public: virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const; virtual bool AddWatchOnly(const CScript &dest); + virtual bool RemoveWatchOnly(const CScript &dest); virtual bool HaveWatchOnly(const CScript &dest) const; virtual bool HaveWatchOnly() const; }; diff --git a/src/limitedmap.h b/src/limitedmap.h index 4bc8d9e5aa..03727d7c42 100644 --- a/src/limitedmap.h +++ b/src/limitedmap.h @@ -1,11 +1,11 @@ -// Copyright (c) 2012 The Bitcoin developers -// Distributed under the MIT/X11 software license, see the accompanying +// Copyright (c) 2012-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_LIMITEDMAP_H #define BITCOIN_LIMITEDMAP_H -#include <assert.h> // TODO: remove +#include <assert.h> #include <map> /** STL-like map container that only keeps the N elements with the highest value. */ @@ -59,12 +59,11 @@ public: return; } // Shouldn't ever get here - assert(0); //TODO remove me - map.erase(itTarget); + assert(0); } void update(const_iterator itIn, const mapped_type& v) { - //TODO: When we switch to C++11, use map.erase(itIn, itIn) to get the non-const iterator + // TODO: When we switch to C++11, use map.erase(itIn, itIn) to get the non-const iterator. iterator itTarget = map.find(itIn->first); if (itTarget == map.end()) return; @@ -77,9 +76,7 @@ public: return; } // Shouldn't ever get here - assert(0); //TODO remove me - itTarget->second = v; - rmap.insert(make_pair(v, itTarget)); + assert(0); } size_type max_size() const { return nMaxSize; } size_type max_size(size_type s) diff --git a/src/main.cpp b/src/main.cpp index 15c3916a6f..fc8167e40e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,7 @@ #include "txmempool.h" #include "ui_interface.h" #include "util.h" +#include "utilmoneystr.h" #include <sstream> @@ -25,8 +26,8 @@ #include <boost/filesystem/fstream.hpp> #include <boost/thread.hpp> -using namespace std; using namespace boost; +using namespace std; #if defined(NDEBUG) # error "Bitcoin cannot be compiled without assertions." @@ -391,72 +392,19 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals) nodeSignals.FinalizeNode.disconnect(&FinalizeNode); } -////////////////////////////////////////////////////////////////////////////// -// -// CChain implementation -// - -CBlockIndex *CChain::SetTip(CBlockIndex *pindex) { - if (pindex == NULL) { - vChain.clear(); - return NULL; - } - vChain.resize(pindex->nHeight + 1); - while (pindex && vChain[pindex->nHeight] != pindex) { - vChain[pindex->nHeight] = pindex; - pindex = pindex->pprev; - } - return pindex; -} - -CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { - int nStep = 1; - std::vector<uint256> vHave; - vHave.reserve(32); - - if (!pindex) - pindex = Tip(); - while (pindex) { - vHave.push_back(pindex->GetBlockHash()); - // Stop when we have added the genesis block. - if (pindex->nHeight == 0) - break; - // Exponentially larger steps back, plus the genesis block. - int nHeight = std::max(pindex->nHeight - nStep, 0); - if (Contains(pindex)) { - // Use O(1) CChain index if possible. - pindex = (*this)[nHeight]; - } else { - // Otherwise, use O(log n) skiplist. - pindex = pindex->GetAncestor(nHeight); - } - if (vHave.size() > 10) - nStep *= 2; - } - - return CBlockLocator(vHave); -} - -CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const { +CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator) +{ // Find the first block the caller has in the main chain BOOST_FOREACH(const uint256& hash, locator.vHave) { BlockMap::iterator mi = mapBlockIndex.find(hash); if (mi != mapBlockIndex.end()) { CBlockIndex* pindex = (*mi).second; - if (Contains(pindex)) + if (chain.Contains(pindex)) return pindex; } } - return Genesis(); -} - -const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { - if (pindex->nHeight > Height()) - pindex = pindex->GetAncestor(Height()); - while (pindex && !Contains(pindex)) - pindex = pindex->pprev; - return pindex; + return chain.Genesis(); } CCoinsViewCache *pcoinsTip = NULL; @@ -697,7 +645,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // IsStandard() will have already returned false // and this method isn't called. vector<vector<unsigned char> > stack; - if (!EvalScript(stack, tx.vin[i].scriptSig, tx, i, false)) + if (!EvalScript(stack, tx.vin[i].scriptSig, false, BaseSignatureChecker())) return false; if (whichType == TX_SCRIPTHASH) @@ -781,7 +729,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) REJECT_INVALID, "bad-txns-oversize"); // Check for negative or overflow output values - int64_t nValueOut = 0; + CAmount nValueOut = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { if (txout.nValue < 0) @@ -823,19 +771,19 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) return true; } -int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) +CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree) { { LOCK(mempool.cs); uint256 hash = tx.GetHash(); double dPriorityDelta = 0; - int64_t nFeeDelta = 0; + CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); if (dPriorityDelta > 0 || nFeeDelta > 0) return 0; } - int64_t nMinFee = ::minRelayTxFee.GetFee(nBytes); + CAmount nMinFee = ::minRelayTxFee.GetFee(nBytes); if (fAllowFree) { @@ -896,12 +844,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa { CCoinsView dummy; - CCoinsViewCache view(dummy); + CCoinsViewCache view(&dummy); - int64_t nValueIn = 0; + CAmount nValueIn = 0; { LOCK(pool.cs); - CCoinsViewMemPool viewMemPool(*pcoinsTip, pool); + CCoinsViewMemPool viewMemPool(pcoinsTip, pool); view.SetBackend(viewMemPool); // do we already have it? @@ -950,15 +898,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa hash.ToString(), nSigOps, MAX_TX_SIGOPS), REJECT_NONSTANDARD, "bad-txns-too-many-sigops"); - int64_t nValueOut = tx.GetValueOut(); - int64_t nFees = nValueIn-nValueOut; + CAmount nValueOut = tx.GetValueOut(); + CAmount nFees = nValueIn-nValueOut; double dPriority = view.GetPriority(tx, chainActive.Height()); CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height()); unsigned int nSize = entry.GetTxSize(); // Don't accept it if it can't get into a block - int64_t txMinFee = GetMinRelayFee(tx, nSize, true); + CAmount txMinFee = GetMinRelayFee(tx, nSize, true); if (fLimitFree && nFees < txMinFee) return state.DoS(0, error("AcceptToMemoryPool : not enough fees %s, %d < %d", hash.ToString(), nFees, txMinFee), @@ -995,7 +943,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check against previous transactions // This is done last to help prevent CPU exhaustion denial-of-service attacks. - if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS)) + if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true)) { return error("AcceptToMemoryPool: : ConnectInputs failed %s", hash.ToString()); } @@ -1082,7 +1030,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos) { // Open history file to append - CAutoFile fileout = CAutoFile(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); + CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) return error("WriteBlockToDisk : OpenBlockFile failed"); @@ -1110,7 +1058,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) block.SetNull(); // Open history file to read - CAutoFile filein = CAutoFile(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); + CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION); if (!filein) return error("ReadBlockFromDisk : OpenBlockFile failed"); @@ -1178,7 +1126,7 @@ void static PruneOrphanBlocks() mapOrphanBlocks.erase(hash); } -int64_t GetBlockValue(int nHeight, int64_t nFees) +CAmount GetBlockValue(int nHeight, const CAmount& nFees) { int64_t nSubsidy = 50 * COIN; int halvings = nHeight / Params().SubsidyHalvingInterval(); @@ -1230,14 +1178,9 @@ void CheckForkWarningConditions() { if (!fLargeWorkForkFound) { - std::string strCmd = GetArg("-alertnotify", ""); - if (!strCmd.empty()) - { - std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + - pindexBestForkBase->phashBlock->ToString() + std::string("'"); - boost::replace_all(strCmd, "%s", warning); - boost::thread t(runCommand, strCmd); // thread runs free - } + std::string warning = std::string("'Warning: Large-work fork detected, forking after block ") + + pindexBestForkBase->phashBlock->ToString() + std::string("'"); + CAlert::Notify(warning, true); } if (pindexBestForkTip) { @@ -1348,32 +1291,28 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight) { - bool ret; // mark inputs spent if (!tx.IsCoinBase()) { txundo.vprevout.reserve(tx.vin.size()); - for (unsigned int i = 0; i < tx.vin.size(); i++) { - const CTxIn &txin = tx.vin[i]; - CCoins &coins = inputs.GetCoins(txin.prevout.hash); + BOOST_FOREACH(const CTxIn &txin, tx.vin) { txundo.vprevout.push_back(CTxInUndo()); - ret = coins.Spend(txin.prevout, txundo.vprevout.back()); + bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back()); assert(ret); } } // add outputs - ret = inputs.SetCoins(tx.GetHash(), CCoins(tx, nHeight)); - assert(ret); + inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } bool CScriptCheck::operator()() const { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, *ptxTo, nIn, nFlags)) - return error("CScriptCheck() : %s VerifySignature failed", ptxTo->GetHash().ToString()); + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore))) + return error("CScriptCheck() : %s:%d VerifySignature failed", ptxTo->GetHash().ToString(), nIn); return true; } -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, std::vector<CScriptCheck> *pvChecks) +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks) { if (!tx.IsCoinBase()) { @@ -1389,8 +1328,8 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // This is also true for mempool checks. CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; int nSpendHeight = pindexPrev->nHeight + 1; - int64_t nValueIn = 0; - int64_t nFees = 0; + CAmount nValueIn = 0; + CAmount nFees = 0; for (unsigned int i = 0; i < tx.vin.size(); i++) { const COutPoint &prevout = tx.vin[i].prevout; @@ -1414,11 +1353,12 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi } if (nValueIn < tx.GetValueOut()) - return state.DoS(100, error("CheckInputs() : %s value in < value out", tx.GetHash().ToString()), + return state.DoS(100, error("CheckInputs() : %s value in (%s) < value out (%s)", + tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())), REJECT_INVALID, "bad-txns-in-belowout"); // Tally transaction fees - int64_t nTxFee = nValueIn - tx.GetValueOut(); + CAmount nTxFee = nValueIn - tx.GetValueOut(); if (nTxFee < 0) return state.DoS(100, error("CheckInputs() : %s nTxFee < 0", tx.GetHash().ToString()), REJECT_INVALID, "bad-txns-fee-negative"); @@ -1441,7 +1381,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi assert(coins); // Verify signature - CScriptCheck check(*coins, tx, i, flags); + CScriptCheck check(*coins, tx, i, flags, cacheStore); if (pvChecks) { pvChecks->push_back(CScriptCheck()); check.swap(pvChecks->back()); @@ -1454,7 +1394,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi // avoid splitting the network between upgraded and // non-upgraded nodes. CScriptCheck check(*coins, tx, i, - flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS); + flags & ~STANDARD_NOT_MANDATORY_VERIFY_FLAGS, cacheStore); if (check()) return state.Invalid(false, REJECT_NONSTANDARD, "non-mandatory-script-verify-flag"); } @@ -1504,21 +1444,23 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // exactly. Note that transactions with only provably unspendable outputs won't // have outputs available even in the block itself, so we handle that case // specially with outsEmpty. + { CCoins outsEmpty; - CCoins &outs = view.HaveCoins(hash) ? view.GetCoins(hash) : outsEmpty; - outs.ClearUnspendable(); + CCoinsModifier outs = view.ModifyCoins(hash); + outs->ClearUnspendable(); - CCoins outsBlock = CCoins(tx, pindex->nHeight); + CCoins outsBlock(tx, pindex->nHeight); // The CCoins serialization does not serialize negative numbers. // No network rules currently depend on the version here, so an inconsistency is harmless // but it must be corrected before txout nversion ever influences a network rule. if (outsBlock.nVersion < 0) - outs.nVersion = outsBlock.nVersion; - if (outs != outsBlock) + outs->nVersion = outsBlock.nVersion; + if (*outs != outsBlock) fClean = fClean && error("DisconnectBlock() : added transaction mismatch? database corrupted"); // remove outputs - outs = CCoins(); + outs->Clear(); + } // restore inputs if (i > 0) { // not coinbases @@ -1528,27 +1470,24 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex for (unsigned int j = tx.vin.size(); j-- > 0;) { const COutPoint &out = tx.vin[j].prevout; const CTxInUndo &undo = txundo.vprevout[j]; - CCoins coins; - view.GetCoins(out.hash, coins); // this can fail if the prevout was already entirely spent + CCoinsModifier coins = view.ModifyCoins(out.hash); if (undo.nHeight != 0) { // undo data contains height: this is the last output of the prevout tx being spent - if (!coins.IsPruned()) + if (!coins->IsPruned()) fClean = fClean && error("DisconnectBlock() : undo data overwriting existing transaction"); - coins = CCoins(); - coins.fCoinBase = undo.fCoinBase; - coins.nHeight = undo.nHeight; - coins.nVersion = undo.nVersion; + coins->Clear(); + coins->fCoinBase = undo.fCoinBase; + coins->nHeight = undo.nHeight; + coins->nVersion = undo.nVersion; } else { - if (coins.IsPruned()) + if (coins->IsPruned()) fClean = fClean && error("DisconnectBlock() : undo data adding output to missing transaction"); } - if (coins.IsAvailable(out.n)) + if (coins->IsAvailable(out.n)) fClean = fClean && error("DisconnectBlock() : undo data overwriting existing output"); - if (coins.vout.size() < out.n+1) - coins.vout.resize(out.n+1); - coins.vout[out.n] = undo.txout; - if (!view.SetCoins(out.hash, coins)) - return error("DisconnectBlock() : cannot restore coin inputs"); + if (coins->vout.size() < out.n+1) + coins->vout.resize(out.n+1); + coins->vout[out.n] = undo.txout; } } } @@ -1650,15 +1589,14 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C int64_t nBIP16SwitchTime = 1333238400; bool fStrictPayToScriptHash = (pindex->GetBlockTime() >= nBIP16SwitchTime); - unsigned int flags = SCRIPT_VERIFY_NOCACHE | - (fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE); + unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE; CBlockUndo blockundo; CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); int64_t nTimeStart = GetTimeMicros(); - int64_t nFees = 0; + CAmount nFees = 0; int nInputs = 0; unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); @@ -1695,7 +1633,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C nFees += view.GetValueIn(tx)-tx.GetValueOut(); std::vector<CScriptCheck> vChecks; - if (!CheckInputs(tx, state, view, fScriptChecks, flags, nScriptCheckThreads ? &vChecks : NULL)) + if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL)) return false; control.Add(vChecks); } @@ -1739,7 +1677,7 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40)) return error("ConnectBlock() : FindUndoPos failed"); if (!blockundo.WriteToDisk(pos, pindex->pprev->GetBlockHash())) - return state.Abort(_("Failed to write undo data")); + return state.Abort("Failed to write undo data"); // update nUndoPos in block index pindex->nUndoPos = pos.nPos; @@ -1750,17 +1688,15 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C CDiskBlockIndex blockindex(pindex); if (!pblocktree->WriteBlockIndex(blockindex)) - return state.Abort(_("Failed to write block index")); + return state.Abort("Failed to write block index"); } if (fTxIndex) if (!pblocktree->WriteTxIndex(vPos)) - return state.Abort(_("Failed to write transaction index")); + return state.Abort("Failed to write transaction index"); // add this block to the view's block chain - bool ret; - ret = view.SetBestBlock(pindex->GetBlockHash()); - assert(ret); + view.SetBestBlock(pindex->GetBlockHash()); int64_t nTime3 = GetTimeMicros(); nTimeIndex += nTime3 - nTime2; LogPrint("bench", " - Index writing: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeIndex * 0.000001); @@ -1790,7 +1726,7 @@ bool static WriteChainState(CValidationState &state) { FlushBlockFile(); pblocktree->Sync(); if (!pcoinsTip->Flush()) - return state.Abort(_("Failed to write to coin database")); + return state.Abort("Failed to write to coin database"); nLastWrite = GetTimeMicros(); } return true; @@ -1804,15 +1740,16 @@ void static UpdateTip(CBlockIndex *pindexNew) { nTimeBestReceived = GetTime(); mempool.AddTransactionsUpdated(1); - LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f\n", + LogPrintf("UpdateTip: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx, DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()), - Checkpoints::GuessVerificationProgress(chainActive.Tip())); + Checkpoints::GuessVerificationProgress(chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); // Check the version of the last 100 blocks to see if we need to upgrade: - if (!IsInitialBlockDownload()) + static bool fWarned = false; + if (!IsInitialBlockDownload() && !fWarned) { int nUpgraded = 0; const CBlockIndex* pindex = chainActive.Tip(); @@ -1825,8 +1762,12 @@ void static UpdateTip(CBlockIndex *pindexNew) { if (nUpgraded > 0) LogPrintf("SetBestChain: %d of last 100 blocks above version %d\n", nUpgraded, (int)CBlock::CURRENT_VERSION); if (nUpgraded > 100/2) + { // strMiscWarning is read by GetWarnings(), called by Qt and the JSON-RPC code to warn the user: strMiscWarning = _("Warning: This version is obsolete, upgrade required!"); + CAlert::Notify(strMiscWarning, true); + fWarned = true; + } } } @@ -1838,11 +1779,11 @@ bool static DisconnectTip(CValidationState &state) { // Read block from disk. CBlock block; if (!ReadBlockFromDisk(block, pindexDelete)) - return state.Abort(_("Failed to read block")); + return state.Abort("Failed to read block"); // Apply the block atomically to the chain state. int64_t nStart = GetTimeMicros(); { - CCoinsViewCache view(*pcoinsTip, true); + CCoinsViewCache view(pcoinsTip); if (!DisconnectBlock(block, state, pindexDelete, view)) return error("DisconnectTip() : DisconnectBlock %s failed", pindexDelete->GetBlockHash().ToString()); assert(view.Flush()); @@ -1887,7 +1828,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * CBlock block; if (!pblock) { if (!ReadBlockFromDisk(block, pindexNew)) - return state.Abort(_("Failed to read block")); + return state.Abort("Failed to read block"); pblock = █ } // Apply the block atomically to the chain state. @@ -1895,7 +1836,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * int64_t nTime3; LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); { - CCoinsViewCache view(*pcoinsTip, true); + CCoinsViewCache view(pcoinsTip); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); if (!ConnectBlock(*pblock, state, pindexNew, view)) { if (state.IsInvalid()) @@ -2041,7 +1982,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo CheckForkWarningConditions(); if (!pblocktree->Flush()) - return state.Abort(_("Failed to sync block index")); + return state.Abort("Failed to sync block index"); return true; } @@ -2078,10 +2019,10 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) { // Relay inventory, but don't relay old inventory during initial block download. int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(); { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) - pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) + pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip)); } uiInterface.NotifyBlockTip(hashNewTip); @@ -2148,7 +2089,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl setBlockIndexValid.insert(pindexNew); if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew))) - return state.Abort(_("Failed to write block index")); + return state.Abort("Failed to write block index"); return true; } @@ -2200,7 +2141,7 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd } if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) - return state.Abort(_("Failed to write file info")); + return state.Abort("Failed to write file info"); if (fUpdatedLast) pblocktree->WriteLastBlockFile(nLastBlockFile); @@ -2218,15 +2159,15 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne pos.nPos = infoLastBlockFile.nUndoSize; nNewSize = (infoLastBlockFile.nUndoSize += nAddSize); if (!pblocktree->WriteBlockFileInfo(nLastBlockFile, infoLastBlockFile)) - return state.Abort(_("Failed to write block info")); + return state.Abort("Failed to write block info"); } else { CBlockFileInfo info; if (!pblocktree->ReadBlockFileInfo(nFile, info)) - return state.Abort(_("Failed to read block info")); + return state.Abort("Failed to read block info"); pos.nPos = info.nUndoSize; nNewSize = (info.nUndoSize += nAddSize); if (!pblocktree->WriteBlockFileInfo(nFile, info)) - return state.Abort(_("Failed to write block info")); + return state.Abort("Failed to write block info"); } unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; @@ -2289,13 +2230,12 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo if (!CheckTransaction(tx, state)) return error("CheckBlock() : CheckTransaction failed"); - // Check for duplicate txids. This is caught by ConnectInputs(), - // but catching it earlier avoids a potential DoS attack: - set<uint256> uniqueTx; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - uniqueTx.insert(tx.GetHash()); - } - if (uniqueTx.size() != block.vtx.size()) + // Check for merkle tree malleability (CVE-2012-2459): repeating sequences + // of transactions in a block without affecting the merkle root of a block, + // while still invalidating it. + bool mutated; + uint256 hashMerkleRoot2 = block.BuildMerkleTree(&mutated); + if (mutated) return state.DoS(100, error("CheckBlock() : duplicate transaction"), REJECT_INVALID, "bad-txns-duplicate", true); @@ -2309,7 +2249,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo REJECT_INVALID, "bad-blk-sigops", true); // Check merkle root - if (fCheckMerkleRoot && block.hashMerkleRoot != block.BuildMerkleTree()) + if (fCheckMerkleRoot && block.hashMerkleRoot != hashMerkleRoot2) return state.DoS(100, error("CheckBlock() : hashMerkleRoot mismatch"), REJECT_INVALID, "bad-txnmrklroot", true); @@ -2326,7 +2266,7 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex if (miSelf != mapBlockIndex.end()) { pindex = miSelf->second; if (pindex->nStatus & BLOCK_FAILED_MASK) - return state.Invalid(error("AcceptBlock() : block is marked invalid"), 0, "duplicate"); + return state.Invalid(error("%s : block is marked invalid", __func__), 0, "duplicate"); } CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); @@ -2336,12 +2276,12 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex int64_t deltaTime = block.GetBlockTime() - pcheckpoint->GetBlockTime(); if (deltaTime < 0) { - return state.DoS(100, error("CheckBlockHeader() : block with timestamp before last checkpoint"), + return state.DoS(100, error("%s : block with timestamp before last checkpoint", __func__), REJECT_CHECKPOINT, "time-too-old"); } if (!CheckMinWork(block.nBits, pcheckpoint->nBits, deltaTime)) { - return state.DoS(100, error("CheckBlockHeader() : block with too little proof-of-work"), + return state.DoS(100, error("%s : block with too little proof-of-work", __func__), REJECT_INVALID, "bad-diffbits"); } } @@ -2352,35 +2292,36 @@ bool AcceptBlockHeader(CBlockHeader& block, CValidationState& state, CBlockIndex if (hash != Params().HashGenesisBlock()) { BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); if (mi == mapBlockIndex.end()) - return state.DoS(10, error("AcceptBlock() : prev block not found"), 0, "bad-prevblk"); + return state.DoS(10, error("%s : prev block not found", __func__), 0, "bad-prevblk"); pindexPrev = (*mi).second; nHeight = pindexPrev->nHeight+1; // Check proof of work - if (block.nBits != GetNextWorkRequired(pindexPrev, &block)) - return state.DoS(100, error("AcceptBlock() : incorrect proof of work"), + if ((!Params().SkipProofOfWorkCheck()) && + (block.nBits != GetNextWorkRequired(pindexPrev, &block))) + return state.DoS(100, error("%s : incorrect proof of work", __func__), REJECT_INVALID, "bad-diffbits"); // Check timestamp against prev if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) - return state.Invalid(error("AcceptBlock() : block's timestamp is too early"), + return state.Invalid(error("%s : block's timestamp is too early", __func__), REJECT_INVALID, "time-too-old"); // Check that the block chain matches the known block chain up to a checkpoint if (!Checkpoints::CheckBlock(nHeight, hash)) - return state.DoS(100, error("AcceptBlock() : rejected by checkpoint lock-in at %d", nHeight), + return state.DoS(100, error("%s : rejected by checkpoint lock-in at %d", __func__, nHeight), REJECT_CHECKPOINT, "checkpoint mismatch"); // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(); if (pcheckpoint && nHeight < pcheckpoint->nHeight) - return state.DoS(100, error("AcceptBlock() : forked chain older than last checkpoint (height %d)", nHeight)); + return state.DoS(100, error("%s : forked chain older than last checkpoint (height %d)", __func__, nHeight)); // Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded: if (block.nVersion < 2 && CBlockIndex::IsSuperMajority(2, pindexPrev, Params().RejectBlockOutdatedMajority())) { - return state.Invalid(error("AcceptBlock() : rejected nVersion=1 block"), + return state.Invalid(error("%s : rejected nVersion=1 block", __func__), REJECT_OBSOLETE, "bad-version"); } } @@ -2443,11 +2384,11 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, return error("AcceptBlock() : FindBlockPos failed"); if (dbp == NULL) if (!WriteBlockToDisk(block, blockPos)) - return state.Abort(_("Failed to write block")); + return state.Abort("Failed to write block"); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("AcceptBlock() : ReceivedBlockTransactions failed"); } catch(std::runtime_error &e) { - return state.Abort(_("System error: ") + e.what()); + return state.Abort(std::string("System error: ") + e.what()); } return true; @@ -2770,10 +2711,12 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) { -bool AbortNode(const std::string &strMessage) { +bool AbortNode(const std::string &strMessage, const std::string &userMessage) { strMiscWarning = strMessage; LogPrintf("*** %s\n", strMessage); - uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_ERROR); + uiInterface.ThreadSafeMessageBox( + userMessage.empty() ? _("Error: A fatal internal error occured, see debug.log for details") : userMessage, + "", CClientUIInterface::MSG_ERROR); StartShutdown(); return false; } @@ -2784,7 +2727,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes) // Check for nMinDiskSpace bytes (currently 50MB) if (nFreeBytesAvailable < nMinDiskSpace + nAdditionalBytes) - return AbortNode(_("Error: Disk space is low!")); + return AbortNode("Disk space is low!", _("Error: Disk space is low!")); return true; } @@ -2943,7 +2886,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth nCheckDepth = chainActive.Height(); nCheckLevel = std::max(0, std::min(4, nCheckLevel)); LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); - CCoinsViewCache coins(*coinsview, true); + CCoinsViewCache coins(coinsview); CBlockIndex* pindexState = chainActive.Tip(); CBlockIndex* pindexFailure = NULL; int nGoodTransactions = 0; @@ -3136,6 +3079,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) int nLoaded = 0; try { + // This takes over fileIn and calls fclose() on it in the CBufferedFile destructor CBufferedFile blkdat(fileIn, 2*MAX_BLOCK_SIZE, MAX_BLOCK_SIZE+8, SER_DISK, CLIENT_VERSION); uint64_t nStartByte = 0; if (dbp) { @@ -3192,9 +3136,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s : Deserialize or I/O error - %s", __func__, e.what()); } } - fclose(fileIn); } catch(std::runtime_error &e) { - AbortNode(_("Error: system error: ") + e.what()); + AbortNode(std::string("System error: ") + e.what()); } if (nLoaded > 0) LogPrintf("Loaded %i blocks from external file in %dms\n", nLoaded, GetTimeMillis() - nStart); @@ -3709,7 +3652,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LOCK(cs_main); // Find the last block the caller has in the main chain - CBlockIndex* pindex = chainActive.FindFork(locator); + CBlockIndex* pindex = FindForkInGlobalIndex(chainActive, locator); // Send the rest of the chain if (pindex) @@ -3756,7 +3699,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else { // Find the last block the caller has in the main chain - pindex = chainActive.FindFork(locator); + pindex = FindForkInGlobalIndex(chainActive, locator); if (pindex) pindex = chainActive.Next(pindex); } @@ -4503,7 +4446,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) { // Open history file to append - CAutoFile fileout = CAutoFile(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); if (!fileout) return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); @@ -4535,7 +4478,7 @@ bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) { // Open history file to read - CAutoFile filein = CAutoFile(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); if (!filein) return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); diff --git a/src/main.h b/src/main.h index 5acc551793..cad7eebfb7 100644 --- a/src/main.h +++ b/src/main.h @@ -10,12 +10,14 @@ #include "config/bitcoin-config.h" #endif +#include "chain.h" #include "chainparams.h" #include "coins.h" #include "core.h" #include "net.h" #include "pow.h" #include "script/script.h" +#include "script/sigcache.h" #include "script/standard.h" #include "sync.h" #include "txmempool.h" @@ -113,7 +115,6 @@ static const uint64_t nMinDiskSpace = 52428800; class CBlockTreeDB; -struct CDiskBlockPos; class CTxUndo; class CScriptCheck; class CValidationState; @@ -172,12 +173,12 @@ std::string GetWarnings(std::string strFor); bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false); /** Find the best known block, and make it the tip of the block chain */ bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL); -int64_t GetBlockValue(int nHeight, int64_t nFees); +CAmount GetBlockValue(int nHeight, const CAmount& nFees); /** Create a new block index entry for a given block hash */ CBlockIndex * InsertBlockIndex(uint256 hash); /** Abort with a message */ -bool AbortNode(const std::string &msg); +bool AbortNode(const std::string &msg, const std::string &userMessage=""); /** Get statistics from node state */ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); /** Increase a node's misbehavior score. */ @@ -189,51 +190,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa bool* pfMissingInputs, bool fRejectInsaneFee=false); - - - - - - struct CNodeStateStats { int nMisbehavior; int nSyncHeight; }; -struct CDiskBlockPos -{ - int nFile; - unsigned int nPos; - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(nFile)); - READWRITE(VARINT(nPos)); - } - - CDiskBlockPos() { - SetNull(); - } - - CDiskBlockPos(int nFileIn, unsigned int nPosIn) { - nFile = nFileIn; - nPos = nPosIn; - } - - friend bool operator==(const CDiskBlockPos &a, const CDiskBlockPos &b) { - return (a.nFile == b.nFile && a.nPos == b.nPos); - } - - friend bool operator!=(const CDiskBlockPos &a, const CDiskBlockPos &b) { - return !(a == b); - } - - void SetNull() { nFile = -1; nPos = 0; } - bool IsNull() const { return (nFile == -1); } -}; - struct CDiskTxPos : public CDiskBlockPos { unsigned int nTxOffset; // after header @@ -260,7 +221,7 @@ struct CDiskTxPos : public CDiskBlockPos }; -int64_t GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); +CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree); // // Check transaction inputs, and make sure any @@ -298,9 +259,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& ma // Check whether all inputs of this transaction are valid (no double spends, scripts & sigs, amounts) // This does not modify the UTXO set. If pvChecks is not NULL, script checks are pushed onto it // instead of being performed inline. -bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks = true, - unsigned int flags = STANDARD_SCRIPT_VERIFY_FLAGS, - std::vector<CScriptCheck> *pvChecks = NULL); +bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &view, bool fScriptChecks, + unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks = NULL); // Apply the effects of this transaction on the UTXO set represented by view void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight); @@ -342,12 +302,13 @@ private: const CTransaction *ptxTo; unsigned int nIn; unsigned int nFlags; + bool cacheStore; public: - CScriptCheck(): ptxTo(0), nIn(0), nFlags(0) {} - CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn) : + CScriptCheck(): ptxTo(0), nIn(0), nFlags(0), cacheStore(false) {} + CScriptCheck(const CCoins& txFromIn, const CTransaction& txToIn, unsigned int nInIn, unsigned int nFlagsIn, bool cacheIn) : scriptPubKey(txFromIn.vout[txToIn.vin[nInIn].prevout.n].scriptPubKey), - ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn) { } + ptxTo(&txToIn), nIn(nInIn), nFlags(nFlagsIn), cacheStore(cacheIn) { } bool operator()() const; @@ -356,6 +317,7 @@ public: std::swap(ptxTo, check.ptxTo); std::swap(nIn, check.nIn); std::swap(nFlags, check.nFlags); + std::swap(cacheStore, check.cacheStore); } }; @@ -545,288 +507,6 @@ public: } }; -enum BlockStatus { - BLOCK_VALID_UNKNOWN = 0, - BLOCK_VALID_HEADER = 1, // parsed, version ok, hash satisfies claimed PoW, 1 <= vtx count <= max, timestamp not in future - BLOCK_VALID_TREE = 2, // parent found, difficulty matches, timestamp >= median previous, checkpoint - BLOCK_VALID_TRANSACTIONS = 3, // only first tx is coinbase, 2 <= coinbase input script length <= 100, transactions valid, no duplicate txids, sigops, size, merkle root - BLOCK_VALID_CHAIN = 4, // outputs do not overspend inputs, no double spends, coinbase output ok, immature coinbase spends, BIP30 - BLOCK_VALID_SCRIPTS = 5, // scripts/signatures ok - BLOCK_VALID_MASK = BLOCK_VALID_HEADER | BLOCK_VALID_TREE | BLOCK_VALID_TRANSACTIONS | - BLOCK_VALID_CHAIN | BLOCK_VALID_SCRIPTS, - - BLOCK_HAVE_DATA = 8, // full block available in blk*.dat - BLOCK_HAVE_UNDO = 16, // undo data available in rev*.dat - BLOCK_HAVE_MASK = BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO, - - BLOCK_FAILED_VALID = 32, // stage after last reached validness failed - BLOCK_FAILED_CHILD = 64, // descends from failed block - BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, -}; - -/** The block chain is a tree shaped structure starting with the - * genesis block at the root, with each block potentially having multiple - * candidates to be the next block. A blockindex may have multiple pprev pointing - * to it, but at most one of them can be part of the currently active branch. - */ -class CBlockIndex -{ -public: - // pointer to the hash of the block, if any. memory is owned by this CBlockIndex - const uint256* phashBlock; - - // pointer to the index of the predecessor of this block - CBlockIndex* pprev; - - // pointer to the index of some further predecessor of this block - CBlockIndex* pskip; - - // height of the entry in the chain. The genesis block has height 0 - int nHeight; - - // Which # file this block is stored in (blk?????.dat) - int nFile; - - // Byte offset within blk?????.dat where this block's data is stored - unsigned int nDataPos; - - // Byte offset within rev?????.dat where this block's undo data is stored - unsigned int nUndoPos; - - // (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block - uint256 nChainWork; - - // Number of transactions in this block. - // Note: in a potential headers-first mode, this number cannot be relied upon - unsigned int nTx; - - // (memory only) Number of transactions in the chain up to and including this block - unsigned int nChainTx; // change to 64-bit type when necessary; won't happen before 2030 - - // Verification status of this block. See enum BlockStatus - unsigned int nStatus; - - // block header - int nVersion; - uint256 hashMerkleRoot; - unsigned int nTime; - unsigned int nBits; - unsigned int nNonce; - - // (memory only) Sequencial id assigned to distinguish order in which blocks are received. - uint32_t nSequenceId; - - void SetNull() - { - phashBlock = NULL; - pprev = NULL; - pskip = NULL; - nHeight = 0; - nFile = 0; - nDataPos = 0; - nUndoPos = 0; - nChainWork = 0; - nTx = 0; - nChainTx = 0; - nStatus = 0; - nSequenceId = 0; - - nVersion = 0; - hashMerkleRoot = 0; - nTime = 0; - nBits = 0; - nNonce = 0; - } - - CBlockIndex() - { - SetNull(); - } - - CBlockIndex(CBlockHeader& block) - { - SetNull(); - - nVersion = block.nVersion; - hashMerkleRoot = block.hashMerkleRoot; - nTime = block.nTime; - nBits = block.nBits; - nNonce = block.nNonce; - } - - CDiskBlockPos GetBlockPos() const { - CDiskBlockPos ret; - if (nStatus & BLOCK_HAVE_DATA) { - ret.nFile = nFile; - ret.nPos = nDataPos; - } - return ret; - } - - CDiskBlockPos GetUndoPos() const { - CDiskBlockPos ret; - if (nStatus & BLOCK_HAVE_UNDO) { - ret.nFile = nFile; - ret.nPos = nUndoPos; - } - return ret; - } - - CBlockHeader GetBlockHeader() const - { - CBlockHeader block; - block.nVersion = nVersion; - if (pprev) - block.hashPrevBlock = pprev->GetBlockHash(); - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block; - } - - uint256 GetBlockHash() const - { - return *phashBlock; - } - - int64_t GetBlockTime() const - { - return (int64_t)nTime; - } - - uint256 GetBlockWork() const - { - return GetProofIncrement(nBits); - } - - enum { nMedianTimeSpan=11 }; - - int64_t GetMedianTimePast() const - { - int64_t pmedian[nMedianTimeSpan]; - int64_t* pbegin = &pmedian[nMedianTimeSpan]; - int64_t* pend = &pmedian[nMedianTimeSpan]; - - const CBlockIndex* pindex = this; - for (int i = 0; i < nMedianTimeSpan && pindex; i++, pindex = pindex->pprev) - *(--pbegin) = pindex->GetBlockTime(); - - std::sort(pbegin, pend); - return pbegin[(pend - pbegin)/2]; - } - - /** - * Returns true if there are nRequired or more blocks of minVersion or above - * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart - * and going backwards. - */ - static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, - unsigned int nRequired); - - std::string ToString() const - { - return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)", - pprev, nHeight, - hashMerkleRoot.ToString(), - GetBlockHash().ToString()); - } - - // Check whether this block index entry is valid up to the passed validity level. - bool IsValid(enum BlockStatus nUpTo = BLOCK_VALID_TRANSACTIONS) const - { - assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. - if (nStatus & BLOCK_FAILED_MASK) - return false; - return ((nStatus & BLOCK_VALID_MASK) >= nUpTo); - } - - // Raise the validity level of this block index entry. - // Returns true if the validity was changed. - bool RaiseValidity(enum BlockStatus nUpTo) - { - assert(!(nUpTo & ~BLOCK_VALID_MASK)); // Only validity flags allowed. - if (nStatus & BLOCK_FAILED_MASK) - return false; - if ((nStatus & BLOCK_VALID_MASK) < nUpTo) { - nStatus = (nStatus & ~BLOCK_VALID_MASK) | nUpTo; - return true; - } - return false; - } - - // Build the skiplist pointer for this entry. - void BuildSkip(); - - // Efficiently find an ancestor of this block. - CBlockIndex* GetAncestor(int height); - const CBlockIndex* GetAncestor(int height) const; -}; - -/** Used to marshal pointers into hashes for db storage. */ -class CDiskBlockIndex : public CBlockIndex -{ -public: - uint256 hashPrev; - - CDiskBlockIndex() { - hashPrev = 0; - } - - explicit CDiskBlockIndex(CBlockIndex* pindex) : CBlockIndex(*pindex) { - hashPrev = (pprev ? pprev->GetBlockHash() : 0); - } - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - if (!(nType & SER_GETHASH)) - READWRITE(VARINT(nVersion)); - - READWRITE(VARINT(nHeight)); - READWRITE(VARINT(nStatus)); - READWRITE(VARINT(nTx)); - if (nStatus & (BLOCK_HAVE_DATA | BLOCK_HAVE_UNDO)) - READWRITE(VARINT(nFile)); - if (nStatus & BLOCK_HAVE_DATA) - READWRITE(VARINT(nDataPos)); - if (nStatus & BLOCK_HAVE_UNDO) - READWRITE(VARINT(nUndoPos)); - - // block header - READWRITE(this->nVersion); - READWRITE(hashPrev); - READWRITE(hashMerkleRoot); - READWRITE(nTime); - READWRITE(nBits); - READWRITE(nNonce); - } - - uint256 GetBlockHash() const - { - CBlockHeader block; - block.nVersion = nVersion; - block.hashPrevBlock = hashPrev; - block.hashMerkleRoot = hashMerkleRoot; - block.nTime = nTime; - block.nBits = nBits; - block.nNonce = nNonce; - return block.GetHash(); - } - - - std::string ToString() const - { - std::string str = "CDiskBlockIndex("; - str += CBlockIndex::ToString(); - str += strprintf("\n hashBlock=%s, hashPrev=%s)", - GetBlockHash().ToString(), - hashPrev.ToString()); - return str; - } -}; - /** Capture information about block/transaction validation */ class CValidationState { private: @@ -898,65 +578,8 @@ public: bool VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth); }; -/** An in-memory indexed chain of blocks. */ -class CChain { -private: - std::vector<CBlockIndex*> vChain; - -public: - /** Returns the index entry for the genesis block of this chain, or NULL if none. */ - CBlockIndex *Genesis() const { - return vChain.size() > 0 ? vChain[0] : NULL; - } - - /** Returns the index entry for the tip of this chain, or NULL if none. */ - CBlockIndex *Tip() const { - return vChain.size() > 0 ? vChain[vChain.size() - 1] : NULL; - } - - /** Returns the index entry at a particular height in this chain, or NULL if no such height exists. */ - CBlockIndex *operator[](int nHeight) const { - if (nHeight < 0 || nHeight >= (int)vChain.size()) - return NULL; - return vChain[nHeight]; - } - - /** Compare two chains efficiently. */ - friend bool operator==(const CChain &a, const CChain &b) { - return a.vChain.size() == b.vChain.size() && - a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; - } - - /** Efficiently check whether a block is present in this chain. */ - bool Contains(const CBlockIndex *pindex) const { - return (*this)[pindex->nHeight] == pindex; - } - - /** Find the successor of a block in this chain, or NULL if the given index is not found or is the tip. */ - CBlockIndex *Next(const CBlockIndex *pindex) const { - if (Contains(pindex)) - return (*this)[pindex->nHeight + 1]; - else - return NULL; - } - - /** Return the maximal height in the chain. Is equal to chain.Tip() ? chain.Tip()->nHeight : -1. */ - int Height() const { - return vChain.size() - 1; - } - - /** Set/initialize a chain with a given tip. Returns the forking point. */ - CBlockIndex *SetTip(CBlockIndex *pindex); - - /** Return a CBlockLocator that refers to a block in this chain (by default the tip). */ - CBlockLocator GetLocator(const CBlockIndex *pindex = NULL) const; - - /** Find the last common block between this chain and a locator. */ - CBlockIndex *FindFork(const CBlockLocator &locator) const; - - /** Find the last common block between this chain and a block index entry. */ - const CBlockIndex *FindFork(const CBlockIndex *pindex) const; -}; +/** Find the last common block between the parameter chain and a locator. */ +CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator); /** The currently-connected chain of blocks. */ extern CChain chainActive; @@ -970,7 +593,7 @@ extern CBlockTreeDB *pblocktree; struct CBlockTemplate { CBlock block; - std::vector<int64_t> vTxFees; + std::vector<CAmount> vTxFees; std::vector<int64_t> vTxSigOps; }; diff --git a/src/miner.cpp b/src/miner.cpp index d05ddbeb1f..c2762bf44e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -83,6 +83,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) return NULL; CBlock *pblock = &pblocktemplate->block; // pointer for convenience + // -regtest only: allow overriding block.nVersion with + // -blockversion=N to test forking scenarios + if (Params().MineBlocksOnDemand()) + pblock->nVersion = GetArg("-blockversion", pblock->nVersion); + // Create coinbase tx CMutableTransaction txNew; txNew.vin.resize(1); @@ -111,12 +116,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize); // Collect memory pool transactions into the block - int64_t nFees = 0; + CAmount nFees = 0; { LOCK2(cs_main, mempool.cs); CBlockIndex* pindexPrev = chainActive.Tip(); - CCoinsViewCache view(*pcoinsTip, true); + CCoinsViewCache view(pcoinsTip); // Priority order to process transactions list<COrphan> vOrphan; // list memory doesn't move @@ -135,7 +140,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) COrphan* porphan = NULL; double dPriority = 0; - int64_t nTotalIn = 0; + CAmount nTotalIn = 0; bool fMissingInputs = false; BOOST_FOREACH(const CTxIn& txin, tx.vin) { @@ -170,7 +175,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) const CCoins* coins = view.AccessCoins(txin.prevout.hash); assert(coins); - int64_t nValueIn = coins->vout[txin.prevout.n].nValue; + CAmount nValueIn = coins->vout[txin.prevout.n].nValue; nTotalIn += nValueIn; int nConf = pindexPrev->nHeight - coins->nHeight + 1; @@ -229,7 +234,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Skip free transactions if we're past the minimum block size: const uint256& hash = tx.GetHash(); double dPriorityDelta = 0; - int64_t nFeeDelta = 0; + CAmount nFeeDelta = 0; mempool.ApplyDeltas(hash, dPriorityDelta, nFeeDelta); if (fSortedByFee && (dPriorityDelta <= 0) && (nFeeDelta <= 0) && (feeRate < ::minRelayTxFee) && (nBlockSize + nTxSize >= nBlockMinSize)) continue; @@ -247,7 +252,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!view.HaveInputs(tx)) continue; - int64_t nTxFees = view.GetValueIn(tx)-tx.GetValueOut(); + CAmount nTxFees = view.GetValueIn(tx)-tx.GetValueOut(); nTxSigOps += GetP2SHSigOpCount(tx, view); if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) @@ -257,7 +262,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // policy here, but we still have to ensure that the block we // create only contains transactions that are valid in new blocks. CValidationState state; - if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS)) + if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) continue; CTxUndo txundo; @@ -316,7 +321,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CBlockIndex indexDummy(*pblock); indexDummy.pprev = pindexPrev; indexDummy.nHeight = pindexPrev->nHeight + 1; - CCoinsViewCache viewNew(*pcoinsTip, true); + CCoinsViewCache viewNew(pcoinsTip); CValidationState state; if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); diff --git a/src/net.cpp b/src/net.cpp index ab547e2fd7..dd5cb480cc 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -78,6 +78,7 @@ uint64_t nLocalHostNonce = 0; static std::vector<ListenSocket> vhListenSocket; CAddrMan addrman; int nMaxConnections = 125; +bool fAddressesInitialized = false; vector<CNode*> vNodes; CCriticalSection cs_vNodes; @@ -1739,6 +1740,18 @@ void static Discover(boost::thread_group& threadGroup) void StartNode(boost::thread_group& threadGroup) { + uiInterface.InitMessage(_("Loading addresses...")); + // Load addresses for peers.dat + int64_t nStart = GetTimeMillis(); + { + CAddrDB adb; + if (!adb.Read(addrman)) + LogPrintf("Invalid or missing peers.dat; recreating\n"); + } + LogPrintf("Loaded %i addresses from peers.dat %dms\n", + addrman.size(), GetTimeMillis() - nStart); + fAddressesInitialized = true; + if (semOutbound == NULL) { // initialize semaphore int nMaxOutbound = min(MAX_OUTBOUND_CONNECTIONS, nMaxConnections); @@ -1785,7 +1798,12 @@ bool StopNode() if (semOutbound) for (int i=0; i<MAX_OUTBOUND_CONNECTIONS; i++) semOutbound->post(); - DumpAddresses(); + + if (fAddressesInitialized) + { + DumpAddresses(); + fAddressesInitialized = false; + } return true; } @@ -1957,7 +1975,7 @@ bool CAddrDB::Write(const CAddrMan& addr) // open temp output file, and associate with CAutoFile boost::filesystem::path pathTmp = GetDataDir() / tmpfn; FILE *file = fopen(pathTmp.string().c_str(), "wb"); - CAutoFile fileout = CAutoFile(file, SER_DISK, CLIENT_VERSION); + CAutoFile fileout(file, SER_DISK, CLIENT_VERSION); if (!fileout) return error("%s : Failed to open file %s", __func__, pathTmp.string()); @@ -1982,7 +2000,7 @@ bool CAddrDB::Read(CAddrMan& addr) { // open input file, and associate with CAutoFile FILE *file = fopen(pathAddr.string().c_str(), "rb"); - CAutoFile filein = CAutoFile(file, SER_DISK, CLIENT_VERSION); + CAutoFile filein(file, SER_DISK, CLIENT_VERSION); if (!filein) return error("%s : Failed to open file %s", __func__, pathAddr.string()); diff --git a/src/netbase.cpp b/src/netbase.cpp index 5819c152a3..b3d1001547 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -40,7 +40,7 @@ using namespace std; static proxyType proxyInfo[NET_MAX]; static CService nameProxy; static CCriticalSection cs_proxyInfos; -int nConnectTimeout = 5000; +int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; bool fNameLookup = false; static const unsigned char pchIPv4[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff }; diff --git a/src/netbase.h b/src/netbase.h index 9fc5c72eb8..1455cd8c33 100644 --- a/src/netbase.h +++ b/src/netbase.h @@ -19,6 +19,9 @@ extern int nConnectTimeout; extern bool fNameLookup; +/** -timeout default */ +static const int DEFAULT_CONNECT_TIMEOUT = 5000; + #ifdef WIN32 // In MSVC, this is defined as a macro, undefine it to prevent a compile and link error #undef SetPort diff --git a/src/pow.cpp b/src/pow.cpp index 893f6c18be..d50222849c 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -81,6 +81,10 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) bool fNegative; bool fOverflow; uint256 bnTarget; + + if (Params().SkipProofOfWorkCheck()) + return true; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range diff --git a/src/protocol.cpp b/src/protocol.cpp index 341de0602a..0e28f3abbd 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -24,7 +24,6 @@ CMessageHeader::CMessageHeader() { memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); memset(pchCommand, 0, sizeof(pchCommand)); - pchCommand[1] = 1; nMessageSize = -1; nChecksum = 0; } @@ -32,6 +31,7 @@ CMessageHeader::CMessageHeader() CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSizeIn) { memcpy(pchMessageStart, Params().MessageStart(), MESSAGE_START_SIZE); + memset(pchCommand, 0, sizeof(pchCommand)); strncpy(pchCommand, pszCommand, COMMAND_SIZE); nMessageSize = nMessageSizeIn; nChecksum = 0; @@ -39,10 +39,7 @@ CMessageHeader::CMessageHeader(const char* pszCommand, unsigned int nMessageSize std::string CMessageHeader::GetCommand() const { - if (pchCommand[COMMAND_SIZE-1] == 0) - return std::string(pchCommand, pchCommand + strlen(pchCommand)); - else - return std::string(pchCommand, pchCommand + COMMAND_SIZE); + return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE)); } bool CMessageHeader::IsValid() const diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 6cc6b99ceb..9872ebc1f6 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -12,10 +12,12 @@ #include "guiconstants.h" #include "guiutil.h" #include "intro.h" +#include "networkstyle.h" #include "optionsmodel.h" #include "splashscreen.h" #include "utilitydialog.h" #include "winshutdownmonitor.h" + #ifdef ENABLE_WALLET #include "paymentserver.h" #include "walletmodel.h" @@ -26,6 +28,7 @@ #include "rpcserver.h" #include "ui_interface.h" #include "util.h" + #ifdef ENABLE_WALLET #include "wallet.h" #endif @@ -34,15 +37,16 @@ #include <boost/filesystem/operations.hpp> #include <boost/thread.hpp> + #include <QApplication> #include <QDebug> #include <QLibraryInfo> #include <QLocale> #include <QMessageBox> #include <QSettings> +#include <QThread> #include <QTimer> #include <QTranslator> -#include <QThread> #if defined(QT_STATICPLUGIN) #include <QtPlugin> @@ -70,6 +74,7 @@ Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); // Declare meta types used for QMetaObject::invokeMethod Q_DECLARE_METATYPE(bool*) +Q_DECLARE_METATYPE(CAmount) static void InitMessage(const std::string &message) { @@ -186,9 +191,9 @@ public: /// Create options model void createOptionsModel(); /// Create main window - void createWindow(bool isaTestNet); + void createWindow(const NetworkStyle *networkStyle); /// Create splash screen - void createSplashScreen(bool isaTestNet); + void createSplashScreen(const NetworkStyle *networkStyle); /// Request core initialization void requestInitialize(); @@ -327,18 +332,20 @@ void BitcoinApplication::createOptionsModel() optionsModel = new OptionsModel(); } -void BitcoinApplication::createWindow(bool isaTestNet) +void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) { - window = new BitcoinGUI(isaTestNet, 0); + window = new BitcoinGUI(networkStyle, 0); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); pollShutdownTimer->start(200); } -void BitcoinApplication::createSplashScreen(bool isaTestNet) +void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { - SplashScreen *splash = new SplashScreen(QPixmap(), 0, isaTestNet); + SplashScreen *splash = new SplashScreen(0, networkStyle); + // We don't hold a direct pointer to the splash screen after creation, so use + // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. splash->setAttribute(Qt::WA_DeleteOnClose); splash->show(); connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); @@ -423,8 +430,6 @@ void BitcoinApplication::initializeResult(int retval) } #endif - emit splashFinished(window); - // If -min option passed, start window minimized. if(GetBoolArg("-min", false)) { @@ -434,6 +439,8 @@ void BitcoinApplication::initializeResult(int retval) { window->show(); } + emit splashFinished(window); + #ifdef ENABLE_WALLET // Now that initialization/startup is done, process any command-line // bitcoin: URIs or payment requests: @@ -504,6 +511,9 @@ int main(int argc, char *argv[]) // Register meta types used for QMetaObject::invokeMethod qRegisterMetaType< bool* >(); + // Need to pass name here as CAmount is a typedef (see http://qt-project.org/doc/qt-5/qmetatype.html#qRegisterMetaType) + // IMPORTANT if it is no longer a typedef use the normal variant above + qRegisterMetaType< CAmount >("CAmount"); /// 3. Application identification // must be set before OptionsModel is initialized or translations are loaded, @@ -563,12 +573,10 @@ int main(int argc, char *argv[]) if (!PaymentServer::ipcParseCommandLine(argc, argv)) exit(0); #endif - bool isaTestNet = Params().NetworkID() != CBaseChainParams::MAIN; + QScopedPointer<const NetworkStyle> networkStyle(NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString()))); + assert(!networkStyle.isNull()); // Allow for separate UI settings for testnets - if (isaTestNet) - QApplication::setApplicationName(QAPP_APP_NAME_TESTNET); - else - QApplication::setApplicationName(QAPP_APP_NAME_DEFAULT); + QApplication::setApplicationName(networkStyle->getAppName()); // Re-initialize translations after changing application name (language in network-specific settings can be different) initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); @@ -608,11 +616,11 @@ int main(int argc, char *argv[]) uiInterface.InitMessage.connect(InitMessage); if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) - app.createSplashScreen(isaTestNet); + app.createSplashScreen(networkStyle.data()); try { - app.createWindow(isaTestNet); + app.createWindow(networkStyle.data()); app.requestInitialize(); #if defined(Q_OS_WIN) && QT_VERSION >= 0x050000 WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("Bitcoin Core didn't yet exit safely..."), (HWND)app.getMainWinId()); diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index 6466039013..6e35bf17b3 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -44,7 +44,7 @@ public: void fixup(QString &input) const { bool valid = false; - qint64 val = parse(input, &valid); + CAmount val = parse(input, &valid); if(valid) { input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways); @@ -52,12 +52,12 @@ public: } } - qint64 value(bool *valid_out=0) const + CAmount value(bool *valid_out=0) const { return parse(text(), valid_out); } - void setValue(qint64 value) + void setValue(const CAmount& value) { lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); emit valueChanged(); @@ -66,9 +66,9 @@ public: void stepBy(int steps) { bool valid = false; - qint64 val = value(&valid); + CAmount val = value(&valid); val = val + steps * singleStep; - val = qMin(qMax(val, Q_INT64_C(0)), BitcoinUnits::maxMoney()); + val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney()); setValue(val); } @@ -78,7 +78,7 @@ public: if(text().isEmpty()) // Allow step-up with empty field return StepUpEnabled; bool valid = false; - qint64 val = value(&valid); + CAmount val = value(&valid); if(valid) { if(val > 0) @@ -92,7 +92,7 @@ public: void setDisplayUnit(int unit) { bool valid = false; - qint64 val = value(&valid); + CAmount val = value(&valid); currentUnit = unit; @@ -102,7 +102,7 @@ public: clear(); } - void setSingleStep(qint64 step) + void setSingleStep(const CAmount& step) { singleStep = step; } @@ -140,7 +140,7 @@ public: } private: int currentUnit; - qint64 singleStep; + CAmount singleStep; mutable QSize cachedMinimumSizeHint; /** @@ -148,9 +148,9 @@ private: * return validity. * @note Must return 0 if !valid. */ - qint64 parse(const QString &text, bool *valid_out=0) const + CAmount parse(const QString &text, bool *valid_out=0) const { - qint64 val = 0; + CAmount val = 0; bool valid = BitcoinUnits::parse(currentUnit, text, &val); if(valid) { @@ -253,12 +253,12 @@ QWidget *BitcoinAmountField::setupTabChain(QWidget *prev) return unit; } -qint64 BitcoinAmountField::value(bool *valid_out) const +CAmount BitcoinAmountField::value(bool *valid_out) const { return amount->value(valid_out); } -void BitcoinAmountField::setValue(qint64 value) +void BitcoinAmountField::setValue(const CAmount& value) { amount->setValue(value); } @@ -285,7 +285,7 @@ void BitcoinAmountField::setDisplayUnit(int newUnit) unit->setValue(newUnit); } -void BitcoinAmountField::setSingleStep(qint64 step) +void BitcoinAmountField::setSingleStep(const CAmount& step) { amount->setSingleStep(step); } diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index c713f5d687..e52feeb46e 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -5,30 +5,32 @@ #ifndef BITCOINAMOUNTFIELD_H #define BITCOINAMOUNTFIELD_H +#include "amount.h" + #include <QWidget> +class AmountSpinBox; + QT_BEGIN_NAMESPACE class QValueComboBox; QT_END_NAMESPACE -class AmountSpinBox; - /** Widget for entering bitcoin amounts. */ class BitcoinAmountField: public QWidget { Q_OBJECT - Q_PROPERTY(qint64 value READ value WRITE setValue NOTIFY valueChanged USER true) + Q_PROPERTY(CAmount value READ value WRITE setValue NOTIFY valueChanged USER true) public: explicit BitcoinAmountField(QWidget *parent = 0); - qint64 value(bool *valid=0) const; - void setValue(qint64 value); + CAmount value(bool *value=0) const; + void setValue(const CAmount& value); /** Set single step in satoshis **/ - void setSingleStep(qint64 step); + void setSingleStep(const CAmount& step); /** Make read-only **/ void setReadOnly(bool fReadOnly); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 790301a1eb..8a945606dc 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -8,12 +8,14 @@ #include "clientmodel.h" #include "guiconstants.h" #include "guiutil.h" +#include "networkstyle.h" #include "notificator.h" #include "openuridialog.h" #include "optionsdialog.h" #include "optionsmodel.h" #include "rpcconsole.h" #include "utilitydialog.h" + #ifdef ENABLE_WALLET #include "walletframe.h" #include "walletmodel.h" @@ -24,8 +26,8 @@ #endif #include "init.h" -#include "util.h" #include "ui_interface.h" +#include "util.h" #include <iostream> @@ -50,15 +52,15 @@ #include <QVBoxLayout> #if QT_VERSION < 0x050000 -#include <QUrl> #include <QTextDocument> +#include <QUrl> #else #include <QUrlQuery> #endif const QString BitcoinGUI::DEFAULT_WALLET = "~Default"; -BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : +BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) : QMainWindow(parent), clientModel(0), walletFrame(0), @@ -111,26 +113,13 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : } else { windowTitle += tr("Node"); } - - if (!fIsTestnet) - { + windowTitle += " " + networkStyle->getTitleAddText(); #ifndef Q_OS_MAC - QApplication::setWindowIcon(QIcon(":icons/bitcoin")); - setWindowIcon(QIcon(":icons/bitcoin")); + QApplication::setWindowIcon(networkStyle->getAppIcon()); + setWindowIcon(networkStyle->getAppIcon()); #else - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin")); + MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon()); #endif - } - else - { - windowTitle += " " + tr("[testnet]"); -#ifndef Q_OS_MAC - QApplication::setWindowIcon(QIcon(":icons/bitcoin_testnet")); - setWindowIcon(QIcon(":icons/bitcoin_testnet")); -#else - MacDockIconHandler::instance()->setIcon(QIcon(":icons/bitcoin_testnet")); -#endif - } setWindowTitle(windowTitle); #if defined(Q_OS_MAC) && QT_VERSION < 0x050000 @@ -160,7 +149,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : // Create actions for the toolbar, menu bar and tray/dock icon // Needs walletFrame to be initialized - createActions(fIsTestnet); + createActions(networkStyle); // Create application menu bar createMenuBar(); @@ -169,7 +158,7 @@ BitcoinGUI::BitcoinGUI(bool fIsTestnet, QWidget *parent) : createToolBars(); // Create system tray icon and notification - createTrayIcon(fIsTestnet); + createTrayIcon(networkStyle); // Create status bar statusBar(); @@ -247,7 +236,7 @@ BitcoinGUI::~BitcoinGUI() #endif } -void BitcoinGUI::createActions(bool fIsTestnet) +void BitcoinGUI::createActions(const NetworkStyle *networkStyle) { QActionGroup *tabGroup = new QActionGroup(this); @@ -294,10 +283,7 @@ void BitcoinGUI::createActions(bool fIsTestnet) quitAction->setStatusTip(tr("Quit application")); quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); quitAction->setMenuRole(QAction::QuitRole); - if (!fIsTestnet) - aboutAction = new QAction(QIcon(":/icons/bitcoin"), tr("&About Bitcoin Core"), this); - else - aboutAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&About Bitcoin Core"), this); + aboutAction = new QAction(networkStyle->getAppIcon(), tr("&About Bitcoin Core"), this); aboutAction->setStatusTip(tr("Show information about Bitcoin Core")); aboutAction->setMenuRole(QAction::AboutRole); #if QT_VERSION < 0x050000 @@ -310,10 +296,7 @@ void BitcoinGUI::createActions(bool fIsTestnet) optionsAction = new QAction(QIcon(":/icons/options"), tr("&Options..."), this); optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin")); optionsAction->setMenuRole(QAction::PreferencesRole); - if (!fIsTestnet) - toggleHideAction = new QAction(QIcon(":/icons/bitcoin"), tr("&Show / Hide"), this); - else - toggleHideAction = new QAction(QIcon(":/icons/bitcoin_testnet"), tr("&Show / Hide"), this); + toggleHideAction = new QAction(networkStyle->getAppIcon(), tr("&Show / Hide"), this); toggleHideAction->setStatusTip(tr("Show or hide the main Window")); encryptWalletAction = new QAction(QIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this); @@ -504,22 +487,13 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled) openAction->setEnabled(enabled); } -void BitcoinGUI::createTrayIcon(bool fIsTestnet) +void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle) { #ifndef Q_OS_MAC trayIcon = new QSystemTrayIcon(this); - - if (!fIsTestnet) - { - trayIcon->setToolTip(tr("Bitcoin Core client")); - trayIcon->setIcon(QIcon(":/icons/bitcoin")); - } - else - { - trayIcon->setToolTip(tr("Bitcoin Core client") + " " + tr("[testnet]")); - trayIcon->setIcon(QIcon(":/icons/bitcoin_testnet")); - } - + QString toolTip = tr("Bitcoin Core client") + " " + networkStyle->getTitleAddText(); + trayIcon->setToolTip(toolTip); + trayIcon->setIcon(networkStyle->getAppIcon()); trayIcon->show(); #endif @@ -661,6 +635,9 @@ void BitcoinGUI::setNumConnections(int count) void BitcoinGUI::setNumBlocks(int count) { + if(!clientModel) + return; + // Prevent orphan statusbar messages (e.g. hover Quit in main menu, wait until chain-sync starts -> garbelled text) statusBar()->clearMessage(); @@ -831,7 +808,7 @@ void BitcoinGUI::changeEvent(QEvent *e) #ifndef Q_OS_MAC // Ignored on Mac if(e->type() == QEvent::WindowStateChange) { - if(clientModel && clientModel->getOptionsModel()->getMinimizeToTray()) + if(clientModel && clientModel->getOptionsModel() && clientModel->getOptionsModel()->getMinimizeToTray()) { QWindowStateChangeEvent *wsevt = static_cast<QWindowStateChangeEvent*>(e); if(!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) @@ -846,21 +823,21 @@ void BitcoinGUI::changeEvent(QEvent *e) void BitcoinGUI::closeEvent(QCloseEvent *event) { - if(clientModel) - { #ifndef Q_OS_MAC // Ignored on Mac + if(clientModel && clientModel->getOptionsModel()) + { if(!clientModel->getOptionsModel()->getMinimizeToTray() && !clientModel->getOptionsModel()->getMinimizeOnClose()) { QApplication::quit(); } -#endif } +#endif QMainWindow::closeEvent(event); } #ifdef ENABLE_WALLET -void BitcoinGUI::incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address) +void BitcoinGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address) { // On new transaction, make an info balloon message((amount)<0 ? tr("Sent transaction") : tr("Incoming transaction"), @@ -916,8 +893,7 @@ bool BitcoinGUI::handlePaymentRequest(const SendCoinsRecipient& recipient) gotoSendCoinsPage(); return true; } - else - return false; + return false; } void BitcoinGUI::setEncryptionStatus(int status) diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 30b05cb7d9..f65f0e9137 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -9,6 +9,8 @@ #include "config/bitcoin-config.h" #endif +#include "amount.h" + #include <QLabel> #include <QMainWindow> #include <QMap> @@ -17,6 +19,7 @@ #include <QSystemTrayIcon> class ClientModel; +class NetworkStyle; class Notificator; class OptionsModel; class RPCConsole; @@ -44,7 +47,7 @@ class BitcoinGUI : public QMainWindow public: static const QString DEFAULT_WALLET; - explicit BitcoinGUI(bool fIsTestnet = false, QWidget *parent = 0); + explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0); ~BitcoinGUI(); /** Set the client model. @@ -112,13 +115,13 @@ private: int spinnerFrame; /** Create the main UI actions. */ - void createActions(bool fIsTestnet); + void createActions(const NetworkStyle *networkStyle); /** Create the menu bar and sub-menus. */ void createMenuBar(); /** Create the toolbars */ void createToolBars(); /** Create system tray icon and notification */ - void createTrayIcon(bool fIsTestnet); + void createTrayIcon(const NetworkStyle *networkStyle); /** Create system tray menu (or setup the dock menu) */ void createTrayIconMenu(); @@ -159,7 +162,7 @@ public slots: bool handlePaymentRequest(const SendCoinsRecipient& recipient); /** Show incoming transaction notification for new transactions. */ - void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); #endif private slots: diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp index 3b4b40aae3..25c811183f 100644 --- a/src/qt/bitcoinstrings.cpp +++ b/src/qt/bitcoinstrings.cpp @@ -195,21 +195,11 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet corrupted"), QT_TRANSLATE_NOOP("bitcoin-core", "Error loading wallet.dat: Wallet requires newer version of Bitcoin Core"), QT_TRANSLATE_NOOP("bitcoin-core", "Error opening block database"), QT_TRANSLATE_NOOP("bitcoin-core", "Error"), +QT_TRANSLATE_NOOP("bitcoin-core", "Error: A fatal internal error occured, see debug.log for details"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Disk space is low!"), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Unsupported argument -tor found, use -onion."), QT_TRANSLATE_NOOP("bitcoin-core", "Error: Wallet locked, unable to create transaction!"), -QT_TRANSLATE_NOOP("bitcoin-core", "Error: system error: "), QT_TRANSLATE_NOOP("bitcoin-core", "Failed to listen on any port. Use -listen=0 if you want this."), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block info"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to read block"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to sync block index"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block index"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block info"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write block"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write file info"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write to coin database"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write transaction index"), -QT_TRANSLATE_NOOP("bitcoin-core", "Failed to write undo data"), QT_TRANSLATE_NOOP("bitcoin-core", "Fee (in BTC/kB) to add to transactions you send (default: %s)"), QT_TRANSLATE_NOOP("bitcoin-core", "Force safe mode (default: 0)"), QT_TRANSLATE_NOOP("bitcoin-core", "Generate coins (default: 0)"), @@ -231,6 +221,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount for -paytxfee=<amount>: '%s'") QT_TRANSLATE_NOOP("bitcoin-core", "Invalid amount"), QT_TRANSLATE_NOOP("bitcoin-core", "Invalid netmask specified in -whitelist: '%s'"), QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable blocks in memory (default: %u)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Keep at most <n> unconnectable transactions in memory (default: %u)"), QT_TRANSLATE_NOOP("bitcoin-core", "Limit size of signature cache to <n> entries (default: 50000)"), QT_TRANSLATE_NOOP("bitcoin-core", "Listen for connections on <port> (default: 8333 or testnet: 18333)"), QT_TRANSLATE_NOOP("bitcoin-core", "Loading addresses..."), @@ -245,7 +236,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Need to specify a port with -whitebind: '%s'" QT_TRANSLATE_NOOP("bitcoin-core", "Node relay options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Not enough file descriptors available."), QT_TRANSLATE_NOOP("bitcoin-core", "Only accept block chain matching built-in checkpoints (default: 1)"), -QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (IPv4, IPv6 or Tor)"), +QT_TRANSLATE_NOOP("bitcoin-core", "Only connect to nodes in network <net> (ipv4, ipv6 or onion)"), QT_TRANSLATE_NOOP("bitcoin-core", "Options:"), QT_TRANSLATE_NOOP("bitcoin-core", "Password for JSON-RPC connections"), QT_TRANSLATE_NOOP("bitcoin-core", "Prepend debug output with timestamp (default: 1)"), @@ -282,7 +273,6 @@ QT_TRANSLATE_NOOP("bitcoin-core", "Specify wallet file (within data directory)") QT_TRANSLATE_NOOP("bitcoin-core", "Specify your own public address"), QT_TRANSLATE_NOOP("bitcoin-core", "Spend unconfirmed change when sending transactions (default: 1)"), QT_TRANSLATE_NOOP("bitcoin-core", "Stop running after importing blocks from disk (default: 0)"), -QT_TRANSLATE_NOOP("bitcoin-core", "System error: "), QT_TRANSLATE_NOOP("bitcoin-core", "This help message"), QT_TRANSLATE_NOOP("bitcoin-core", "This is experimental software."), QT_TRANSLATE_NOOP("bitcoin-core", "This is intended for regression testing tools and app development."), diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 3215363fa0..423b559bf7 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -91,12 +91,13 @@ int BitcoinUnits::decimals(int unit) } } -QString BitcoinUnits::format(int unit, qint64 n, bool fPlus, SeparatorStyle separators) +QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. if(!valid(unit)) return QString(); // Refuse to format invalid unit + qint64 n = (qint64)nIn; qint64 coin = factor(unit); int num_decimals = decimals(unit); qint64 n_abs = (n > 0 ? n : -n); @@ -138,12 +139,12 @@ QString BitcoinUnits::format(int unit, qint64 n, bool fPlus, SeparatorStyle sepa // Please take care to use formatHtmlWithUnit instead, when // appropriate. -QString BitcoinUnits::formatWithUnit(int unit, qint64 amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { return format(unit, amount, plussign, separators) + QString(" ") + name(unit); } -QString BitcoinUnits::formatHtmlWithUnit(int unit, qint64 amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { QString str(formatWithUnit(unit, amount, plussign, separators)); str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML)); @@ -151,7 +152,7 @@ QString BitcoinUnits::formatHtmlWithUnit(int unit, qint64 amount, bool plussign, } -bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out) +bool BitcoinUnits::parse(int unit, const QString &value, CAmount *val_out) { if(!valid(unit) || value.isEmpty()) return false; // Refuse to parse invalid unit or empty string @@ -182,7 +183,7 @@ bool BitcoinUnits::parse(int unit, const QString &value, qint64 *val_out) { return false; // Longer numbers will exceed 63 bits } - qint64 retvalue = str.toLongLong(&ok); + CAmount retvalue(str.toLongLong(&ok)); if(val_out) { *val_out = retvalue; @@ -226,7 +227,7 @@ QVariant BitcoinUnits::data(const QModelIndex &index, int role) const return QVariant(); } -qint64 BitcoinUnits::maxMoney() +CAmount BitcoinUnits::maxMoney() { return MAX_MONEY; } diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index be9dca6012..a392c42b9b 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -5,6 +5,8 @@ #ifndef BITCOINUNITS_H #define BITCOINUNITS_H +#include "amount.h" + #include <QAbstractListModel> #include <QString> @@ -85,12 +87,12 @@ public: //! Number of decimals left static int decimals(int unit); //! Format as string - static QString format(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard); + static QString format(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); //! Format as string (with unit) - static QString formatWithUnit(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard); - static QString formatHtmlWithUnit(int unit, qint64 amount, bool plussign=false, SeparatorStyle separators=separatorStandard); + static QString formatWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); + static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign=false, SeparatorStyle separators=separatorStandard); //! Parse string to coin amount - static bool parse(int unit, const QString &value, qint64 *val_out); + static bool parse(int unit, const QString &value, CAmount *val_out); //! Gets title for amount column including current display unit if optionsModel reference available */ static QString getAmountColumnTitle(int unit); ///@} @@ -117,7 +119,7 @@ public: } //! Return maximum number of base units (Satoshis) - static qint64 maxMoney(); + static CAmount maxMoney(); private: QList<BitcoinUnits::Unit> unitlist; diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index d10463fd8f..ba0febe546 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -29,7 +29,7 @@ #include <QTreeWidgetItem> using namespace std; -QList<qint64> CoinControlDialog::payAmounts; +QList<CAmount> CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); CoinControlDialog::CoinControlDialog(QWidget *parent) : @@ -443,10 +443,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) return; // nPayAmount - qint64 nPayAmount = 0; + CAmount nPayAmount = 0; bool fDust = false; CMutableTransaction txDummy; - foreach(const qint64 &amount, CoinControlDialog::payAmounts) + foreach(const CAmount &amount, CoinControlDialog::payAmounts) { nPayAmount += amount; @@ -460,10 +460,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) } QString sPriorityLabel = tr("none"); - int64_t nAmount = 0; - int64_t nPayFee = 0; - int64_t nAfterFee = 0; - int64_t nChange = 0; + CAmount nAmount = 0; + CAmount nPayFee = 0; + CAmount nAfterFee = 0; + CAmount nChange = 0; unsigned int nBytes = 0; unsigned int nBytesInputs = 0; double dPriority = 0; @@ -684,7 +684,7 @@ void CoinControlDialog::updateView() itemWalletAddress->setText(COLUMN_ADDRESS, sWalletAddress); } - int64_t nSum = 0; + CAmount nSum = 0; double dPrioritySum = 0; int nChildren = 0; int nInputSum = 0; diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 4f7422642f..9eaa8eb41d 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -5,6 +5,8 @@ #ifndef COINCONTROLDIALOG_H #define COINCONTROLDIALOG_H +#include "amount.h" + #include <QAbstractButton> #include <QAction> #include <QDialog> @@ -14,13 +16,15 @@ #include <QString> #include <QTreeWidgetItem> -namespace Ui { - class CoinControlDialog; -} class WalletModel; + class CCoinControl; class CTxMemPool; +namespace Ui { + class CoinControlDialog; +} + class CoinControlDialog : public QDialog { Q_OBJECT @@ -35,7 +39,7 @@ public: static void updateLabels(WalletModel*, QDialog*); static QString getPriorityLabel(const CTxMemPool& pool, double); - static QList<qint64> payAmounts; + static QList<CAmount> payAmounts; static CCoinControl *coinControl; private: diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index fc22871a6b..91bb10755a 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -221,7 +221,7 @@ QString formatBitcoinURI(const SendCoinsRecipient &info) return ret; } -bool isDust(const QString& address, qint64 amount) +bool isDust(const QString& address, const CAmount& amount) { CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); CScript script = GetScriptForDestination(dest); diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index 67e11e59a0..0939c78f64 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -5,6 +5,8 @@ #ifndef GUIUTIL_H #define GUIUTIL_H +#include "amount.h" + #include <QHeaderView> #include <QMessageBox> #include <QObject> @@ -46,7 +48,7 @@ namespace GUIUtil QString formatBitcoinURI(const SendCoinsRecipient &info); // Returns true if given address+amount meets "dust" definition - bool isDust(const QString& address, qint64 amount); + bool isDust(const QString& address, const CAmount& amount); // HTML escaping for rich text controls QString HtmlEscape(const QString& str, bool fMultiLine=false); diff --git a/src/qt/intro.h b/src/qt/intro.h index 295a75562f..e3e396d369 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -12,7 +12,7 @@ class FreespaceChecker; namespace Ui { -class Intro; + class Intro; } /** Introduction screen (pre-GUI startup). diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts index a527602b5a..5c3abef2e7 100644 --- a/src/qt/locale/bitcoin_en.ts +++ b/src/qt/locale/bitcoin_en.ts @@ -19,7 +19,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+14"/> <source>Copy the currently selected address to the system clipboard</source> <translation>Copy the currently selected address to the system clipboard</translation> </message> @@ -29,7 +29,7 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+58"/> + <location line="+67"/> <source>C&lose</source> <translation type="unfinished"></translation> </message> @@ -39,12 +39,12 @@ <translation>&Copy Address</translation> </message> <message> - <location filename="../forms/addressbookpage.ui" line="-47"/> + <location filename="../forms/addressbookpage.ui" line="-53"/> <source>Delete the currently selected address from the list</source> <translation>Delete the currently selected address from the list</translation> </message> <message> - <location line="+27"/> + <location line="+30"/> <source>Export the data in the current tab to a file</source> <translation>Export the data in the current tab to a file</translation> </message> @@ -54,7 +54,7 @@ <translation>&Export</translation> </message> <message> - <location line="-27"/> + <location line="-30"/> <source>&Delete</source> <translation>&Delete</translation> </message> @@ -286,17 +286,17 @@ <context> <name>BitcoinGUI</name> <message> - <location filename="../bitcoingui.cpp" line="+300"/> + <location filename="../bitcoingui.cpp" line="+327"/> <source>Sign &message...</source> <translation>Sign &message...</translation> </message> <message> - <location line="+339"/> + <location line="+348"/> <source>Synchronizing with network...</source> <translation>Synchronizing with network...</translation> </message> <message> - <location line="-411"/> + <location line="-420"/> <source>&Overview</source> <translation>&Overview</translation> </message> @@ -377,13 +377,13 @@ <translation type="unfinished"></translation> </message> <message> - <location line="+168"/> + <location line="+175"/> <location line="+5"/> <source>Bitcoin Core client</source> <translation type="unfinished"></translation> </message> <message> - <location line="+156"/> + <location line="+158"/> <source>Importing blocks from disk...</source> <translation>Importing blocks from disk...</translation> </message> @@ -393,7 +393,7 @@ <translation>Reindexing blocks on disk...</translation> </message> <message> - <location line="-409"/> + <location line="-418"/> <source>Send coins to a Bitcoin address</source> <translation>Send coins to a Bitcoin address</translation> </message> @@ -428,12 +428,12 @@ <translation>&Verify message...</translation> </message> <message> - <location line="+437"/> + <location line="+446"/> <source>Bitcoin</source> <translation>Bitcoin</translation> </message> <message> - <location line="-655"/> + <location line="-664"/> <source>Wallet</source> <translation>Wallet</translation> </message> @@ -500,12 +500,12 @@ </message> <message> <location line="-289"/> - <location line="+386"/> + <location line="+393"/> <source>[testnet]</source> <translation>[testnet]</translation> </message> <message> - <location line="-411"/> + <location line="-418"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -546,7 +546,7 @@ <translation type="unfinished"></translation> </message> <message numerus="yes"> - <location line="+310"/> + <location line="+316"/> <source>%n active connection(s) to Bitcoin network</source> <translation> <numerusform>%n active connection to Bitcoin network</numerusform> @@ -554,7 +554,7 @@ </translation> </message> <message> - <location line="+22"/> + <location line="+25"/> <source>No block source available...</source> <translation>No block source available...</translation> </message> @@ -665,7 +665,7 @@ Address: %4 </translation> </message> <message> - <location line="+69"/> + <location line="+68"/> <source>Wallet is <b>encrypted</b> and currently <b>unlocked</b></source> <translation>Wallet is <b>encrypted</b> and currently <b>unlocked</b></translation> </message> @@ -678,7 +678,7 @@ Address: %4 <context> <name>ClientModel</name> <message> - <location filename="../clientmodel.cpp" line="+138"/> + <location filename="../clientmodel.cpp" line="+139"/> <source>Network Alert</source> <translation>Network Alert</translation> </message> @@ -736,7 +736,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+16"/> <source>Tree mode</source> <translation type="unfinished"></translation> </message> @@ -1059,7 +1059,7 @@ Address: %4 <context> <name>HelpMessageDialog</name> <message> - <location filename="../utilitydialog.cpp" line="+29"/> + <location filename="../utilitydialog.cpp" line="+31"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -1201,7 +1201,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+11"/> + <location line="+10"/> <source>Select payment request file</source> <translation type="unfinished"></translation> </message> @@ -1430,12 +1430,12 @@ Address: %4 <translation>&OK</translation> </message> <message> - <location line="+7"/> + <location line="+13"/> <source>&Cancel</source> <translation>&Cancel</translation> </message> <message> - <location filename="../optionsdialog.cpp" line="+68"/> + <location filename="../optionsdialog.cpp" line="+71"/> <source>default</source> <translation>default</translation> </message> @@ -1479,23 +1479,18 @@ Address: %4 <translation>Form</translation> </message> <message> - <location line="+52"/> - <location line="+394"/> + <location line="+53"/> + <location line="+372"/> <source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source> <translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation> </message> <message> - <location line="-401"/> - <source>Wallet</source> - <translation>Wallet</translation> - </message> - <message> - <location line="+33"/> + <location line="-133"/> <source>Watch-only:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+43"/> + <location line="+10"/> <source>Available:</source> <translation type="unfinished"></translation> </message> @@ -1505,62 +1500,72 @@ Address: %4 <translation>Your current spendable balance</translation> </message> <message> - <location line="+16"/> + <location line="+41"/> <source>Pending:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+16"/> + <location line="-236"/> <source>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</source> <translation>Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance</translation> </message> <message> - <location line="+16"/> + <location line="+112"/> <source>Immature:</source> <translation>Immature:</translation> </message> <message> - <location line="+16"/> + <location line="-29"/> <source>Mined balance that has not yet matured</source> <translation>Mined balance that has not yet matured</translation> </message> <message> - <location line="+23"/> + <location line="-163"/> + <source>Balances</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+147"/> <source>Total:</source> <translation>Total:</translation> </message> <message> - <location line="+16"/> + <location line="+61"/> <source>Your current total balance</source> <translation>Your current total balance</translation> </message> <message> - <location line="+38"/> + <location line="+92"/> <source>Your current balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+23"/> + <source>Spendable:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+49"/> + <source>Recent transactions</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="-317"/> <source>Unconfirmed transactions to watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+25"/> + <location line="+50"/> <source>Mined balance in watch-only addresses that has not yet matured</source> <translation type="unfinished"></translation> </message> <message> - <location line="+44"/> + <location line="+128"/> <source>Current total balance in watch-only addresses</source> <translation type="unfinished"></translation> </message> <message> - <location line="+67"/> - <source><b>Recent transactions</b></source> - <translation><b>Recent transactions</b></translation> - </message> - <message> - <location filename="../overviewpage.cpp" line="+123"/> + <location filename="../overviewpage.cpp" line="+131"/> <location line="+1"/> <source>out of sync</source> <translation>out of sync</translation> @@ -1569,7 +1574,7 @@ Address: %4 <context> <name>PaymentServer</name> <message> - <location filename="../paymentserver.cpp" line="+405"/> + <location filename="../paymentserver.cpp" line="+410"/> <location line="+14"/> <location line="+7"/> <source>URI handling</source> @@ -1681,7 +1686,7 @@ Address: %4 <context> <name>PeerTableModel</name> <message> - <location filename="../peertablemodel.cpp" line="+112"/> + <location filename="../peertablemodel.cpp" line="+118"/> <source>User Agent</source> <translation type="unfinished"></translation> </message> @@ -1699,17 +1704,17 @@ Address: %4 <context> <name>QObject</name> <message> - <location filename="../bitcoinunits.cpp" line="+200"/> + <location filename="../bitcoinunits.cpp" line="+196"/> <source>Amount</source> <translation type="unfinished">Amount</translation> </message> <message> - <location filename="../guiutil.cpp" line="+97"/> + <location filename="../guiutil.cpp" line="+106"/> <source>Enter a Bitcoin address (e.g. %1)</source> <translation type="unfinished"></translation> </message> <message> - <location line="+673"/> + <location line="+698"/> <source>%1 d</source> <translation type="unfinished"></translation> </message> @@ -1795,7 +1800,7 @@ Address: %4 <location line="+23"/> <location line="+36"/> <location line="+23"/> - <location line="+462"/> + <location line="+465"/> <location line="+23"/> <location line="+23"/> <location line="+23"/> @@ -1813,7 +1818,7 @@ Address: %4 <translation>N/A</translation> </message> <message> - <location line="-987"/> + <location line="-990"/> <source>Client version</source> <translation>Client version</translation> </message> @@ -1873,7 +1878,7 @@ Address: %4 <translation>Current number of blocks</translation> </message> <message> - <location line="+300"/> + <location line="+303"/> <source>Received</source> <translation type="unfinished"></translation> </message> @@ -1889,7 +1894,7 @@ Address: %4 </message> <message> <location line="+39"/> - <location filename="../rpcconsole.cpp" line="+234"/> + <location filename="../rpcconsole.cpp" line="+236"/> <location line="+327"/> <source>Select a peer to view detailed information.</source> <translation type="unfinished"></translation> @@ -1965,7 +1970,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="-761"/> + <location line="-764"/> <source>Last block time</source> <translation>Last block time</translation> </message> @@ -1990,7 +1995,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+13"/> + <location line="+16"/> <source>Totals</source> <translation type="unfinished"></translation> </message> @@ -2005,7 +2010,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location filename="../forms/rpcconsole.ui" line="-354"/> + <location filename="../forms/rpcconsole.ui" line="-357"/> <source>Build date</source> <translation>Build date</translation> </message> @@ -2163,12 +2168,12 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+78"/> + <location line="+75"/> <source>Requested payments history</source> <translation type="unfinished"></translation> </message> <message> - <location line="-98"/> + <location line="-95"/> <source>&Request payment</source> <translation type="unfinished"></translation> </message> @@ -2183,7 +2188,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+17"/> <source>Remove the selected entries from the list</source> <translation type="unfinished"></translation> </message> @@ -2221,12 +2226,12 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>Copy &Address</source> <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>&Save Image...</source> <translation type="unfinished"></translation> </message> @@ -2279,7 +2284,7 @@ Address: %4 <context> <name>RecentRequestsTableModel</name> <message> - <location filename="../recentrequeststablemodel.cpp" line="+24"/> + <location filename="../recentrequeststablemodel.cpp" line="+26"/> <source>Date</source> <translation type="unfinished">Date</translation> </message> @@ -2333,7 +2338,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+7"/> + <location line="+10"/> <source>automatically selected</source> <translation type="unfinished"></translation> </message> @@ -2398,22 +2403,22 @@ Address: %4 <translation>Add &Recipient</translation> </message> <message> - <location line="-23"/> + <location line="-20"/> <source>Clear all fields of the form.</source> <translation type="unfinished"></translation> </message> <message> - <location line="-271"/> + <location line="-274"/> <source>Dust:</source> <translation type="unfinished"></translation> </message> <message> - <location line="+274"/> + <location line="+277"/> <source>Clear &All</source> <translation>Clear &All</translation> </message> <message> - <location line="+58"/> + <location line="+55"/> <source>Balance:</source> <translation>Balance:</translation> </message> @@ -2653,7 +2658,7 @@ Address: %4 <context> <name>ShutdownWindow</name> <message> - <location filename="../utilitydialog.cpp" line="+51"/> + <location filename="../utilitydialog.cpp" line="+47"/> <source>Bitcoin Core is shutting down...</source> <translation type="unfinished"></translation> </message> @@ -2671,7 +2676,7 @@ Address: %4 <translation>Signatures - Sign / Verify a Message</translation> </message> <message> - <location line="+10"/> + <location line="+13"/> <source>&Sign Message</source> <translation>&Sign Message</translation> </message> @@ -2848,7 +2853,7 @@ Address: %4 <context> <name>SplashScreen</name> <message> - <location filename="../splashscreen.cpp" line="+32"/> + <location filename="../splashscreen.cpp" line="+34"/> <source>Bitcoin Core</source> <translation type="unfinished">Bitcoin Core</translation> </message> @@ -2874,7 +2879,7 @@ Address: %4 <context> <name>TransactionDesc</name> <message> - <location filename="../transactiondesc.cpp" line="+33"/> + <location filename="../transactiondesc.cpp" line="+34"/> <source>Open until %1</source> <translation>Open until %1</translation> </message> @@ -3098,7 +3103,7 @@ Address: %4 <context> <name>TransactionTableModel</name> <message> - <location filename="../transactiontablemodel.cpp" line="+237"/> + <location filename="../transactiontablemodel.cpp" line="+235"/> <source>Date</source> <translation>Date</translation> </message> @@ -3166,7 +3171,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="+51"/> + <location line="+48"/> <source>Received with</source> <translation>Received with</translation> </message> @@ -3191,12 +3196,17 @@ Address: %4 <translation>Mined</translation> </message> <message> - <location line="+41"/> + <location line="+28"/> + <source>watch-only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+15"/> <source>(n/a)</source> <translation>(n/a)</translation> </message> <message> - <location line="+193"/> + <location line="+210"/> <source>Transaction status. Hover over this field to show number of confirmations.</source> <translation>Transaction status. Hover over this field to show number of confirmations.</translation> </message> @@ -3212,6 +3222,11 @@ Address: %4 </message> <message> <location line="+2"/> + <source>Whether or not a watch-only address is involved in this transaction.</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+2"/> <source>Destination address of transaction.</source> <translation>Destination address of transaction.</translation> </message> @@ -3224,7 +3239,7 @@ Address: %4 <context> <name>TransactionView</name> <message> - <location filename="../transactionview.cpp" line="+60"/> + <location filename="../transactionview.cpp" line="+67"/> <location line="+16"/> <source>All</source> <translation>All</translation> @@ -3325,12 +3340,17 @@ Address: %4 <translation>Show transaction details</translation> </message> <message> - <location line="+163"/> + <location line="+179"/> <source>Export Transaction History</source> <translation type="unfinished"></translation> </message> <message> - <location line="+19"/> + <location line="+12"/> + <source>Watch-only</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+9"/> <source>Exporting Failed</source> <translation type="unfinished"></translation> </message> @@ -3350,7 +3370,7 @@ Address: %4 <translation type="unfinished"></translation> </message> <message> - <location line="-22"/> + <location line="-24"/> <source>Comma separated file (*.csv)</source> <translation>Comma separated file (*.csv)</translation> </message> @@ -3360,7 +3380,7 @@ Address: %4 <translation>Confirmed</translation> </message> <message> - <location line="+1"/> + <location line="+3"/> <source>Date</source> <translation>Date</translation> </message> @@ -3398,7 +3418,7 @@ Address: %4 <context> <name>UnitDisplayStatusBarControl</name> <message> - <location filename="../bitcoingui.cpp" line="+101"/> + <location filename="../bitcoingui.cpp" line="+103"/> <source>Unit to show amounts in. Click to select another unit.</source> <translation type="unfinished"></translation> </message> @@ -3465,7 +3485,7 @@ Address: %4 <context> <name>bitcoin-core</name> <message> - <location filename="../bitcoinstrings.cpp" line="+249"/> + <location filename="../bitcoinstrings.cpp" line="+240"/> <source>Options:</source> <translation>Options:</translation> </message> @@ -3495,22 +3515,22 @@ Address: %4 <translation>Maintain at most <n> connections to peers (default: 125)</translation> </message> <message> - <location line="-62"/> + <location line="-53"/> <source>Connect to a node to retrieve peer addresses, and disconnect</source> <translation>Connect to a node to retrieve peer addresses, and disconnect</translation> </message> <message> - <location line="+103"/> + <location line="+94"/> <source>Specify your own public address</source> <translation>Specify your own public address</translation> </message> <message> - <location line="+7"/> + <location line="+6"/> <source>Threshold for disconnecting misbehaving peers (default: 100)</source> <translation>Threshold for disconnecting misbehaving peers (default: 100)</translation> </message> <message> - <location line="-181"/> + <location line="-171"/> <source>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</source> <translation>Number of seconds to keep misbehaving peers from reconnecting (default: 86400)</translation> </message> @@ -3525,17 +3545,17 @@ Address: %4 <translation>Accept command line and JSON-RPC commands</translation> </message> <message> - <location line="+99"/> + <location line="+90"/> <source>Run in the background as a daemon and accept commands</source> <translation>Run in the background as a daemon and accept commands</translation> </message> <message> - <location line="+36"/> + <location line="+35"/> <source>Use the test network</source> <translation>Use the test network</translation> </message> <message> - <location line="-134"/> + <location line="-124"/> <source>Accept connections from outside (default: 1 if no -proxy or -connect)</source> <translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation> </message> @@ -3756,6 +3776,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <location line="+2"/> + <source>Error: A fatal internal error occured, see debug.log for details</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Error: Disk space is low!</source> <translation>Error: Disk space is low!</translation> </message> @@ -3766,65 +3791,10 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <location line="+1"/> - <source>Error: system error: </source> - <translation>Error: system error: </translation> - </message> - <message> - <location line="+1"/> <source>Failed to listen on any port. Use -listen=0 if you want this.</source> <translation>Failed to listen on any port. Use -listen=0 if you want this.</translation> </message> <message> - <location line="+1"/> - <source>Failed to read block info</source> - <translation>Failed to read block info</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to read block</source> - <translation>Failed to read block</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to sync block index</source> - <translation>Failed to sync block index</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write block index</source> - <translation>Failed to write block index</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write block info</source> - <translation>Failed to write block info</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write block</source> - <translation>Failed to write block</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write file info</source> - <translation>Failed to write file info</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write to coin database</source> - <translation>Failed to write to coin database</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write transaction index</source> - <translation>Failed to write transaction index</translation> - </message> - <message> - <location line="+1"/> - <source>Failed to write undo data</source> - <translation>Failed to write undo data</translation> - </message> - <message> <location line="+2"/> <source>Force safe mode (default: 0)</source> <translation type="unfinished"></translation> @@ -3860,12 +3830,17 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation type="unfinished"></translation> </message> <message> - <location line="+21"/> + <location line="+22"/> <source>Not enough file descriptors available.</source> <translation>Not enough file descriptors available.</translation> </message> <message> - <location line="+5"/> + <location line="+2"/> + <source>Only connect to nodes in network <net> (ipv4, ipv6 or onion)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+3"/> <source>Prepend debug output with timestamp (default: 1)</source> <translation type="unfinished"></translation> </message> @@ -3905,7 +3880,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+3"/> <source>This is intended for regression testing tools and app development.</source> <translation type="unfinished"></translation> </message> @@ -3940,7 +3915,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Imports blocks from external blk000??.dat file</translation> </message> <message> - <location line="-195"/> + <location line="-185"/> <source>(default: 1, 1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)</source> <translation type="unfinished"></translation> </message> @@ -4080,12 +4055,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation type="unfinished"></translation> </message> <message> - <location line="+4"/> + <location line="+5"/> <source>Error: Unsupported argument -tor found, use -onion.</source> <translation type="unfinished"></translation> </message> <message> - <location line="+14"/> + <location line="+3"/> <source>Fee (in BTC/kB) to add to transactions you send (default: %s)</source> <translation type="unfinished"></translation> </message> @@ -4131,6 +4106,11 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. </message> <message> <location line="+1"/> + <source>Keep at most <n> unconnectable transactions in memory (default: %u)</source> + <translation type="unfinished"></translation> + </message> + <message> + <location line="+1"/> <source>Limit size of signature cache to <n> entries (default: 50000)</source> <translation type="unfinished"></translation> </message> @@ -4170,12 +4150,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Only accept block chain matching built-in checkpoints (default: 1)</translation> </message> <message> - <location line="+1"/> - <source>Only connect to nodes in network <net> (IPv4, IPv6 or Tor)</source> - <translation>Only connect to nodes in network <net> (IPv4, IPv6 or Tor)</translation> - </message> - <message> - <location line="+4"/> + <location line="+5"/> <source>Print block on startup, if found in block index</source> <translation type="unfinished"></translation> </message> @@ -4255,12 +4230,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Specify connection timeout in milliseconds (default: 5000)</translation> </message> <message> - <location line="+7"/> - <source>System error: </source> - <translation>System error: </translation> - </message> - <message> - <location line="+2"/> + <location line="+8"/> <source>This is experimental software.</source> <translation type="unfinished"></translation> </message> @@ -4340,22 +4310,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>wallet.dat corrupt, salvage failed</translation> </message> <message> - <location line="-64"/> + <location line="-63"/> <source>Password for JSON-RPC connections</source> <translation>Password for JSON-RPC connections</translation> </message> <message> - <location line="-164"/> + <location line="-155"/> <source>Execute command when the best block changes (%s in cmd is replaced by block hash)</source> <translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation> </message> <message> - <location line="+210"/> + <location line="+200"/> <source>Upgrade wallet to latest format</source> <translation>Upgrade wallet to latest format</translation> </message> <message> - <location line="-27"/> + <location line="-26"/> <source>Set key pool size to <n> (default: 100)</source> <translation>Set key pool size to <n> (default: 100)</translation> </message> @@ -4365,12 +4335,12 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Rescan the block chain for missing wallet transactions</translation> </message> <message> - <location line="+36"/> + <location line="+35"/> <source>Use OpenSSL (https) for JSON-RPC connections</source> <translation>Use OpenSSL (https) for JSON-RPC connections</translation> </message> <message> - <location line="-31"/> + <location line="-30"/> <source>Server certificate file (default: server.cert)</source> <translation>Server certificate file (default: server.cert)</translation> </message> @@ -4380,22 +4350,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Server private key (default: server.pem)</translation> </message> <message> - <location line="+19"/> + <location line="+18"/> <source>This help message</source> <translation>This help message</translation> </message> <message> - <location line="-118"/> + <location line="-108"/> <source>Allow DNS lookups for -addnode, -seednode and -connect</source> <translation>Allow DNS lookups for -addnode, -seednode and -connect</translation> </message> <message> - <location line="+68"/> + <location line="+59"/> <source>Loading addresses...</source> <translation>Loading addresses...</translation> </message> <message> - <location line="-42"/> + <location line="-33"/> <source>Error loading wallet.dat: Wallet corrupted</source> <translation>Error loading wallet.dat: Wallet corrupted</translation> </message> @@ -4405,7 +4375,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Error loading wallet.dat</translation> </message> <message> - <location line="+33"/> + <location line="+23"/> <source>Invalid -proxy address: '%s'</source> <translation>Invalid -proxy address: '%s'</translation> </message> @@ -4415,7 +4385,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Unknown network specified in -onlynet: '%s'</translation> </message> <message> - <location line="-122"/> + <location line="-112"/> <source>Cannot resolve -bind address: '%s'</source> <translation>Cannot resolve -bind address: '%s'</translation> </message> @@ -4425,7 +4395,7 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot resolve -externalip address: '%s'</translation> </message> <message> - <location line="+56"/> + <location line="+46"/> <source>Invalid amount for -paytxfee=<amount>: '%s'</source> <translation>Invalid amount for -paytxfee=<amount>: '%s'</translation> </message> @@ -4440,22 +4410,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Insufficient funds</translation> </message> <message> - <location line="+13"/> + <location line="+14"/> <source>Loading block index...</source> <translation>Loading block index...</translation> </message> <message> - <location line="-70"/> + <location line="-61"/> <source>Add a node to connect to and attempt to keep the connection open</source> <translation>Add a node to connect to and attempt to keep the connection open</translation> </message> <message> - <location line="+71"/> + <location line="+62"/> <source>Loading wallet...</source> <translation>Loading wallet...</translation> </message> <message> - <location line="-66"/> + <location line="-57"/> <source>Cannot downgrade wallet</source> <translation>Cannot downgrade wallet</translation> </message> @@ -4465,22 +4435,22 @@ for example: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo. <translation>Cannot write default address</translation> </message> <message> - <location line="+86"/> + <location line="+77"/> <source>Rescanning...</source> <translation>Rescanning...</translation> </message> <message> - <location line="-73"/> + <location line="-64"/> <source>Done loading</source> <translation>Done loading</translation> </message> <message> - <location line="+101"/> + <location line="+91"/> <source>To use the %s option</source> <translation>To use the %s option</translation> </message> <message> - <location line="-93"/> + <location line="-83"/> <source>Error</source> <translation>Error</translation> </message> diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp new file mode 100644 index 0000000000..62c44703f4 --- /dev/null +++ b/src/qt/networkstyle.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "networkstyle.h" + +#include "guiconstants.h" + +#include <QApplication> + +static const struct { + const char *networkId; + const char *appName; + const char *appIcon; + const char *titleAddText; + const char *splashImage; +} network_styles[] = { + {"main", QAPP_APP_NAME_DEFAULT, ":/icons/bitcoin", "", ":/images/splash"}, + {"test", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", QT_TRANSLATE_NOOP("SplashScreen", "[testnet]"), ":/images/splash_testnet"}, + {"regtest", QAPP_APP_NAME_TESTNET, ":/icons/bitcoin_testnet", "[regtest]", ":/images/splash_testnet"} +}; +static const unsigned network_styles_count = sizeof(network_styles)/sizeof(*network_styles); + +// titleAddText needs to be const char* for tr() +NetworkStyle::NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage): + appName(appName), + appIcon(appIcon), + titleAddText(qApp->translate("SplashScreen", titleAddText)), + splashImage(splashImage) +{ +} + +const NetworkStyle *NetworkStyle::instantiate(const QString &networkId) +{ + for (unsigned x=0; x<network_styles_count; ++x) + { + if (networkId == network_styles[x].networkId) + { + return new NetworkStyle( + network_styles[x].appName, + network_styles[x].appIcon, + network_styles[x].titleAddText, + network_styles[x].splashImage); + } + } + return 0; +} diff --git a/src/qt/networkstyle.h b/src/qt/networkstyle.h new file mode 100644 index 0000000000..99304d61a3 --- /dev/null +++ b/src/qt/networkstyle.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef H_NETWORKSTYLE +#define H_NETWORKSTYLE + +#include <QIcon> +#include <QPixmap> +#include <QString> + +/* Coin network-specific GUI style information */ +class NetworkStyle +{ +public: + /** Get style associated with provided BIP70 network id, or 0 if not known */ + static const NetworkStyle *instantiate(const QString &networkId); + + const QString &getAppName() const { return appName; } + const QIcon &getAppIcon() const { return appIcon; } + const QString &getTitleAddText() const { return titleAddText; } + const QPixmap &getSplashImage() const { return splashImage; } + +private: + NetworkStyle(const QString &appName, const QString &appIcon, const char *titleAddText, const QString &splashImage); + + QString appName; + QIcon appIcon; + QString titleAddText; + QPixmap splashImage; +}; + +#endif // H_NETWORKSTYLE diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index 28da7d6d9d..67a5f167d1 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -8,7 +8,7 @@ #include <QDialog> namespace Ui { -class OpenURIDialog; + class OpenURIDialog; } class OpenURIDialog : public QDialog diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index c775a7f8d6..279467129f 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -17,11 +17,13 @@ #include "main.h" // for MAX_SCRIPTCHECK_THREADS #include "netbase.h" #include "txdb.h" // for -dbcache defaults + #ifdef ENABLE_WALLET #include "wallet.h" // for CWallet::minTxFee #endif #include <boost/thread.hpp> + #include <QDir> #include <QIntValidator> #include <QLocale> diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 99928ebe4d..6db654dff7 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -15,6 +15,7 @@ #include "main.h" #include "net.h" #include "txdb.h" // for -dbcache defaults + #ifdef ENABLE_WALLET #include "wallet.h" #include "walletdb.h" @@ -118,6 +119,8 @@ void OptionsModel::Init() // Only try to set -proxy, if user has enabled fUseProxy if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString())) addOverriddenOption("-proxy"); + else if(!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty()) + addOverriddenOption("-proxy"); // Display if (!settings.contains("language")) @@ -274,9 +277,9 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in #ifdef ENABLE_WALLET case Fee: { // core option - can be changed on-the-fly // Todo: Add is valid check and warn via message, if not - qint64 nTransactionFee = value.toLongLong(); + CAmount nTransactionFee(value.toLongLong()); payTxFee = CFeeRate(nTransactionFee, 1000); - settings.setValue("nTransactionFee", nTransactionFee); + settings.setValue("nTransactionFee", qint64(nTransactionFee)); emit transactionFeeChanged(nTransactionFee); break; } diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 80adab89c8..42ea3bf8e5 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -5,6 +5,8 @@ #ifndef OPTIONSMODEL_H #define OPTIONSMODEL_H +#include "amount.h" + #include <QAbstractListModel> QT_BEGIN_NAMESPACE @@ -82,7 +84,7 @@ private: signals: void displayUnitChanged(int unit); - void transactionFeeChanged(qint64); + void transactionFeeChanged(const CAmount&); void coinControlFeaturesChanged(bool); }; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 90762bea5d..669d5474fd 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -146,7 +146,7 @@ OverviewPage::~OverviewPage() delete ui; } -void OverviewPage::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance) +void OverviewPage::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance) { int unit = walletModel->getOptionsModel()->getDisplayUnit(); currentBalance = balance; @@ -220,7 +220,7 @@ void OverviewPage::setWalletModel(WalletModel *model) // Keep up to date with wallet setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64))); + connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h index f46374efba..03f239008f 100644 --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -5,6 +5,8 @@ #ifndef OVERVIEWPAGE_H #define OVERVIEWPAGE_H +#include "amount.h" + #include <QWidget> class ClientModel; @@ -34,8 +36,8 @@ public: void showOutOfSyncWarning(bool fShow); public slots: - void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, - qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance); + void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); signals: void transactionClicked(const QModelIndex &index); @@ -44,12 +46,12 @@ private: Ui::OverviewPage *ui; ClientModel *clientModel; WalletModel *walletModel; - qint64 currentBalance; - qint64 currentUnconfirmedBalance; - qint64 currentImmatureBalance; - qint64 currentWatchOnlyBalance; - qint64 currentWatchUnconfBalance; - qint64 currentWatchImmatureBalance; + CAmount currentBalance; + CAmount currentUnconfirmedBalance; + CAmount currentImmatureBalance; + CAmount currentWatchOnlyBalance; + CAmount currentWatchUnconfBalance; + CAmount currentWatchImmatureBalance; TxViewDelegate *txdelegate; TransactionFilterProxy *filter; diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp index acce42e203..7aefffe24a 100644 --- a/src/qt/paymentrequestplus.cpp +++ b/src/qt/paymentrequestplus.cpp @@ -13,6 +13,7 @@ #include <openssl/x509.h> #include <openssl/x509_vfy.h> + #include <QDateTime> #include <QDebug> #include <QSslCertificate> @@ -195,9 +196,9 @@ bool PaymentRequestPlus::getMerchant(X509_STORE* certStore, QString& merchant) c return fResult; } -QList<std::pair<CScript,qint64> > PaymentRequestPlus::getPayTo() const +QList<std::pair<CScript,CAmount> > PaymentRequestPlus::getPayTo() const { - QList<std::pair<CScript,qint64> > result; + QList<std::pair<CScript,CAmount> > result; for (int i = 0; i < details.outputs_size(); i++) { const unsigned char* scriptStr = (const unsigned char*)details.outputs(i).script().data(); diff --git a/src/qt/paymentrequestplus.h b/src/qt/paymentrequestplus.h index 3c4861a4d4..3d94d93269 100644 --- a/src/qt/paymentrequestplus.h +++ b/src/qt/paymentrequestplus.h @@ -33,7 +33,7 @@ public: bool getMerchant(X509_STORE* certStore, QString& merchant) const; // Returns list of outputs, amount - QList<std::pair<CScript,qint64> > getPayTo() const; + QList<std::pair<CScript,CAmount> > getPayTo() const; const payments::PaymentDetails& getDetails() const { return details; } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index cc4478f39f..707de55290 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -532,10 +532,10 @@ bool PaymentServer::processPaymentRequest(PaymentRequestPlus& request, SendCoins request.getMerchant(PaymentServer::certStore, recipient.authenticatedMerchant); - QList<std::pair<CScript, qint64> > sendingTos = request.getPayTo(); + QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo(); QStringList addresses; - foreach(const PAIRTYPE(CScript, qint64)& sendingTo, sendingTos) { + foreach(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) { // Extract and check destination addresses CTxDestination dest; if (ExtractDestination(sendingTo.first, dest)) { diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h index 663cb157a4..7a7e38e25e 100644 --- a/src/qt/receivecoinsdialog.h +++ b/src/qt/receivecoinsdialog.h @@ -5,6 +5,8 @@ #ifndef RECEIVECOINSDIALOG_H #define RECEIVECOINSDIALOG_H +#include "guiutil.h" + #include <QDialog> #include <QHeaderView> #include <QItemSelection> @@ -13,13 +15,12 @@ #include <QPoint> #include <QVariant> -#include "guiutil.h" +class OptionsModel; +class WalletModel; namespace Ui { class ReceiveCoinsDialog; } -class OptionsModel; -class WalletModel; QT_BEGIN_NAMESPACE class QModelIndex; diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index 11089b2497..8129353d4b 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -16,10 +16,12 @@ #include "util.h" #include "json/json_spirit_value.h" + +#include <openssl/crypto.h> + #ifdef ENABLE_WALLET #include <db_cxx.h> #endif -#include <openssl/crypto.h> #include <QKeyEvent> #include <QScrollBar> diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h index 64bb5c29b3..1ffff92758 100644 --- a/src/qt/rpcconsole.h +++ b/src/qt/rpcconsole.h @@ -14,14 +14,14 @@ class ClientModel; -QT_BEGIN_NAMESPACE -class QItemSelection; -QT_END_NAMESPACE - namespace Ui { class RPCConsole; } +QT_BEGIN_NAMESPACE +class QItemSelection; +QT_END_NAMESPACE + /** Local Bitcoin RPC console. */ class RPCConsole: public QDialog { diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 25e3d2a0dc..ce94131cce 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -92,13 +92,13 @@ void SendCoinsDialog::setModel(WalletModel *model) setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getWatchBalance(), model->getWatchUnconfirmedBalance(), model->getWatchImmatureBalance()); - connect(model, SIGNAL(balanceChanged(qint64, qint64, qint64, qint64, qint64, qint64)), this, SLOT(setBalance(qint64, qint64, qint64, qint64, qint64, qint64))); + connect(model, SIGNAL(balanceChanged(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount)), this, SLOT(setBalance(CAmount,CAmount,CAmount,CAmount,CAmount,CAmount))); connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); // Coin Control connect(model->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(coinControlUpdateLabels())); connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); - connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(qint64)), this, SLOT(coinControlUpdateLabels())); + connect(model->getOptionsModel(), SIGNAL(transactionFeeChanged(CAmount)), this, SLOT(coinControlUpdateLabels())); ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); coinControlUpdateLabels(); } @@ -203,7 +203,7 @@ void SendCoinsDialog::on_sendButton_clicked() return; } - qint64 txFee = currentTransaction.getTransactionFee(); + CAmount txFee = currentTransaction.getTransactionFee(); QString questionString = tr("Are you sure you want to send?"); questionString.append("<br /><br />%1"); @@ -218,7 +218,7 @@ void SendCoinsDialog::on_sendButton_clicked() // add total amount in all subdivision units questionString.append("<hr />"); - qint64 totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; + CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee; QStringList alternativeUnits; foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits()) { @@ -384,8 +384,8 @@ bool SendCoinsDialog::handlePaymentRequest(const SendCoinsRecipient &rv) return true; } -void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, - qint64 watchBalance, qint64 watchUnconfirmedBalance, qint64 watchImmatureBalance) +void SendCoinsDialog::setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& watchBalance, const CAmount& watchUnconfirmedBalance, const CAmount& watchImmatureBalance) { Q_UNUSED(unconfirmedBalance); Q_UNUSED(immatureBalance); diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 6cdf4a00c8..74cc4bde56 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -14,14 +14,14 @@ class OptionsModel; class SendCoinsEntry; class SendCoinsRecipient; -QT_BEGIN_NAMESPACE -class QUrl; -QT_END_NAMESPACE - namespace Ui { class SendCoinsDialog; } +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + /** Dialog for sending bitcoins */ class SendCoinsDialog : public QDialog { @@ -47,8 +47,8 @@ public slots: void accept(); SendCoinsEntry *addEntry(); void updateTabsAndLabels(); - void setBalance(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, - qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance); + void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); private: Ui::SendCoinsDialog *ui; diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 5dd110b36a..b4b81440ca 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -4,23 +4,25 @@ #include "splashscreen.h" -#include "version.h" #include "clientversion.h" #include "init.h" +#include "networkstyle.h" #include "ui_interface.h" #include "util.h" +#include "version.h" + #ifdef ENABLE_WALLET #include "wallet.h" #endif #include <QApplication> +#include <QCloseEvent> +#include <QDesktopWidget> #include <QPainter> -SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet) : - QSplashScreen(pixmap, f) +SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) : + QWidget(0, f), curAlignment(0) { - setAutoFillBackground(true); - // set reference point, paddings int paddingRight = 50; int paddingTop = 50; @@ -33,20 +35,14 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTest QString titleText = tr("Bitcoin Core"); QString versionText = QString("Version %1").arg(QString::fromStdString(FormatFullVersion())); QString copyrightText = QChar(0xA9)+QString(" 2009-%1 ").arg(COPYRIGHT_YEAR) + QString(tr("The Bitcoin Core developers")); - QString testnetAddText = QString(tr("[testnet]")); // define text to place as single text object + QString titleAddText = networkStyle->getTitleAddText(); QString font = "Arial"; // load the bitmap for writing some text over it - QPixmap newPixmap; - if(isTestNet) { - newPixmap = QPixmap(":/images/splash_testnet"); - } - else { - newPixmap = QPixmap(":/images/splash"); - } + pixmap = networkStyle->getSplashImage(); - QPainter pixPaint(&newPixmap); + QPainter pixPaint(&pixmap); pixPaint.setPen(QColor(100,100,100)); // check font size and drawing with @@ -61,7 +57,7 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTest pixPaint.setFont(QFont(font, 33*fontFactor)); fm = pixPaint.fontMetrics(); titleTextWidth = fm.width(titleText); - pixPaint.drawText(newPixmap.width()-titleTextWidth-paddingRight,paddingTop,titleText); + pixPaint.drawText(pixmap.width()-titleTextWidth-paddingRight,paddingTop,titleText); pixPaint.setFont(QFont(font, 15*fontFactor)); @@ -72,25 +68,32 @@ SplashScreen::SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTest pixPaint.setFont(QFont(font, 10*fontFactor)); titleVersionVSpace -= 5; } - pixPaint.drawText(newPixmap.width()-titleTextWidth-paddingRight+2,paddingTop+titleVersionVSpace,versionText); + pixPaint.drawText(pixmap.width()-titleTextWidth-paddingRight+2,paddingTop+titleVersionVSpace,versionText); // draw copyright stuff pixPaint.setFont(QFont(font, 10*fontFactor)); - pixPaint.drawText(newPixmap.width()-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText); + pixPaint.drawText(pixmap.width()-titleTextWidth-paddingRight,paddingTop+titleCopyrightVSpace,copyrightText); - // draw testnet string if testnet is on - if(isTestNet) { + // draw additional text if special network + if(!titleAddText.isEmpty()) { QFont boldFont = QFont(font, 10*fontFactor); boldFont.setWeight(QFont::Bold); pixPaint.setFont(boldFont); fm = pixPaint.fontMetrics(); - int testnetAddTextWidth = fm.width(testnetAddText); - pixPaint.drawText(newPixmap.width()-testnetAddTextWidth-10,15,testnetAddText); + int titleAddTextWidth = fm.width(titleAddText); + pixPaint.drawText(pixmap.width()-titleAddTextWidth-10,15,titleAddText); } pixPaint.end(); - this->setPixmap(newPixmap); + // Set window title + setWindowTitle(titleText + " " + titleAddText); + + // Resize window and move to center of desktop, disallow resizing + QRect r(QPoint(), pixmap.size()); + resize(r.size()); + setFixedSize(r.size()); + move(QApplication::desktop()->screenGeometry().center() - r.center()); subscribeToCoreSignals(); } @@ -102,7 +105,8 @@ SplashScreen::~SplashScreen() void SplashScreen::slotFinish(QWidget *mainWin) { - finish(mainWin); + Q_UNUSED(mainWin); + hide(); } static void InitMessage(SplashScreen *splash, const std::string &message) @@ -146,3 +150,26 @@ void SplashScreen::unsubscribeFromCoreSignals() pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); #endif } + +void SplashScreen::showMessage(const QString &message, int alignment, const QColor &color) +{ + curMessage = message; + curAlignment = alignment; + curColor = color; + update(); +} + +void SplashScreen::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.drawPixmap(0, 0, pixmap); + QRect r = rect().adjusted(5, 5, -5, -5); + painter.setPen(curColor); + painter.drawText(r, curAlignment, curMessage); +} + +void SplashScreen::closeEvent(QCloseEvent *event) +{ + StartShutdown(); // allows an "emergency" shutdown during startup + event->ignore(); +} diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index d79038d81d..128edadbee 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -7,25 +7,43 @@ #include <QSplashScreen> -/** class for the splashscreen with information of the running client +class NetworkStyle; + +/** Class for the splashscreen with information of the running client. + * + * @note this is intentionally not a QSplashScreen. Bitcoin Core initialization + * can take a long time, and in that case a progress window that cannot be + * moved around and minimized has turned out to be frustrating to the user. */ -class SplashScreen : public QSplashScreen +class SplashScreen : public QWidget { Q_OBJECT public: - explicit SplashScreen(const QPixmap &pixmap, Qt::WindowFlags f, bool isTestNet); + explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle); ~SplashScreen(); +protected: + void paintEvent(QPaintEvent *event); + void closeEvent(QCloseEvent *event); + public slots: /** Slot to call finish() method as it's not defined as slot */ void slotFinish(QWidget *mainWin); + /** Show message and progress */ + void showMessage(const QString &message, int alignment, const QColor &color); + private: /** Connect core signals to splash screen */ void subscribeToCoreSignals(); /** Disconnect core signals to splash screen */ void unsubscribeFromCoreSignals(); + + QPixmap pixmap; + QString curMessage; + QColor curColor; + int curAlignment; }; #endif // SPLASHSCREEN_H diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp index 727b8dc66d..1efad8259b 100644 --- a/src/qt/transactiondesc.cpp +++ b/src/qt/transactiondesc.cpp @@ -6,13 +6,13 @@ #include "bitcoinunits.h" #include "guiutil.h" +#include "paymentserver.h" +#include "transactionrecord.h" #include "base58.h" #include "db.h" #include "main.h" -#include "paymentserver.h" #include "script/script.h" -#include "transactionrecord.h" #include "timedata.h" #include "ui_interface.h" #include "util.h" @@ -56,9 +56,9 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>"; int64_t nTime = wtx.GetTxTime(); - int64_t nCredit = wtx.GetCredit(ISMINE_ALL); - int64_t nDebit = wtx.GetDebit(ISMINE_ALL); - int64_t nNet = nCredit - nDebit; + CAmount nCredit = wtx.GetCredit(ISMINE_ALL); + CAmount nDebit = wtx.GetDebit(ISMINE_ALL); + CAmount nNet = nCredit - nDebit; strHTML += "<b>" + tr("Status") + ":</b> " + FormatTxStatus(wtx); int nRequests = wtx.GetRequestCount(); @@ -132,7 +132,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco // // Coinbase // - int64_t nUnmatured = 0; + CAmount nUnmatured = 0; BOOST_FOREACH(const CTxOut& txout, wtx.vout) nUnmatured += wallet->GetCredit(txout, ISMINE_ALL); strHTML += "<b>" + tr("Credit") + ":</b> "; @@ -206,13 +206,13 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco if (fAllToMe) { // Payment to self - int64_t nChange = wtx.GetChange(); - int64_t nValue = nCredit - nChange; + CAmount nChange = wtx.GetChange(); + CAmount nValue = nCredit - nChange; strHTML += "<b>" + tr("Total debit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nValue) + "<br>"; strHTML += "<b>" + tr("Total credit") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, nValue) + "<br>"; } - int64_t nTxFee = nDebit - wtx.GetValueOut(); + CAmount nTxFee = nDebit - wtx.GetValueOut(); if (nTxFee > 0) strHTML += "<b>" + tr("Transaction fee") + ":</b> " + BitcoinUnits::formatHtmlWithUnit(unit, -nTxFee) + "<br>"; } diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 6ab029173b..2a0f621d1e 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -78,7 +78,7 @@ void TransactionFilterProxy::setTypeFilter(quint32 modes) invalidateFilter(); } -void TransactionFilterProxy::setMinAmount(qint64 minimum) +void TransactionFilterProxy::setMinAmount(const CAmount& minimum) { this->minAmount = minimum; invalidateFilter(); diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index f408317b53..ca31ee8f87 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -5,6 +5,8 @@ #ifndef TRANSACTIONFILTERPROXY_H #define TRANSACTIONFILTERPROXY_H +#include "amount.h" + #include <QDateTime> #include <QSortFilterProxyModel> @@ -38,7 +40,7 @@ public: @note Type filter takes a bit field created with TYPE() or ALL_TYPES */ void setTypeFilter(quint32 modes); - void setMinAmount(qint64 minimum); + void setMinAmount(const CAmount& minimum); void setWatchOnlyFilter(WatchOnlyFilter filter); /** Set maximum number of rows returned, -1 if unlimited. */ @@ -58,7 +60,7 @@ private: QString addrPrefix; quint32 typeFilter; WatchOnlyFilter watchOnlyFilter; - qint64 minAmount; + CAmount minAmount; int limitRows; bool showInactive; }; diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 20c1449c92..5278c8673a 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -32,9 +32,9 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); - int64_t nCredit = wtx.GetCredit(true); - int64_t nDebit = wtx.GetDebit(ISMINE_ALL); - int64_t nNet = nCredit - nDebit; + CAmount nCredit = wtx.GetCredit(ISMINE_ALL); + CAmount nDebit = wtx.GetDebit(ISMINE_ALL); + CAmount nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; @@ -97,7 +97,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * if (fAllFromMe && fAllToMe) { // Payment to self - int64_t nChange = wtx.GetChange(); + CAmount nChange = wtx.GetChange(); parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); @@ -108,7 +108,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * // // Debit // - int64_t nTxFee = nDebit - wtx.GetValueOut(); + CAmount nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { @@ -138,7 +138,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet * sub.address = mapValue["to"]; } - int64_t nValue = txout.nValue; + CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index 626b7654c6..9276c9f0af 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -5,6 +5,7 @@ #ifndef TRANSACTIONRECORD_H #define TRANSACTIONRECORD_H +#include "amount.h" #include "uint256.h" #include <QList> @@ -94,7 +95,7 @@ public: TransactionRecord(uint256 hash, qint64 time, Type type, const std::string &address, - qint64 debit, qint64 credit): + const CAmount& debit, const CAmount& credit): hash(hash), time(time), type(type), address(address), debit(debit), credit(credit), idx(0) { @@ -111,8 +112,8 @@ public: qint64 time; Type type; std::string address; - qint64 debit; - qint64 credit; + CAmount debit; + CAmount credit; /**@}*/ /** Subtransaction index, for sort key */ diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 2b869b4ea5..e34d776818 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -546,7 +546,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case ToAddress: return formatTxToAddress(rec, true); case Amount: - return rec->credit + rec->debit; + return qint64(rec->credit + rec->debit); } break; case Qt::ToolTipRole: @@ -583,7 +583,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const case LabelRole: return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address)); case AmountRole: - return rec->credit + rec->debit; + return qint64(rec->credit + rec->debit); case TxIDRole: return rec->getTxID(); case TxHashRole: diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp index a7ba100cd2..d153973872 100644 --- a/src/qt/transactionview.cpp +++ b/src/qt/transactionview.cpp @@ -304,7 +304,7 @@ void TransactionView::changedAmount(const QString &amount) { if(!transactionProxyModel) return; - qint64 amount_parsed = 0; + CAmount amount_parsed = 0; if(BitcoinUnits::parse(model->getOptionsModel()->getDisplayUnit(), amount, &amount_parsed)) { transactionProxyModel->setMinAmount(amount_parsed); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 7df9d1bc2d..84f88dff5a 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -15,6 +15,7 @@ #include <stdio.h> +#include <QCloseEvent> #include <QLabel> #include <QRegExp> #include <QVBoxLayout> @@ -106,18 +107,26 @@ void HelpMessageDialog::on_okButton_accepted() /** "Shutdown" window */ +ShutdownWindow::ShutdownWindow(QWidget *parent, Qt::WindowFlags f): + QWidget(parent, f) +{ + QVBoxLayout *layout = new QVBoxLayout(); + layout->addWidget(new QLabel( + tr("Bitcoin Core is shutting down...") + "<br /><br />" + + tr("Do not shut down the computer until this window disappears."))); + setLayout(layout); +} + void ShutdownWindow::showShutdownWindow(BitcoinGUI *window) { if (!window) return; // Show a simple window indicating shutdown status - QWidget *shutdownWindow = new QWidget(); - QVBoxLayout *layout = new QVBoxLayout(); - layout->addWidget(new QLabel( - tr("Bitcoin Core is shutting down...") + "<br /><br />" + - tr("Do not shut down the computer until this window disappears."))); - shutdownWindow->setLayout(layout); + QWidget *shutdownWindow = new ShutdownWindow(); + // We don't hold a direct pointer to the shutdown window after creation, so use + // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. + shutdownWindow->setAttribute(Qt::WA_DeleteOnClose); shutdownWindow->setWindowTitle(window->windowTitle()); // Center shutdown window at where main window was @@ -125,3 +134,8 @@ void ShutdownWindow::showShutdownWindow(BitcoinGUI *window) shutdownWindow->move(global.x() - shutdownWindow->width() / 2, global.y() - shutdownWindow->height() / 2); shutdownWindow->show(); } + +void ShutdownWindow::closeEvent(QCloseEvent *event) +{ + event->ignore(); +} diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 154bb70b8b..ae5045cca9 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -37,12 +37,16 @@ private slots: /** "Shutdown" window */ -class ShutdownWindow : public QObject +class ShutdownWindow : public QWidget { Q_OBJECT public: + ShutdownWindow(QWidget *parent=0, Qt::WindowFlags f=0); static void showShutdownWindow(BitcoinGUI *window); + +protected: + void closeEvent(QCloseEvent *event); }; #endif // UTILITYDIALOG_H diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index ed90914ba7..b4733d369e 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -55,11 +55,11 @@ WalletModel::~WalletModel() unsubscribeFromCoreSignals(); } -qint64 WalletModel::getBalance(const CCoinControl *coinControl) const +CAmount WalletModel::getBalance(const CCoinControl *coinControl) const { if (coinControl) { - qint64 nBalance = 0; + CAmount nBalance = 0; std::vector<COutput> vCoins; wallet->AvailableCoins(vCoins, true, coinControl); BOOST_FOREACH(const COutput& out, vCoins) @@ -72,12 +72,12 @@ qint64 WalletModel::getBalance(const CCoinControl *coinControl) const return wallet->GetBalance(); } -qint64 WalletModel::getUnconfirmedBalance() const +CAmount WalletModel::getUnconfirmedBalance() const { return wallet->GetUnconfirmedBalance(); } -qint64 WalletModel::getImmatureBalance() const +CAmount WalletModel::getImmatureBalance() const { return wallet->GetImmatureBalance(); } @@ -87,17 +87,17 @@ bool WalletModel::haveWatchOnly() const return fHaveWatchOnly; } -qint64 WalletModel::getWatchBalance() const +CAmount WalletModel::getWatchBalance() const { return wallet->GetWatchOnlyBalance(); } -qint64 WalletModel::getWatchUnconfirmedBalance() const +CAmount WalletModel::getWatchUnconfirmedBalance() const { return wallet->GetUnconfirmedWatchOnlyBalance(); } -qint64 WalletModel::getWatchImmatureBalance() const +CAmount WalletModel::getWatchImmatureBalance() const { return wallet->GetImmatureWatchOnlyBalance(); } @@ -137,12 +137,12 @@ void WalletModel::pollBalanceChanged() void WalletModel::checkBalanceChanged() { - qint64 newBalance = getBalance(); - qint64 newUnconfirmedBalance = getUnconfirmedBalance(); - qint64 newImmatureBalance = getImmatureBalance(); - qint64 newWatchOnlyBalance = 0; - qint64 newWatchUnconfBalance = 0; - qint64 newWatchImmatureBalance = 0; + CAmount newBalance = getBalance(); + CAmount newUnconfirmedBalance = getUnconfirmedBalance(); + CAmount newImmatureBalance = getImmatureBalance(); + CAmount newWatchOnlyBalance = 0; + CAmount newWatchUnconfBalance = 0; + CAmount newWatchImmatureBalance = 0; if (haveWatchOnly()) { newWatchOnlyBalance = getWatchBalance(); @@ -194,9 +194,9 @@ bool WalletModel::validateAddress(const QString &address) WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction &transaction, const CCoinControl *coinControl) { - qint64 total = 0; + CAmount total = 0; QList<SendCoinsRecipient> recipients = transaction.getRecipients(); - std::vector<std::pair<CScript, int64_t> > vecSend; + std::vector<std::pair<CScript, CAmount> > vecSend; if(recipients.empty()) { @@ -211,7 +211,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact { if (rcp.paymentRequest.IsInitialized()) { // PaymentRequest... - int64_t subtotal = 0; + CAmount subtotal = 0; const payments::PaymentDetails& details = rcp.paymentRequest.getDetails(); for (int i = 0; i < details.outputs_size(); i++) { @@ -220,7 +220,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact subtotal += out.amount(); const unsigned char* scriptStr = (const unsigned char*)out.script().data(); CScript scriptPubKey(scriptStr, scriptStr+out.script().size()); - vecSend.push_back(std::pair<CScript, int64_t>(scriptPubKey, out.amount())); + vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, out.amount())); } if (subtotal <= 0) { @@ -242,7 +242,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact ++nAddresses; CScript scriptPubKey = GetScriptForDestination(CBitcoinAddress(rcp.address.toStdString()).Get()); - vecSend.push_back(std::pair<CScript, int64_t>(scriptPubKey, rcp.amount)); + vecSend.push_back(std::pair<CScript, CAmount>(scriptPubKey, rcp.amount)); total += rcp.amount; } @@ -252,7 +252,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact return DuplicateAddress; } - qint64 nBalance = getBalance(coinControl); + CAmount nBalance = getBalance(coinControl); if(total > nBalance) { @@ -263,7 +263,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact LOCK2(cs_main, wallet->cs_wallet); transaction.newPossibleKeyChange(wallet); - int64_t nFeeRequired = 0; + CAmount nFeeRequired = 0; std::string strFailReason; CWalletTx *newTx = transaction.getTransaction(); @@ -605,7 +605,8 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins) int nDepth = wallet->mapWallet[outpoint.hash].GetDepthInMainChain(); if (nDepth < 0) continue; COutput out(&wallet->mapWallet[outpoint.hash], outpoint.n, nDepth, true); - vCoins.push_back(out); + if (outpoint.n < out.tx->vout.size() && wallet->IsMine(out.tx->vout[outpoint.n]) == ISMINE_SPENDABLE) + vCoins.push_back(out); } BOOST_FOREACH(const COutput& out, vCoins) diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 111ae2178c..b1d0f28f12 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -37,7 +37,7 @@ class SendCoinsRecipient { public: explicit SendCoinsRecipient() : amount(0), nVersion(SendCoinsRecipient::CURRENT_VERSION) { } - explicit SendCoinsRecipient(const QString &addr, const QString &label, quint64 amount, const QString &message): + explicit SendCoinsRecipient(const QString &addr, const QString &label, const CAmount& amount, const QString &message): address(addr), label(label), amount(amount), message(message), nVersion(SendCoinsRecipient::CURRENT_VERSION) {} // If from an insecure payment request, this is used for storing @@ -47,7 +47,7 @@ public: // Todo: This is a hack, should be replaced with a cleaner solution! QString address; QString label; - qint64 amount; + CAmount amount; // If from a payment request, this is used for storing the memo QString message; @@ -125,13 +125,13 @@ public: TransactionTableModel *getTransactionTableModel(); RecentRequestsTableModel *getRecentRequestsTableModel(); - qint64 getBalance(const CCoinControl *coinControl = NULL) const; - qint64 getUnconfirmedBalance() const; - qint64 getImmatureBalance() const; + CAmount getBalance(const CCoinControl *coinControl = NULL) const; + CAmount getUnconfirmedBalance() const; + CAmount getImmatureBalance() const; bool haveWatchOnly() const; - qint64 getWatchBalance() const; - qint64 getWatchUnconfirmedBalance() const; - qint64 getWatchImmatureBalance() const; + CAmount getWatchBalance() const; + CAmount getWatchUnconfirmedBalance() const; + CAmount getWatchImmatureBalance() const; EncryptionStatus getEncryptionStatus() const; bool processingQueuedTransactions() { return fProcessingQueuedTransactions; } @@ -210,12 +210,12 @@ private: RecentRequestsTableModel *recentRequestsTableModel; // Cache some values to be able to detect changes - qint64 cachedBalance; - qint64 cachedUnconfirmedBalance; - qint64 cachedImmatureBalance; - qint64 cachedWatchOnlyBalance; - qint64 cachedWatchUnconfBalance; - qint64 cachedWatchImmatureBalance; + CAmount cachedBalance; + CAmount cachedUnconfirmedBalance; + CAmount cachedImmatureBalance; + CAmount cachedWatchOnlyBalance; + CAmount cachedWatchUnconfBalance; + CAmount cachedWatchImmatureBalance; EncryptionStatus cachedEncryptionStatus; int cachedNumBlocks; @@ -227,8 +227,8 @@ private: signals: // Signal that balance in wallet changed - void balanceChanged(qint64 balance, qint64 unconfirmedBalance, qint64 immatureBalance, - qint64 watchOnlyBalance, qint64 watchUnconfBalance, qint64 watchImmatureBalance); + void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); // Encryption status of wallet changed void encryptionStatusChanged(int status); diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 943f13e208..ddd2d09bb5 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -31,19 +31,19 @@ CWalletTx *WalletModelTransaction::getTransaction() return walletTransaction; } -qint64 WalletModelTransaction::getTransactionFee() +CAmount WalletModelTransaction::getTransactionFee() { return fee; } -void WalletModelTransaction::setTransactionFee(qint64 newFee) +void WalletModelTransaction::setTransactionFee(const CAmount& newFee) { fee = newFee; } -qint64 WalletModelTransaction::getTotalTransactionAmount() +CAmount WalletModelTransaction::getTotalTransactionAmount() { - qint64 totalTransactionAmount = 0; + CAmount totalTransactionAmount = 0; foreach(const SendCoinsRecipient &rcp, recipients) { totalTransactionAmount += rcp.amount; diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index b7e85bcd11..4eadfbe4d1 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -26,10 +26,10 @@ public: CWalletTx *getTransaction(); - void setTransactionFee(qint64 newFee); - qint64 getTransactionFee(); + void setTransactionFee(const CAmount& newFee); + CAmount getTransactionFee(); - qint64 getTotalTransactionAmount(); + CAmount getTotalTransactionAmount(); void newPossibleKeyChange(CWallet *wallet); CReserveKey *getPossibleKeyChange(); @@ -38,7 +38,7 @@ private: const QList<SendCoinsRecipient> recipients; CWalletTx *walletTransaction; CReserveKey *keyChange; - qint64 fee; + CAmount fee; }; #endif // WALLETMODELTRANSACTION_H diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp index b40ddc0a2f..eff50593bd 100644 --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -92,7 +92,7 @@ void WalletView::setBitcoinGUI(BitcoinGUI *gui) connect(this, SIGNAL(encryptionStatusChanged(int)), gui, SLOT(setEncryptionStatus(int))); // Pass through transaction notifications - connect(this, SIGNAL(incomingTransaction(QString,int,qint64,QString,QString)), gui, SLOT(incomingTransaction(QString,int,qint64,QString,QString))); + connect(this, SIGNAL(incomingTransaction(QString,int,CAmount,QString,QString)), gui, SLOT(incomingTransaction(QString,int,CAmount,QString,QString))); } } diff --git a/src/qt/walletview.h b/src/qt/walletview.h index 9cfa8d6760..cafba517fd 100644 --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -5,6 +5,8 @@ #ifndef WALLETVIEW_H #define WALLETVIEW_H +#include "amount.h" + #include <QStackedWidget> class BitcoinGUI; @@ -111,7 +113,7 @@ signals: /** Encryption status of wallet changed */ void encryptionStatusChanged(int status); /** Notify that a new transaction appeared */ - void incomingTransaction(const QString& date, int unit, qint64 amount, const QString& type, const QString& address); + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); }; #endif // WALLETVIEW_H diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 4b3beae20c..24175215bf 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -381,7 +381,7 @@ Value gettxout(const Array& params, bool fHelp) CCoins coins; if (fMempool) { LOCK(mempool.cs); - CCoinsViewMemPool view(*pcoinsTip, mempool); + CCoinsViewMemPool view(pcoinsTip, mempool); if (!view.GetCoins(hash, coins)) return Value::null; mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp index 1ac7024550..9da0a7d091 100644 --- a/src/rpcdump.cpp +++ b/src/rpcdump.cpp @@ -114,8 +114,6 @@ Value importprivkey(const Array& params, bool fHelp) CPubKey pubkey = key.GetPubKey(); CKeyID vchAddress = pubkey.GetID(); { - LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->MarkDirty(); pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); @@ -181,7 +179,8 @@ Value importaddress(const Array& params, bool fHelp) fRescan = params[2].get_bool(); { - LOCK2(cs_main, pwalletMain->cs_wallet); + if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) + throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); // add to address book or update label if (address.IsValid()) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 82eaf5d037..c767835a27 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -239,7 +239,7 @@ Value getmininginfo(const Array& params, bool fHelp) obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1))); obj.push_back(Pair("networkhashps", getnetworkhashps(params, false))); obj.push_back(Pair("pooledtx", (uint64_t)mempool.size())); - obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET)); + obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); obj.push_back(Pair("chain", Params().NetworkIDString())); #ifdef ENABLE_WALLET obj.push_back(Pair("generate", getgenerate(params, false))); @@ -273,7 +273,7 @@ Value prioritisetransaction(const Array& params, bool fHelp) uint256 hash; hash.SetHex(params[0].get_str()); - int64_t nAmount = 0; + CAmount nAmount = 0; if (params[2].get_real() != 0.0) nAmount = AmountFromValue(params[2]); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index dd45eefd58..8be14b567c 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -87,7 +87,7 @@ Value getinfo(const Array& params, bool fHelp) obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.ToStringIPPort() : string()))); obj.push_back(Pair("difficulty", (double)GetDifficulty())); - obj.push_back(Pair("testnet", Params().NetworkID() == CBaseChainParams::TESTNET)); + obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index 95f42eb47f..bc19d1372a 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -11,6 +11,7 @@ #include "sync.h" #include "timedata.h" #include "util.h" +#include "version.h" #include <boost/foreach.hpp> @@ -367,23 +368,29 @@ Value getnetworkinfo(const Array& params, bool fHelp) "Returns an object containing various state info regarding P2P networking.\n" "\nResult:\n" "{\n" - " \"version\": xxxxx, (numeric) the server version\n" - " \"protocolversion\": xxxxx, (numeric) the protocol version\n" - " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n" - " \"timeoffset\": xxxxx, (numeric) the time offset\n" - " \"connections\": xxxxx, (numeric) the number of connections\n" - " \"networks\": [ (array) information per network\n" - " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n" - " \"limited\": xxx, (boolean) is the network limited using -onlynet?\n" - " \"reachable\": xxx, (boolean) is the network reachable?\n" - " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n" - " },\n" + " \"version\": xxxxx, (numeric) the server version\n" + " \"subversion\": \"/Satoshi:x.x.x/\", (string) the server subversion string\n" + " \"protocolversion\": xxxxx, (numeric) the protocol version\n" + " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n" + " \"timeoffset\": xxxxx, (numeric) the time offset\n" + " \"connections\": xxxxx, (numeric) the number of connections\n" + " \"networks\": [ (array) information per network\n" + " {\n" + " \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n" + " \"limited\": true|false, (boolean) is the network limited using -onlynet?\n" + " \"reachable\": true|false, (boolean) is the network reachable?\n" + " \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n" + " }\n" + " ,...\n" " ],\n" - " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n" - " \"localaddresses\": [, (array) list of local addresses\n" - " \"address\": \"xxxx\", (string) network address\n" - " \"port\": xxx, (numeric) network port\n" - " \"score\": xxx (numeric) relative score\n" + " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n" + " \"localaddresses\": [ (array) list of local addresses\n" + " {\n" + " \"address\": \"xxxx\", (string) network address\n" + " \"port\": xxx, (numeric) network port\n" + " \"score\": xxx (numeric) relative score\n" + " }\n" + " ,...\n" " ]\n" "}\n" "\nExamples:\n" @@ -392,8 +399,10 @@ Value getnetworkinfo(const Array& params, bool fHelp) ); Object obj; - obj.push_back(Pair("version", (int)CLIENT_VERSION)); - obj.push_back(Pair("protocolversion",(int)PROTOCOL_VERSION)); + obj.push_back(Pair("version", CLIENT_VERSION)); + obj.push_back(Pair("subversion", + FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()))); + obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); obj.push_back(Pair("timeoffset", GetTimeOffset())); obj.push_back(Pair("connections", (int)vNodes.size())); diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index dbb0966ae2..78372da685 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -110,6 +110,9 @@ Value getrawtransaction(const Array& params, bool fHelp) if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "getrawtransaction \"txid\" ( verbose )\n" + "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" + "or there is an unspent output in the utxo for this transaction. To make it always work,\n" + "you need to maintain a transaction index, using the -txindex command line option.\n" "\nReturn the raw transaction data.\n" "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n" "If verbose is non-zero, returns an Object with information about 'txid'.\n" @@ -202,7 +205,7 @@ Value listunspent(const Array& params, bool fHelp) "Results are an array of Objects, each of which has:\n" "{txid, vout, scriptPubKey, amount, confirmations}\n" "\nArguments:\n" - "1. minconf (numeric, optional, default=1) The minimum confirmationsi to filter\n" + "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" "3. \"addresses\" (string) A json array of bitcoin addresses to filter\n" " [\n" @@ -269,7 +272,7 @@ Value listunspent(const Array& params, bool fHelp) continue; } - int64_t nValue = out.tx->vout[out.i].nValue; + CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; Object entry; entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); @@ -367,7 +370,7 @@ Value createrawtransaction(const Array& params, bool fHelp) setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); - int64_t nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(s.value_); CTxOut out(nAmount, scriptPubKey); rawTx.vout.push_back(out); @@ -557,11 +560,11 @@ Value signrawtransaction(const Array& params, bool fHelp) // Fetch previous transactions (inputs): CCoinsView viewDummy; - CCoinsViewCache view(viewDummy); + CCoinsViewCache view(&viewDummy); { LOCK(mempool.cs); CCoinsViewCache &viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(viewChain, mempool); + CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { @@ -612,21 +615,19 @@ Value signrawtransaction(const Array& params, bool fHelp) vector<unsigned char> pkData(ParseHexO(prevOut, "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); - CCoins coins; - if (view.GetCoins(txid, coins)) { - if (coins.IsAvailable(nOut) && coins.vout[nOut].scriptPubKey != scriptPubKey) { + { + CCoinsModifier coins = view.ModifyCoins(txid); + if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { string err("Previous output scriptPubKey mismatch:\n"); - err = err + coins.vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ + err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ scriptPubKey.ToString(); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); } - // what todo if txid is known, but the actual output isn't? + if ((unsigned int)nOut >= coins->vout.size()) + coins->vout.resize(nOut+1); + coins->vout[nOut].scriptPubKey = scriptPubKey; + coins->vout[nOut].nValue = 0; // we don't know the actual output value } - if ((unsigned int)nOut >= coins.vout.size()) - coins.vout.resize(nOut+1); - coins.vout[nOut].scriptPubKey = scriptPubKey; - coins.vout[nOut].nValue = 0; // we don't know the actual output value - view.SetCoins(txid, coins); // if redeemScript given and not using the local wallet (private keys // given), add redeemScript to the tempKeystore so it can be signed: @@ -687,7 +688,7 @@ Value signrawtransaction(const Array& params, bool fHelp) BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); } - if (!VerifyScript(txin.scriptSig, prevPubKey, mergedTx, i, STANDARD_SCRIPT_VERIFY_FLAGS)) + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(mergedTx, i))) fComplete = false; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 190de62282..1a41344da5 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -88,18 +88,18 @@ static inline int64_t roundint64(double d) return (int64_t)(d > 0 ? d + 0.5 : d - 0.5); } -int64_t AmountFromValue(const Value& value) +CAmount AmountFromValue(const Value& value) { double dAmount = value.get_real(); if (dAmount <= 0.0 || dAmount > 21000000.0) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); - int64_t nAmount = roundint64(dAmount * COIN); + CAmount nAmount = roundint64(dAmount * COIN); if (!MoneyRange(nAmount)) throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount"); return nAmount; } -Value ValueFromAmount(int64_t amount) +Value ValueFromAmount(const CAmount& amount) { return (double)amount / (double)COIN; } diff --git a/src/rpcserver.h b/src/rpcserver.h index 820c1bc081..d440035f15 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -6,6 +6,7 @@ #ifndef _BITCOINRPC_SERVER_H_ #define _BITCOINRPC_SERVER_H_ +#include "amount.h" #include "uint256.h" #include "rpcprotocol.h" @@ -116,8 +117,8 @@ extern void InitRPCMining(); extern void ShutdownRPCMining(); extern int64_t nWalletUnlockTime; -extern int64_t AmountFromValue(const json_spirit::Value& value); -extern json_spirit::Value ValueFromAmount(int64_t amount); +extern CAmount AmountFromValue(const json_spirit::Value& value); +extern json_spirit::Value ValueFromAmount(const CAmount& amount); extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern std::string HelpRequiringPassphrase(); extern std::string HelpExampleCli(std::string methodname, std::string args); diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 35637362a4..d11455e389 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -230,15 +230,20 @@ Value setaccount(const Array& params, bool fHelp) if (params.size() > 1) strAccount = AccountFromValue(params[1]); - // Detect when changing the account of an address that is the 'unused current key' of another account: - if (pwalletMain->mapAddressBook.count(address.Get())) + // Only add the account if the address is yours. + if (IsMine(*pwalletMain, address.Get())) { - string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; - if (address == GetAccountAddress(strOldAccount)) - GetAccountAddress(strOldAccount, true); + // Detect when changing the account of an address that is the 'unused current key' of another account: + if (pwalletMain->mapAddressBook.count(address.Get())) + { + string strOldAccount = pwalletMain->mapAddressBook[address.Get()].name; + if (address == GetAccountAddress(strOldAccount)) + GetAccountAddress(strOldAccount, true); + } + pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); } - - pwalletMain->SetAddressBook(address.Get(), strAccount, "receive"); + else + throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address"); return Value::null; } @@ -331,7 +336,7 @@ Value sendtoaddress(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); // Amount - int64_t nAmount = AmountFromValue(params[1]); + CAmount nAmount = AmountFromValue(params[1]); // Wallet comments CWalletTx wtx; @@ -375,7 +380,7 @@ Value listaddressgroupings(const Array& params, bool fHelp) ); Array jsonGroupings; - map<CTxDestination, int64_t> balances = pwalletMain->GetAddressBalances(); + map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances(); BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings()) { Array jsonGrouping; @@ -483,7 +488,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp) nMinDepth = params[1].get_int(); // Tally - int64_t nAmount = 0; + CAmount nAmount = 0; for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; @@ -532,7 +537,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) set<CTxDestination> setAddress = pwalletMain->GetAccountAddresses(strAccount); // Tally - int64_t nAmount = 0; + CAmount nAmount = 0; for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; @@ -552,9 +557,9 @@ Value getreceivedbyaccount(const Array& params, bool fHelp) } -int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) +CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMinDepth, const isminefilter& filter) { - int64_t nBalance = 0; + CAmount nBalance = 0; // Tally wallet transactions for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) @@ -563,7 +568,7 @@ int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0) continue; - int64_t nReceived, nSent, nFee; + CAmount nReceived, nSent, nFee; wtx.GetAccountAmounts(strAccount, nReceived, nSent, nFee, filter); if (nReceived != 0 && wtx.GetDepthInMainChain() >= nMinDepth) @@ -577,7 +582,7 @@ int64_t GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi return nBalance; } -int64_t GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) +CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminefilter& filter) { CWalletDB walletdb(pwalletMain->strWalletFile); return GetAccountBalance(walletdb, strAccount, nMinDepth, filter); @@ -627,14 +632,14 @@ Value getbalance(const Array& params, bool fHelp) // Calculate total balance a different way from GetBalance() // (GetBalance() sums up all unspent TxOuts) // getbalance and getbalance '*' 0 should return the same number - int64_t nBalance = 0; + CAmount nBalance = 0; for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0) continue; - int64_t allFee; + CAmount allFee; string strSentAccount; list<COutputEntry> listReceived; list<COutputEntry> listSent; @@ -653,7 +658,7 @@ Value getbalance(const Array& params, bool fHelp) string strAccount = AccountFromValue(params[0]); - int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, filter); + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, filter); return ValueFromAmount(nBalance); } @@ -692,7 +697,7 @@ Value movecmd(const Array& params, bool fHelp) string strFrom = AccountFromValue(params[0]); string strTo = AccountFromValue(params[1]); - int64_t nAmount = AmountFromValue(params[2]); + CAmount nAmount = AmountFromValue(params[2]); if (params.size() > 3) // unused parameter, used to be nMinDepth, keep type-checking it though (void)params[3].get_int(); @@ -766,7 +771,7 @@ Value sendfrom(const Array& params, bool fHelp) CBitcoinAddress address(params[1].get_str()); if (!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); - int64_t nAmount = AmountFromValue(params[2]); + CAmount nAmount = AmountFromValue(params[2]); int nMinDepth = 1; if (params.size() > 3) nMinDepth = params[3].get_int(); @@ -781,7 +786,7 @@ Value sendfrom(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); if (nAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); @@ -834,9 +839,9 @@ Value sendmany(const Array& params, bool fHelp) wtx.mapValue["comment"] = params[3].get_str(); set<CBitcoinAddress> setAddress; - vector<pair<CScript, int64_t> > vecSend; + vector<pair<CScript, CAmount> > vecSend; - int64_t totalAmount = 0; + CAmount totalAmount = 0; BOOST_FOREACH(const Pair& s, sendTo) { CBitcoinAddress address(s.name_); @@ -848,7 +853,7 @@ Value sendmany(const Array& params, bool fHelp) setAddress.insert(address); CScript scriptPubKey = GetScriptForDestination(address.Get()); - int64_t nAmount = AmountFromValue(s.value_); + CAmount nAmount = AmountFromValue(s.value_); totalAmount += nAmount; vecSend.push_back(make_pair(scriptPubKey, nAmount)); @@ -857,13 +862,13 @@ Value sendmany(const Array& params, bool fHelp) EnsureWalletIsUnlocked(); // Check funds - int64_t nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); + CAmount nBalance = GetAccountBalance(strAccount, nMinDepth, ISMINE_SPENDABLE); if (totalAmount > nBalance) throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds"); // Send CReserveKey keyChange(pwalletMain); - int64_t nFeeRequired = 0; + CAmount nFeeRequired = 0; string strFailReason; bool fCreated = pwalletMain->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, strFailReason); if (!fCreated) @@ -923,7 +928,7 @@ Value addmultisigaddress(const Array& params, bool fHelp) struct tallyitem { - int64_t nAmount; + CAmount nAmount; int nConf; vector<uint256> txids; bool fIsWatchonly; @@ -995,7 +1000,7 @@ Value ListReceived(const Array& params, bool fByAccounts) if (it == mapTally.end() && !fIncludeEmpty) continue; - int64_t nAmount = 0; + CAmount nAmount = 0; int nConf = std::numeric_limits<int>::max(); bool fIsWatchonly = false; if (it != mapTally.end()) @@ -1038,7 +1043,7 @@ Value ListReceived(const Array& params, bool fByAccounts) { for (map<string, tallyitem>::iterator it = mapAccountTally.begin(); it != mapAccountTally.end(); ++it) { - int64_t nAmount = (*it).second.nAmount; + CAmount nAmount = (*it).second.nAmount; int nConf = (*it).second.nConf; Object obj; if((*it).second.fIsWatchonly) @@ -1125,7 +1130,7 @@ static void MaybePushAddress(Object & entry, const CTxDestination &dest) void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter) { - int64_t nFee; + CAmount nFee; string strSentAccount; list<COutputEntry> listReceived; list<COutputEntry> listSent; @@ -1355,7 +1360,7 @@ Value listaccounts(const Array& params, bool fHelp) if(params[1].get_bool()) includeWatchonly = includeWatchonly | ISMINE_WATCH_ONLY; - map<string, int64_t> mapAccountBalances; + map<string, CAmount> mapAccountBalances; BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& entry, pwalletMain->mapAddressBook) { if (IsMine(*pwalletMain, entry.first) & includeWatchonly) // This address belongs to me mapAccountBalances[entry.second.name] = 0; @@ -1364,7 +1369,7 @@ Value listaccounts(const Array& params, bool fHelp) for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { const CWalletTx& wtx = (*it).second; - int64_t nFee; + CAmount nFee; string strSentAccount; list<COutputEntry> listReceived; list<COutputEntry> listSent; @@ -1391,7 +1396,7 @@ Value listaccounts(const Array& params, bool fHelp) mapAccountBalances[entry.strAccount] += entry.nCreditDebit; Object ret; - BOOST_FOREACH(const PAIRTYPE(string, int64_t)& accountBalance, mapAccountBalances) { + BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) { ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second))); } return ret; @@ -1534,10 +1539,10 @@ Value gettransaction(const Array& params, bool fHelp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id"); const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - int64_t nCredit = wtx.GetCredit(filter != 0); - int64_t nDebit = wtx.GetDebit(filter); - int64_t nNet = nCredit - nDebit; - int64_t nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0); + CAmount nCredit = wtx.GetCredit(filter); + CAmount nDebit = wtx.GetDebit(filter); + CAmount nNet = nCredit - nDebit; + CAmount nFee = (wtx.IsFromMe(filter) ? wtx.GetValueOut() - nDebit : 0); entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee))); if (wtx.IsFromMe(filter)) @@ -1937,7 +1942,7 @@ Value settxfee(const Array& params, bool fHelp) ); // Amount - int64_t nAmount = 0; + CAmount nAmount = 0; if (params[0].get_real() != 0.0) nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index fd3e4f1ff7..ae66217b7c 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -9,14 +9,10 @@ #include "crypto/ripemd160.h" #include "crypto/sha1.h" #include "crypto/sha2.h" -#include "random.h" #include "script/script.h" #include "uint256.h" #include "util.h" -#include <boost/thread.hpp> -#include <boost/tuple/tuple_comparison.hpp> - using namespace std; typedef vector<unsigned char> valtype; @@ -56,10 +52,7 @@ static inline void popstack(vector<valtype>& stack) stack.pop_back(); } -bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - +bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { if (vchPubKey.size() < 33) return error("Non-canonical public key: too short"); if (vchPubKey[0] == 0x04) { @@ -74,10 +67,7 @@ bool IsCanonicalPubKey(const valtype &vchPubKey, unsigned int flags) { return true; } -bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { - if (!(flags & SCRIPT_VERIFY_STRICTENC)) - return true; - +bool static IsDERSignature(const valtype &vchSig) { // See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 // A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype> // Where R and S are not negative (their first byte has its highest bit not set), and not @@ -87,9 +77,6 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { return error("Non-canonical signature: too short"); if (vchSig.size() > 73) return error("Non-canonical signature: too long"); - unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); - if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) - return error("Non-canonical signature: unknown hashtype byte"); if (vchSig[0] != 0x30) return error("Non-canonical signature: wrong type"); if (vchSig[1] != vchSig.size()-3) @@ -121,18 +108,55 @@ bool IsCanonicalSignature(const valtype &vchSig, unsigned int flags) { if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return error("Non-canonical signature: S value excessively padded"); - if (flags & SCRIPT_VERIFY_LOW_S) { - // If the S value is above the order of the curve divided by two, its - // complement modulo the order could have been used instead, which is - // one byte shorter when encoded correctly. - if (!CKey::CheckSignatureElement(S, nLenS, true)) - return error("Non-canonical signature: S value is unnecessarily high"); + return true; +} + +bool static IsLowDERSignature(const valtype &vchSig) { + if (!IsDERSignature(vchSig)) { + return false; } + unsigned int nLenR = vchSig[3]; + unsigned int nLenS = vchSig[5+nLenR]; + const unsigned char *S = &vchSig[6+nLenR]; + // If the S value is above the order of the curve divided by two, its + // complement modulo the order could have been used instead, which is + // one byte shorter when encoded correctly. + if (!CKey::CheckSignatureElement(S, nLenS, true)) + return error("Non-canonical signature: S value is unnecessarily high"); + + return true; +} + +bool static IsDefinedHashtypeSignature(const valtype &vchSig) { + if (vchSig.size() == 0) { + return false; + } + unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); + if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) + return error("Non-canonical signature: unknown hashtype byte"); + + return true; +} + +bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) { + if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) { + return false; + } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) { + return false; + } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) { + return false; + } + return true; +} +bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) { + if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) { + return false; + } return true; } -bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) { CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); @@ -637,19 +661,19 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) - CRIPEMD160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_SHA1) - CSHA1().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_SHA256) - CSHA256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_HASH160) - CHash160().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); else if (opcode == OP_HASH256) - CHash256().Write(&vch[0], vch.size()).Finalize(&vchHash[0]); + CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash)); popstack(stack); stack.push_back(vchHash); } - break; + break; case OP_CODESEPARATOR: { @@ -674,8 +698,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); - bool fSuccess = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + if (!CheckSignatureEncoding(vchSig, flags)) { + return false; + } + + bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode); popstack(stack); popstack(stack); @@ -734,9 +761,12 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, co valtype& vchSig = stacktop(-isig); valtype& vchPubKey = stacktop(-ikey); + if (!CheckSignatureEncoding(vchSig, flags)) { + return false; + } + // Check signature - bool fOk = IsCanonicalSignature(vchSig, flags) && IsCanonicalPubKey(vchPubKey, flags) && - CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, flags); + bool fOk = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode); if (fOk) { isig++; @@ -839,7 +869,8 @@ public: itBegin = it; } } - s.write((char*)&itBegin[0], it-itBegin); + if (itBegin != scriptCode.end()) + s.write((char*)&itBegin[0], it-itBegin); } /** Serialize an input of txTo */ @@ -896,7 +927,7 @@ public: } // anon namespace -uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) +uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) { if (nIn >= txTo.vin.size()) { LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); @@ -920,70 +951,19 @@ uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -// Valid signature cache, to avoid doing expensive ECDSA signature checking -// twice for every transaction (once when accepted into memory pool, and -// again when accepted into the block chain) -class CSignatureCache +bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { -private: - // sigdata_type is (signature hash, signature, public key): - typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; - std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; - -public: - bool - Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); - - sigdata_type k(hash, vchSig, pubKey); - std::set<sigdata_type>::iterator mi = setValid.find(k); - if (mi != setValid.end()) - return true; - return false; - } - - void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) - { - // DoS prevention: limit cache size to less than 10MB - // (~200 bytes per cache entry times 50,000 entries) - // Since there are a maximum of 20,000 signature operations per block - // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); - if (nMaxCacheSize <= 0) return; - - boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); - - while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) - { - // Evict a random entry. Random because that helps - // foil would-be DoS attackers who might try to pre-generate - // and re-use a set of valid signatures just-slightly-greater - // than our cache size. - uint256 randomHash = GetRandHash(); - std::vector<unsigned char> unused; - std::set<sigdata_type>::iterator it = - setValid.lower_bound(sigdata_type(randomHash, unused, unused)); - if (it == setValid.end()) - it = setValid.begin(); - setValid.erase(*it); - } - - sigdata_type k(hash, vchSig, pubKey); - setValid.insert(k); - } -}; + return pubkey.Verify(sighash, vchSig); +} -bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubKey, const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int flags) +bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const { - static CSignatureCache signatureCache; - CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) return false; // Hash type is one byte tacked on to the end of the signature + vector<unsigned char> vchSig(vchSigIn); if (vchSig.empty()) return false; int nHashType = vchSig.back(); @@ -991,26 +971,20 @@ bool CheckSig(vector<unsigned char> vchSig, const vector<unsigned char>& vchPubK uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); - if (signatureCache.Get(sighash, vchSig, pubkey)) - return true; - - if (!pubkey.Verify(sighash, vchSig)) + if (!VerifySignature(vchSig, pubkey, sighash)) return false; - if (!(flags & SCRIPT_VERIFY_NOCACHE)) - signatureCache.Set(sighash, vchSig, pubkey); - return true; } -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags) +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker) { vector<vector<unsigned char> > stack, stackCopy; - if (!EvalScript(stack, scriptSig, txTo, nIn, flags)) + if (!EvalScript(stack, scriptSig, flags, checker)) return false; if (flags & SCRIPT_VERIFY_P2SH) stackCopy = stack; - if (!EvalScript(stack, scriptPubKey, txTo, nIn, flags)) + if (!EvalScript(stack, scriptPubKey, flags, checker)) return false; if (stack.empty()) return false; @@ -1033,7 +1007,7 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const C CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stackCopy); - if (!EvalScript(stackCopy, pubKey2, txTo, nIn, flags)) + if (!EvalScript(stackCopy, pubKey2, flags, checker)) return false; if (stackCopy.empty()) return false; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index adca2142ac..de5ce2ced1 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -10,6 +10,7 @@ #include <stdint.h> #include <string> +class CPubKey; class CScript; class CTransaction; class uint256; @@ -27,19 +28,54 @@ enum enum { SCRIPT_VERIFY_NONE = 0, - SCRIPT_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts - SCRIPT_VERIFY_STRICTENC = (1U << 1), // enforce strict conformance to DER and SEC2 for signatures and pubkeys - SCRIPT_VERIFY_LOW_S = (1U << 2), // enforce low S values (<n/2) in signatures (depends on STRICTENC) - SCRIPT_VERIFY_NOCACHE = (1U << 3), // do not store results in signature cache (but do query it) - SCRIPT_VERIFY_NULLDUMMY = (1U << 4), // verify dummy stack item consumed by CHECKMULTISIG is of zero-length -}; -bool IsCanonicalPubKey(const std::vector<unsigned char> &vchPubKey, unsigned int flags); -bool IsCanonicalSignature(const std::vector<unsigned char> &vchSig, unsigned int flags); + // Evaluate P2SH subscripts (softfork safe, BIP16). + SCRIPT_VERIFY_P2SH = (1U << 0), + + // Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure. + // Passing a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) to checksig causes that pubkey to be + // skipped (not softfork safe: this flag can widen the validity of OP_CHECKSIG OP_NOT). + SCRIPT_VERIFY_STRICTENC = (1U << 1), + + // Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1) + SCRIPT_VERIFY_DERSIG = (1U << 2), + + // Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure + // (softfork safe, BIP62 rule 5). + SCRIPT_VERIFY_LOW_S = (1U << 3), + + // verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7). + SCRIPT_VERIFY_NULLDUMMY = (1U << 4), +}; uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType); -bool CheckSig(std::vector<unsigned char> vchSig, const std::vector<unsigned char> &vchPubKey, const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int flags); -bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, unsigned int flags); -bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, unsigned int flags); + +class BaseSignatureChecker +{ +public: + virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const + { + return false; + } + + virtual ~BaseSignatureChecker() {} +}; + +class SignatureChecker : public BaseSignatureChecker +{ +private: + const CTransaction& txTo; + unsigned int nIn; + +protected: + virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + +public: + SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} + bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; +}; + +bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker); +bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker); #endif // H_BITCOIN_SCRIPT_INTERPRETER diff --git a/src/script/script.h b/src/script/script.h index 07a4229f85..caf176476f 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -304,7 +304,7 @@ private: // If the input vector's most significant byte is 0x80, remove it from // the result's msb and return a negative. if (vch.back() & 0x80) - return -(result & ~(0x80ULL << (8 * (vch.size() - 1)))); + return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1))))); return result; } @@ -340,9 +340,7 @@ public: CScript() { } CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { } CScript(const_iterator pbegin, const_iterator pend) : std::vector<unsigned char>(pbegin, pend) { } -#ifndef _MSC_VER CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { } -#endif CScript& operator+=(const CScript& b) { @@ -546,7 +544,7 @@ public: { while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0) { - erase(pc, pc + b.size()); + pc = erase(pc, pc + b.size()); ++nFound; } } diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp new file mode 100644 index 0000000000..ab366898d8 --- /dev/null +++ b/src/script/sigcache.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "sigcache.h" + +#include "key.h" +#include "random.h" +#include "uint256.h" +#include "util.h" + +#include <boost/thread.hpp> +#include <boost/tuple/tuple_comparison.hpp> + +namespace { + +// Valid signature cache, to avoid doing expensive ECDSA signature checking +// twice for every transaction (once when accepted into memory pool, and +// again when accepted into the block chain) +class CSignatureCache +{ +private: + // sigdata_type is (signature hash, signature, public key): + typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type; + std::set< sigdata_type> setValid; + boost::shared_mutex cs_sigcache; + +public: + bool + Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + { + boost::shared_lock<boost::shared_mutex> lock(cs_sigcache); + + sigdata_type k(hash, vchSig, pubKey); + std::set<sigdata_type>::iterator mi = setValid.find(k); + if (mi != setValid.end()) + return true; + return false; + } + + void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey) + { + // DoS prevention: limit cache size to less than 10MB + // (~200 bytes per cache entry times 50,000 entries) + // Since there are a maximum of 20,000 signature operations per block + // 50,000 is a reasonable default. + int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + if (nMaxCacheSize <= 0) return; + + boost::unique_lock<boost::shared_mutex> lock(cs_sigcache); + + while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize) + { + // Evict a random entry. Random because that helps + // foil would-be DoS attackers who might try to pre-generate + // and re-use a set of valid signatures just-slightly-greater + // than our cache size. + uint256 randomHash = GetRandHash(); + std::vector<unsigned char> unused; + std::set<sigdata_type>::iterator it = + setValid.lower_bound(sigdata_type(randomHash, unused, unused)); + if (it == setValid.end()) + it = setValid.begin(); + setValid.erase(*it); + } + + sigdata_type k(hash, vchSig, pubKey); + setValid.insert(k); + } +}; + +} + +bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +{ + static CSignatureCache signatureCache; + + if (signatureCache.Get(sighash, vchSig, pubkey)) + return true; + + if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash)) + return false; + + if (store) + signatureCache.Set(sighash, vchSig, pubkey); + return true; +} diff --git a/src/script/sigcache.h b/src/script/sigcache.h new file mode 100644 index 0000000000..46b8f4d335 --- /dev/null +++ b/src/script/sigcache.h @@ -0,0 +1,26 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef H_BITCOIN_SCRIPT_SIGCACHE +#define H_BITCOIN_SCRIPT_SIGCACHE + +#include "script/interpreter.h" + +#include <vector> + +class CPubKey; + +class CachingSignatureChecker : public SignatureChecker +{ +private: + bool store; + +public: + CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {} + + bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; +}; + +#endif // H_BITCOIN_SCRIPT_SIGCACHE diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 8abd8d221d..da77e7d1f1 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -123,7 +123,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, txTo, nIn, STANDARD_SCRIPT_VERIFY_FLAGS); + return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn)); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) @@ -174,7 +174,7 @@ static CScript CombineMultisig(CScript scriptPubKey, const CMutableTransaction& if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (CheckSig(sig, pubkey, scriptPubKey, txTo, nIn, 0)) + if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey)) { sigs[pubkey] = sig; break; @@ -252,9 +252,9 @@ CScript CombineSignatures(CScript scriptPubKey, const CTransaction& txTo, unsign Solver(scriptPubKey, txType, vSolutions); vector<valtype> stack1; - EvalScript(stack1, scriptSig1, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC); + EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); vector<valtype> stack2; - EvalScript(stack2, scriptSig2, CTransaction(), 0, SCRIPT_VERIFY_STRICTENC); + EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 407baf621d..53ae254d59 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -203,7 +203,11 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) if (whichType == TX_PUBKEY) { - addressRet = CPubKey(vSolutions[0]).GetID(); + CPubKey pubKey(vSolutions[0]); + if (!pubKey.IsValid()) + return false; + + addressRet = pubKey.GetID(); return true; } else if (whichType == TX_PUBKEYHASH) @@ -237,9 +241,16 @@ bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vecto nRequiredRet = vSolutions.front()[0]; for (unsigned int i = 1; i < vSolutions.size()-1; i++) { - CTxDestination address = CPubKey(vSolutions[i]).GetID(); + CPubKey pubKey(vSolutions[i]); + if (!pubKey.IsValid()) + continue; + + CTxDestination address = pubKey.GetID(); addressRet.push_back(address); } + + if (addressRet.empty()) + return false; } else { diff --git a/src/serialize.h b/src/serialize.h index 57f5fd069b..55b6891394 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -20,9 +20,6 @@ #include <utility> #include <vector> -#include <boost/tuple/tuple.hpp> -#include <boost/type_traits/is_fundamental.hpp> - class CAutoFile; class CDataStream; class CScript; @@ -245,7 +242,7 @@ uint64_t ReadCompactSize(Stream& is) uint64_t xSize; READDATA(is, xSize); nSizeRet = xSize; - if (nSizeRet < 0x100000000LLu) + if (nSizeRet < 0x100000000ULL) throw std::ios_base::failure("non-canonical ReadCompactSize()"); } if (nSizeRet > (uint64_t)MAX_SIZE) @@ -432,14 +429,15 @@ template<typename Stream, typename C> void Serialize(Stream& os, const std::basi template<typename Stream, typename C> void Unserialize(Stream& is, std::basic_string<C>& str, int, int=0); // vector -template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); -template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); +// vectors of unsigned char are a special case and are intended to be serialized as a single opaque blob. +template<typename T, typename A> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&); +template<typename T, typename A, typename V> unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&); template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion); -template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); -template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); +template<typename Stream, typename T, typename A> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&); +template<typename Stream, typename T, typename A, typename V> void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&); template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion); -template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&); -template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&); +template<typename Stream, typename T, typename A> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&); +template<typename Stream, typename T, typename A, typename V> void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&); template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion); // others derived from vector @@ -452,16 +450,6 @@ template<typename K, typename T> unsigned int GetSerializeSize(const std::pair<K template<typename Stream, typename K, typename T> void Serialize(Stream& os, const std::pair<K, T>& item, int nType, int nVersion); template<typename Stream, typename K, typename T> void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion); -// 3 tuple -template<typename T0, typename T1, typename T2> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); -template<typename Stream, typename T0, typename T1, typename T2> void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion); -template<typename Stream, typename T0, typename T1, typename T2> void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion); - -// 4 tuple -template<typename T0, typename T1, typename T2, typename T3> unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); -template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); -template<typename Stream, typename T0, typename T1, typename T2, typename T3> void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion); - // map template<typename K, typename T, typename Pred, typename A> unsigned int GetSerializeSize(const std::map<K, T, Pred, A>& m, int nType, int nVersion); template<typename Stream, typename K, typename T, typename Pred, typename A> void Serialize(Stream& os, const std::map<K, T, Pred, A>& m, int nType, int nVersion); @@ -536,13 +524,13 @@ void Unserialize(Stream& is, std::basic_string<C>& str, int, int) // vector // template<typename T, typename A> -unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) +unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&) { return (GetSizeOfCompactSize(v.size()) + v.size() * sizeof(T)); } -template<typename T, typename A> -unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) +template<typename T, typename A, typename V> +unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nVersion, const V&) { unsigned int nSize = GetSizeOfCompactSize(v.size()); for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) @@ -553,20 +541,20 @@ unsigned int GetSerializeSize_impl(const std::vector<T, A>& v, int nType, int nV template<typename T, typename A> inline unsigned int GetSerializeSize(const std::vector<T, A>& v, int nType, int nVersion) { - return GetSerializeSize_impl(v, nType, nVersion, boost::is_fundamental<T>()); + return GetSerializeSize_impl(v, nType, nVersion, T()); } template<typename Stream, typename T, typename A> -void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) +void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const unsigned char&) { WriteCompactSize(os, v.size()); if (!v.empty()) os.write((char*)&v[0], v.size() * sizeof(T)); } -template<typename Stream, typename T, typename A> -void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) +template<typename Stream, typename T, typename A, typename V> +void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVersion, const V&) { WriteCompactSize(os, v.size()); for (typename std::vector<T, A>::const_iterator vi = v.begin(); vi != v.end(); ++vi) @@ -576,12 +564,12 @@ void Serialize_impl(Stream& os, const std::vector<T, A>& v, int nType, int nVers template<typename Stream, typename T, typename A> inline void Serialize(Stream& os, const std::vector<T, A>& v, int nType, int nVersion) { - Serialize_impl(os, v, nType, nVersion, boost::is_fundamental<T>()); + Serialize_impl(os, v, nType, nVersion, T()); } template<typename Stream, typename T, typename A> -void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::true_type&) +void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const unsigned char&) { // Limit size per read so bogus size value won't cause out of memory v.clear(); @@ -596,8 +584,8 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, } } -template<typename Stream, typename T, typename A> -void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const boost::false_type&) +template<typename Stream, typename T, typename A, typename V> +void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, const V&) { v.clear(); unsigned int nSize = ReadCompactSize(is); @@ -617,7 +605,7 @@ void Unserialize_impl(Stream& is, std::vector<T, A>& v, int nType, int nVersion, template<typename Stream, typename T, typename A> inline void Unserialize(Stream& is, std::vector<T, A>& v, int nType, int nVersion) { - Unserialize_impl(is, v, nType, nVersion, boost::is_fundamental<T>()); + Unserialize_impl(is, v, nType, nVersion, T()); } @@ -670,71 +658,6 @@ void Unserialize(Stream& is, std::pair<K, T>& item, int nType, int nVersion) // -// 3 tuple -// -template<typename T0, typename T1, typename T2> -unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) -{ - unsigned int nSize = 0; - nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); - return nSize; -} - -template<typename Stream, typename T0, typename T1, typename T2> -void Serialize(Stream& os, const boost::tuple<T0, T1, T2>& item, int nType, int nVersion) -{ - Serialize(os, boost::get<0>(item), nType, nVersion); - Serialize(os, boost::get<1>(item), nType, nVersion); - Serialize(os, boost::get<2>(item), nType, nVersion); -} - -template<typename Stream, typename T0, typename T1, typename T2> -void Unserialize(Stream& is, boost::tuple<T0, T1, T2>& item, int nType, int nVersion) -{ - Unserialize(is, boost::get<0>(item), nType, nVersion); - Unserialize(is, boost::get<1>(item), nType, nVersion); - Unserialize(is, boost::get<2>(item), nType, nVersion); -} - - - -// -// 4 tuple -// -template<typename T0, typename T1, typename T2, typename T3> -unsigned int GetSerializeSize(const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) -{ - unsigned int nSize = 0; - nSize += GetSerializeSize(boost::get<0>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<1>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<2>(item), nType, nVersion); - nSize += GetSerializeSize(boost::get<3>(item), nType, nVersion); - return nSize; -} - -template<typename Stream, typename T0, typename T1, typename T2, typename T3> -void Serialize(Stream& os, const boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) -{ - Serialize(os, boost::get<0>(item), nType, nVersion); - Serialize(os, boost::get<1>(item), nType, nVersion); - Serialize(os, boost::get<2>(item), nType, nVersion); - Serialize(os, boost::get<3>(item), nType, nVersion); -} - -template<typename Stream, typename T0, typename T1, typename T2, typename T3> -void Unserialize(Stream& is, boost::tuple<T0, T1, T2, T3>& item, int nType, int nVersion) -{ - Unserialize(is, boost::get<0>(item), nType, nVersion); - Unserialize(is, boost::get<1>(item), nType, nVersion); - Unserialize(is, boost::get<2>(item), nType, nVersion); - Unserialize(is, boost::get<3>(item), nType, nVersion); -} - - - -// // map // template<typename K, typename T, typename Pred, typename A> @@ -921,7 +844,7 @@ public: Init(nTypeIn, nVersionIn); } - CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]) + CDataStream(const std::vector<unsigned char>& vchIn, int nTypeIn, int nVersionIn) : vch(vchIn.begin(), vchIn.end()) { Init(nTypeIn, nVersionIn); } @@ -1154,7 +1077,7 @@ public: -/** RAII wrapper for FILE*. +/** Non-refcounted RAII wrapper for FILE* * * Will automatically close the file when it goes out of scope if not null. * If you're returning the file pointer, return file.release(). @@ -1162,12 +1085,17 @@ public: */ class CAutoFile { -protected: - FILE* file; -public: +private: + // Disallow copies + CAutoFile(const CAutoFile&); + CAutoFile& operator=(const CAutoFile&); + int nType; int nVersion; + + FILE* file; +public: CAutoFile(FILE* filenew, int nTypeIn, int nVersionIn) { file = filenew; @@ -1182,9 +1110,10 @@ public: void fclose() { - if (file != NULL && file != stdin && file != stdout && file != stderr) + if (file) { ::fclose(file); - file = NULL; + file = NULL; + } } FILE* release() { FILE* ret = file; file = NULL; return ret; } @@ -1252,13 +1181,23 @@ public: } }; -/** Wrapper around a FILE* that implements a ring buffer to - * deserialize from. It guarantees the ability to rewind - * a given number of bytes. */ +/** Non-refcounted RAII wrapper around a FILE* that implements a ring buffer to + * deserialize from. It guarantees the ability to rewind a given number of bytes. + * + * Will automatically close the file when it goes out of scope if not null. + * If you need to close the file early, use file.fclose() instead of fclose(file). + */ class CBufferedFile { private: - FILE *src; // source file + // Disallow copies + CBufferedFile(const CBufferedFile&); + CBufferedFile& operator=(const CBufferedFile&); + + int nType; + int nVersion; + + FILE *src; // source file uint64_t nSrcPos; // how many bytes have been read from source uint64_t nReadPos; // how many bytes have been read from this uint64_t nReadLimit; // up to which position we're allowed to read @@ -1285,12 +1224,25 @@ protected: } public: - int nType; - int nVersion; - CBufferedFile(FILE *fileIn, uint64_t nBufSize, uint64_t nRewindIn, int nTypeIn, int nVersionIn) : - src(fileIn), nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0), - nType(nTypeIn), nVersion(nVersionIn) { + nSrcPos(0), nReadPos(0), nReadLimit((uint64_t)(-1)), nRewind(nRewindIn), vchBuf(nBufSize, 0) + { + src = fileIn; + nType = nTypeIn; + nVersion = nVersionIn; + } + + ~CBufferedFile() + { + fclose(); + } + + void fclose() + { + if (src) { + ::fclose(src); + src = NULL; + } } // check whether we're at the end of the source file diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp index af01e5518c..7bec12b665 100644 --- a/src/test/DoS_tests.cpp +++ b/src/test/DoS_tests.cpp @@ -27,7 +27,11 @@ extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); extern void EraseOrphansFor(NodeId peer); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); -extern std::map<uint256, CTransaction> mapOrphanTransactions; +struct COrphanTx { + CTransaction tx; + NodeId fromPeer; +}; +extern std::map<uint256, COrphanTx> mapOrphanTransactions; extern std::map<uint256, std::set<uint256> > mapOrphanTransactionsByPrev; CService ip(uint32_t i) @@ -149,11 +153,11 @@ BOOST_AUTO_TEST_CASE(DoS_checknbits) CTransaction RandomOrphan() { - std::map<uint256, CTransaction>::iterator it; + std::map<uint256, COrphanTx>::iterator it; it = mapOrphanTransactions.lower_bound(GetRandHash()); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); - return it->second; + return it->second.tx; } BOOST_AUTO_TEST_CASE(DoS_mapOrphans) diff --git a/src/test/accounting_tests.cpp b/src/test/accounting_tests.cpp index 4bee0f6b6e..af2a9a214f 100644 --- a/src/test/accounting_tests.cpp +++ b/src/test/accounting_tests.cpp @@ -15,7 +15,7 @@ extern CWallet* pwalletMain; BOOST_AUTO_TEST_SUITE(accounting_tests) static void -GetResults(CWalletDB& walletdb, std::map<int64_t, CAccountingEntry>& results) +GetResults(CWalletDB& walletdb, std::map<CAmount, CAccountingEntry>& results) { std::list<CAccountingEntry> aes; @@ -34,7 +34,7 @@ BOOST_AUTO_TEST_CASE(acc_orderupgrade) std::vector<CWalletTx*> vpwtx; CWalletTx wtx; CAccountingEntry ae; - std::map<int64_t, CAccountingEntry> results; + std::map<CAmount, CAccountingEntry> results; LOCK(pwalletMain->cs_wallet); diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp index fe68e9e974..c298c805da 100644 --- a/src/test/base58_tests.cpp +++ b/src/test/base58_tests.cpp @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58) std::vector<unsigned char> sourcedata = ParseHex(test[0].get_str()); std::string base58string = test[1].get_str(); BOOST_CHECK_MESSAGE( - EncodeBase58(&sourcedata[0], &sourcedata[sourcedata.size()]) == base58string, + EncodeBase58(begin_ptr(sourcedata), end_ptr(sourcedata)) == base58string, strTest); } } @@ -175,7 +175,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse) BOOST_CHECK_MESSAGE(!secret.IsValid(), "IsValid pubkey as privkey:" + strTest); } } - SelectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::UNITTEST); } // Goal: check that generated keys match test vectors @@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen) CTxDestination nodest = CNoDestination(); BOOST_CHECK(!dummyAddr.Set(nodest)); - SelectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::UNITTEST); } // Goal: check that base58 parsing code is robust against a variety of corrupted data diff --git a/src/test/bctest.py b/src/test/bctest.py index 1839f4fef4..ef461014ea 100644 --- a/src/test/bctest.py +++ b/src/test/bctest.py @@ -7,9 +7,11 @@ import os import json import sys -def bctest(testDir, testObj): - execargs = testObj['exec'] +def bctest(testDir, testObj, exeext): + execprog = testObj['exec'] + exeext + execargs = testObj['args'] + execrun = [execprog] + execargs stdinCfg = None inputData = None if "input" in testObj: @@ -22,12 +24,11 @@ def bctest(testDir, testObj): if "output_cmp" in testObj: outputFn = testObj['output_cmp'] outputData = open(testDir + "/" + outputFn).read() - - proc = subprocess.Popen(execargs, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + proc = subprocess.Popen(execrun, stdin=stdinCfg, stdout=subprocess.PIPE, stderr=subprocess.PIPE,universal_newlines=True) try: outs = proc.communicate(input=inputData) except OSError: - print("OSError, Failed to execute " + execargs[0]) + print("OSError, Failed to execute " + execprog) sys.exit(1) if outputData and (outs[0] != outputData): @@ -41,13 +42,13 @@ def bctest(testDir, testObj): print("Return code mismatch for " + outputFn) sys.exit(1) -def bctester(testDir, input_basename): +def bctester(testDir, input_basename, buildenv): input_filename = testDir + "/" + input_basename raw_data = open(input_filename).read() input_data = json.loads(raw_data) for testObj in input_data: - bctest(testDir, testObj) + bctest(testDir, testObj, buildenv.exeext) sys.exit(0) diff --git a/src/test/bignum.h b/src/test/bignum.h index a75f5250fa..86980b2af6 100644 --- a/src/test/bignum.h +++ b/src/test/bignum.h @@ -63,11 +63,11 @@ public: int getint() const { - unsigned long n = BN_get_word(this); + BN_ULONG n = BN_get_word(this); if (!BN_is_negative(this)) - return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n); + return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n); else - return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); + return (n > (BN_ULONG)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n); } void setint64(int64_t sn) diff --git a/src/test/bitcoin-util-test.py b/src/test/bitcoin-util-test.py index 40690c2fed..0eece14cfe 100755 --- a/src/test/bitcoin-util-test.py +++ b/src/test/bitcoin-util-test.py @@ -5,8 +5,9 @@ import os import bctest +import buildenv if __name__ == '__main__': bctest.bctester(os.environ["srcdir"] + "/test/data", - "bitcoin-util-test.json") + "bitcoin-util-test.json",buildenv) diff --git a/src/test/buildenv.py.in b/src/test/buildenv.py.in new file mode 100644 index 0000000000..1618bdeb76 --- /dev/null +++ b/src/test/buildenv.py.in @@ -0,0 +1,2 @@ +#!/usr/bin/python +exeext="@EXEEXT@" diff --git a/src/test/canonical_tests.cpp b/src/test/canonical_tests.cpp deleted file mode 100644 index a17099de72..0000000000 --- a/src/test/canonical_tests.cpp +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) 2012-2013 The Bitcoin Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -// -// Unit tests for canonical signatures -// - -#include "data/sig_noncanonical.json.h" -#include "data/sig_canonical.json.h" -#include "key.h" -#include "random.h" -#include "script/interpreter.h" -#include "util.h" -#include "utilstrencodings.h" - -#include <boost/foreach.hpp> -#include <boost/test/unit_test.hpp> -#include "json/json_spirit_writer_template.h" -#include <openssl/ecdsa.h> - -using namespace std; -using namespace json_spirit; - -// In script_tests.cpp -extern Array read_json(const std::string& jsondata); - -BOOST_AUTO_TEST_SUITE(canonical_tests) - -// OpenSSL-based test for canonical signature (without test for hashtype byte) -bool static IsCanonicalSignature_OpenSSL_inner(const std::vector<unsigned char>& vchSig) -{ - if (vchSig.size() == 0) - return false; - const unsigned char *input = &vchSig[0]; - ECDSA_SIG *psig = NULL; - d2i_ECDSA_SIG(&psig, &input, vchSig.size()); - if (psig == NULL) - return false; - unsigned char buf[256]; - unsigned char *pbuf = buf; - unsigned int nLen = i2d_ECDSA_SIG(psig, NULL); - if (nLen != vchSig.size()) { - ECDSA_SIG_free(psig); - return false; - } - nLen = i2d_ECDSA_SIG(psig, &pbuf); - ECDSA_SIG_free(psig); - return (memcmp(&vchSig[0], &buf[0], nLen) == 0); -} - -// OpenSSL-based test for canonical signature -bool static IsCanonicalSignature_OpenSSL(const std::vector<unsigned char> &vchSignature) { - if (vchSignature.size() < 1) - return false; - if (vchSignature.size() > 127) - return false; - if (vchSignature[vchSignature.size() - 1] & 0x7C) - return false; - - std::vector<unsigned char> vchSig(vchSignature); - vchSig.pop_back(); - if (!IsCanonicalSignature_OpenSSL_inner(vchSig)) - return false; - return true; -} - -BOOST_AUTO_TEST_CASE(script_canon) -{ - Array tests = read_json(std::string(json_tests::sig_canonical, json_tests::sig_canonical + sizeof(json_tests::sig_canonical))); - - BOOST_FOREACH(Value &tv, tests) { - string test = tv.get_str(); - if (IsHex(test)) { - std::vector<unsigned char> sig = ParseHex(test); - BOOST_CHECK_MESSAGE(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test); - BOOST_CHECK_MESSAGE(IsCanonicalSignature_OpenSSL(sig), test); - } - } -} - -BOOST_AUTO_TEST_CASE(script_noncanon) -{ - Array tests = read_json(std::string(json_tests::sig_noncanonical, json_tests::sig_noncanonical + sizeof(json_tests::sig_noncanonical))); - - BOOST_FOREACH(Value &tv, tests) { - string test = tv.get_str(); - if (IsHex(test)) { - std::vector<unsigned char> sig = ParseHex(test); - BOOST_CHECK_MESSAGE(!IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC), test); - BOOST_CHECK_MESSAGE(!IsCanonicalSignature_OpenSSL(sig), test); - } - } -} - -BOOST_AUTO_TEST_CASE(script_signstrict) -{ - for (int i=0; i<100; i++) { - CKey key; - key.MakeNewKey(i & 1); - std::vector<unsigned char> sig; - uint256 hash = GetRandHash(); - - BOOST_CHECK(key.Sign(hash, sig)); // Generate a random signature. - BOOST_CHECK(key.GetPubKey().Verify(hash, sig)); // Check it. - sig.push_back(0x01); // Append a sighash type. - - BOOST_CHECK(IsCanonicalSignature(sig, SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_LOW_S)); - BOOST_CHECK(IsCanonicalSignature_OpenSSL(sig)); - } -} - -BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp index fdea12846a..67d40a45c7 100644 --- a/src/test/checkblock_tests.cpp +++ b/src/test/checkblock_tests.cpp @@ -35,7 +35,7 @@ bool read_block(const std::string& filename, CBlock& block) fseek(fp, 8, SEEK_SET); // skip msgheader/size - CAutoFile filein = CAutoFile(fp, SER_DISK, CLIENT_VERSION); + CAutoFile filein(fp, SER_DISK, CLIENT_VERSION); if (!filein) return false; filein >> block; diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp new file mode 100644 index 0000000000..3ecd301bc7 --- /dev/null +++ b/src/test/coins_tests.cpp @@ -0,0 +1,178 @@ +// Copyright (c) 2014 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "coins.h" +#include "random.h" +#include "uint256.h" + +#include <vector> +#include <map> + +#include <boost/test/unit_test.hpp> + +namespace +{ +class CCoinsViewTest : public CCoinsView +{ + uint256 hashBestBlock_; + std::map<uint256, CCoins> map_; + +public: + bool GetCoins(const uint256& txid, CCoins& coins) const + { + std::map<uint256, CCoins>::const_iterator it = map_.find(txid); + if (it == map_.end()) { + return false; + } + coins = it->second; + if (coins.IsPruned() && insecure_rand() % 2 == 0) { + // Randomly return false in case of an empty entry. + return false; + } + return true; + } + + bool HaveCoins(const uint256& txid) const + { + CCoins coins; + return GetCoins(txid, coins); + } + + uint256 GetBestBlock() const { return hashBestBlock_; } + + bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock) + { + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) { + map_[it->first] = it->second.coins; + if (it->second.coins.IsPruned() && insecure_rand() % 3 == 0) { + // Randomly delete empty entries on write. + map_.erase(it->first); + } + mapCoins.erase(it++); + } + mapCoins.clear(); + hashBestBlock_ = hashBlock; + return true; + } + + bool GetStats(CCoinsStats& stats) const { return false; } +}; +} + +BOOST_AUTO_TEST_SUITE(coins_tests) + +static const unsigned int NUM_SIMULATION_ITERATIONS = 40000; + +// This is a large randomized insert/remove simulation test on a variable-size +// stack of caches on top of CCoinsViewTest. +// +// It will randomly create/update/delete CCoins entries to a tip of caches, with +// txids picked from a limited list of random 256-bit hashes. Occasionally, a +// new tip is added to the stack of caches, or the tip is flushed and removed. +// +// During the process, booleans are kept to make sure that the randomized +// operation hits all branches. +BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) +{ + // Various coverage trackers. + bool removed_all_caches = false; + bool reached_4_caches = false; + bool added_an_entry = false; + bool removed_an_entry = false; + bool updated_an_entry = false; + bool found_an_entry = false; + bool missed_an_entry = false; + + // A simple map to track what we expect the cache stack to represent. + std::map<uint256, CCoins> result; + + // The cache stack. + CCoinsViewTest base; // A CCoinsViewTest at the bottom. + std::vector<CCoinsViewCache*> stack; // A stack of CCoinsViewCaches on top. + stack.push_back(new CCoinsViewCache(&base)); // Start with one cache. + + // Use a limited set of random transaction ids, so we do test overwriting entries. + std::vector<uint256> txids; + txids.resize(NUM_SIMULATION_ITERATIONS / 8); + for (unsigned int i = 0; i < txids.size(); i++) { + txids[i] = GetRandHash(); + } + + for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { + // Do a random modification. + { + uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration. + CCoins& coins = result[txid]; + CCoinsModifier entry = stack.back()->ModifyCoins(txid); + BOOST_CHECK(coins == *entry); + if (insecure_rand() % 5 == 0 || coins.IsPruned()) { + if (coins.IsPruned()) { + added_an_entry = true; + } else { + updated_an_entry = true; + } + coins.nVersion = insecure_rand(); + coins.vout.resize(1); + coins.vout[0].nValue = insecure_rand(); + *entry = coins; + } else { + coins.Clear(); + entry->Clear(); + removed_an_entry = true; + } + } + + // Once every 1000 iterations and at the end, verify the full cache. + if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { + for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) { + const CCoins* coins = stack.back()->AccessCoins(it->first); + if (coins) { + BOOST_CHECK(*coins == it->second); + found_an_entry = true; + } else { + BOOST_CHECK(it->second.IsPruned()); + missed_an_entry = true; + } + } + } + + if (insecure_rand() % 100 == 0) { + // Every 100 iterations, change the cache stack. + if (stack.size() > 0 && insecure_rand() % 2 == 0) { + stack.back()->Flush(); + delete stack.back(); + stack.pop_back(); + } + if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) { + CCoinsView* tip = &base; + if (stack.size() > 0) { + tip = stack.back(); + } else { + removed_all_caches = true; + } + stack.push_back(new CCoinsViewCache(tip)); + if (stack.size() == 4) { + reached_4_caches = true; + } + } + } + } + + // Clean up the stack. + while (stack.size() > 0) { + delete stack.back(); + stack.pop_back(); + } + + // Verify coverage. + BOOST_CHECK(removed_all_caches); + BOOST_CHECK(reached_4_caches); + BOOST_CHECK(added_an_entry); + BOOST_CHECK(removed_an_entry); + BOOST_CHECK(updated_an_entry); + BOOST_CHECK(found_an_entry); + BOOST_CHECK(missed_an_entry); +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp index a3eec270ee..68232a2ff1 100644 --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -32,7 +32,7 @@ void TestVector(const Hasher &h, const In &in, const Out &out) { size_t len = insecure_rand() % ((in.size() - pos + 1) / 2 + 1); hasher.Write((unsigned char*)&in[pos], len); pos += len; - if (pos > 0 && pos + 2 * out.size() > in.size()) { + if (pos > 0 && pos + 2 * out.size() > in.size() && pos < in.size()) { // Test that writing the rest at once to a copy of a hasher works. Hasher(hasher).Write((unsigned char*)&in[pos], in.size() - pos).Finalize(&hash[0]); BOOST_CHECK(hash == out); diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index cb74d73ef2..f8424b72a3 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -1,33 +1,41 @@ [ - { "exec": ["./bitcoin-tx", "-create"], + { "exec": "././bitcoin-tx", + "args": ["-create"], "output_cmp": "blanktx.hex" }, - { "exec": ["./bitcoin-tx", "-"], + { "exec": "./bitcoin-tx", + "args": ["-"], "input": "blanktx.hex", "output_cmp": "blanktx.hex" }, - { "exec": ["./bitcoin-tx", "-", "delin=1"], + { "exec": "./bitcoin-tx", + "args": ["-", "delin=1"], "input": "tx394b54bb.hex", "output_cmp": "tt-delin1-out.hex" }, - { "exec": ["./bitcoin-tx", "-", "delin=31"], + { "exec": "./bitcoin-tx", + "args": ["-", "delin=31"], "input": "tx394b54bb.hex", "return_code": 1 }, - { "exec": ["./bitcoin-tx", "-", "delout=1"], + { "exec": "./bitcoin-tx", + "args": ["-", "delout=1"], "input": "tx394b54bb.hex", "output_cmp": "tt-delout1-out.hex" }, - { "exec": ["./bitcoin-tx", "-", "delout=2"], + { "exec": "./bitcoin-tx", + "args": ["-", "delout=2"], "input": "tx394b54bb.hex", "return_code": 1 }, - { "exec": ["./bitcoin-tx", "-", "locktime=317000"], + { "exec": "./bitcoin-tx", + "args": ["-", "locktime=317000"], "input": "tx394b54bb.hex", "output_cmp": "tt-locktime317000-out.hex" }, - { "exec": - ["./bitcoin-tx", "-create", + { "exec": "./bitcoin-tx", + "args": + ["-create", "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0", "in=bf829c6bcf84579331337659d31f89dfd138f7f7785802d5501c92333145ca7c:18", "in=22a6f904655d53ae2ff70e701a0bbd90aa3975c0f40bfc6cc996a9049e31cdfc:1", @@ -35,7 +43,8 @@ "outaddr=4:1P8yWvZW8jVihP1bzHeqfE4aoXNX8AVa46"], "output_cmp": "txcreate1.hex" }, - { "exec": ["./bitcoin-tx", "-create", "outscript=0:"], + { "exec": "./bitcoin-tx", + "args": ["-create", "outscript=0:"], "output_cmp": "txcreate2.hex" } ] diff --git a/src/test/data/script_invalid.json b/src/test/data/script_invalid.json index 75de4716f8..b6447cb221 100644 --- a/src/test/data/script_invalid.json +++ b/src/test/data/script_invalid.json @@ -1,4 +1,13 @@ [ +[" +Format is: [scriptPubKey, scriptSig, flags, ... comments] +It is evaluated as if there was a crediting coinbase transaction with two 0 +pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey, +followed by a spending transaction which spends this output as only input (and +correct prevout hash), using the given scriptSig. All nLockTimes are 0, all +nSequences are max. +"], + ["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], [" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."], [" ", "DEPTH", "P2SH,STRICTENC"], @@ -373,5 +382,128 @@ ["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"], ["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"], -["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"] +["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], + +[ + "0x47 0x30440220304eff7556bba9560df47873275e64db45f3cd735998ce3f00d2e57b1bb5f31302205c0c9d14b8b80d43e2ac9b87532f1af6d8a3271262bc694ec4e14068392bb0a001", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "P2PK, bad sig" +], +[ + "0x47 0x3044022037fcdb8e08f41e27588de8bc036d2c4b16eb3d09c1ba53b8f47a0a9c27722a39022058664b7a53b507e71dfafb77193e3786c3f0c119d78ce9104480ee7ece04f09301 0x21 0x03363d90d446b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640", + "DUP HASH160 0x14 0xc0834c0c158f53be706d234c38fd52de7eece656 EQUALVERIFY CHECKSIG", + "", + "P2PKH, bad pubkey" +], +[ + "0x47 0x3044022035e5b6742d299861c84cebaf2ea64145ee427a95facab39e2594d6deebb0c1d602200acb16778faa2e467a59006f342f2535b1418d55ba63a8605b387b7f9ac86d9a01", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "P2PK anyonecanpay marked with normal hashtype" +], +[ + "0x47 0x3044022029b2b8765ca950cf75a69e80b73b7ddfcaa8b27080c2db4c23b36aae60688e790220598ff368e17872ee065aa54d7d3a590682ca5204325b23b31d7da3c4a21ae67901 0x23 0x210279be667ef9dcbbac54a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "P2SH(P2PK), bad redeemscript" +], +[ + "0x47 0x30440220647f906e63890df5ef1d3fed47ba892b31976c634281079e2bd38504fb54a1fb022021e8811f38fbe90efb6b74cb78da01d9badbac3bafdf70a861d7538a220d0b2601 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "P2SH", + "P2SH(P2PKH), bad sig" +], +[ + "0 0x47 0x304402203ef170402f8887f2ac183f31b1f503b0bc60bfc968dd469b097ea6124aefac5002200612febadc4e4cacc086982cb85830a17af3680c1b6a3cf77c1708af7621cf1301 0 0x47 0x304402207821838251a24a2234844f68e7169e6d11945cdf052ea12bd3e4e37457aceb4402200b6b46c81361e314c740ae5133c072af5fa5c209d65d2db1679e1716f19a538101", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "3-of-3, 2 sigs" +], +[ + "0 0 0x47 0x304402204661f7795e8db7be3132e8974e9a76d1d24b31f23df94c6fbcea07d1c205789102203f5e45a1c0b085279b58d11b36d5fea5449c3cf16f844ad10124e9b65e8777d201 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "P2SH(2-of-3), 1 sig" +], +[ + "0x47 0x304402200052bc1600ca45c71f3538720fe62a5e8548dffd137af04467598c98466e9c0a0220789318ddbc9991ee477974089220a2feb6a6298a7c93d5ff6c25a92a2f4b48d501", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "STRICTENC", + "P2PK with too much R padding" +], +[ + "0x48 0x304502206eb7b92628bfb3c4d2a04b65b986987bcbb1af4fceedb144d5a0437b7ee410590221005f57a52df4aa26366742eed0db182fce51fbcd7159011b0644a7c05943eb228901", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "STRICTENC", + "P2PK with too much S padding" +], +[ + "0x47 0x30440220d8ad1efd55a3d2b8896495c38aba72056e1b3ca4a6ca15760e843eb1a9b9907602203eb0e8f3d6bec998262dfd03eaeb0f31c4e5105965436dec77550724b3771f3201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "STRICTENC", + "P2PK with too little R padding" +], +[ + "0x47 0x30440220001d0f82c127470cb38316c96b1719b33382353687a1146a776dee8259606905022062cd1fc8eacef819d68f0f41cc9ae9fdc2e29b70c3c7ad2c6c18f39b4e35c42701", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "P2PK NOT with bad sig with too much R padding" +], +[ + "0x47 0x30440220005d727e2a82d6e8a98a6da6fbc281325644d1a40455e386fdb17883a8e6bc4d02202d15cca42ce136047a980d288e60c679d7e84cce18c3ceffb6bc81b9e9ba517801", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "P2PK NOT with too much R padding but no DERSIG" +], +[ + "0x47 0x30440220006e8bc4f82032b12bd594847c16d8b2986de734aa3b0528bd89d664d41e6d1c02200cfd582694891bcfa2e630e899bda257486eba00a007222fae71144dba07dc2901", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "DERSIG", + "P2PK NOT with too much R padding" +], +[ + "0x48 0x304502206c43e065c8a8db3bbe69015afb86a51fb2fc8870defd41d436da2a197d9d6c12022100fcec35816ee2d84ec271ad159fcabf5dd712157051169e48ac328a7818cdb51e01", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "LOW_S,STRICTENC", + "P2PK with high S" +], +[ + "0x47 0x304402203aab50cd7c30cc1e1475dee615b295bcee6ccf8aa8a7f6cda6b696c70d79cbb40220558e43fe7596c31146e2d077698d5a9c38351d8ba567549a2ae43ca97231c39501", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "STRICTENC", + "P2PK with hybrid pubkey" +], +[ + "0x47 0x304402205745e8f846110c185ee1185c01843a108588b81463d2c34d4a3f2445529f12fe02206ee6a2657bbc4e2bb74bfc44c3a5c4f410ed6356ca68982465de6ca807c807c201", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "P2PK NOT with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x304402201f82b99a813c9c48c8dee8d2c43b8f637b72353fe9bdcc084537bc17e2ab770402200c43b96a5f7e115f0114eabda32e068145965cb6c7b5ef64833bb4fcf9fc1b3b05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "STRICTENC", + "P2PK with undefined hashtype" +], +[ + "0x47 0x30440220166848cd5b82a32b5944d90de3c35249354b43773c2ece1844ee8d1103e2f6c602203b6b046da4243c77adef80ada9201b27bbfdf7f9d5428f40434b060432afd62005", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "STRICTENC", + "P2PK NOT with invalid sig and undefined hashtype" +], +[ + "0x01 0x01 0x47 0x304402200e48ba1cf4d7182db94ffb57bd72ea31b5545dc0d1c512e665779b4fb2badc52022054b8388dfc074c708a75b62359b7be46402751ee40c0a111aef38a837b6ed09801 0x47 0x304402201c9820f59c49107bb30e6175cfc9ec95f897b03beb628b4bc854d2b80392aa0602200235d986ae418bcd111b8814f4c26a0ab5f475fb542a44884fc14912a97a252301 0x47 0x304402204cd7894c6f10a871f5b0c1f9c13228f8cdd4050248f0d0f498ee86be69ee3080022051bd2932c7d585eb600c7194235c74da820935f0d67972fd9545673aa1fd023301", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "NULLDUMMY", + "3-of-3 with nonzero dummy" +], +[ + "0x01 0x01 0x47 0x304402201847fc3b8f7597768e7f543c58da1fca6e8e35eb28979431e6b637572ce6eaa4022048dd58608e040841d0bf52a70cfb70e1a9c8d2826fad068f4e9d2bf5c87766a501 0x47 0x30440220711311a72516affed73363763983d05c3d6a06a2eadf5d76b90b4354162ba94302204841a69e5955a7dc8e4ab3105fd0c86040c1dac6016297a51ddbf5079c28756801 0x47 0x30440220267e331a378191e7282fd10d61c97bf74bc97c233c5833d677936424ac08dee502201eee83d88b91988e1c4d9b979df2404aa190e0987a8ca09c4e5cd61da1d48ecc01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "NULLDUMMY", + "3-of-3 NOT with invalid sig with nonzero dummy" +], + +["The End"] ] diff --git a/src/test/data/script_valid.json b/src/test/data/script_valid.json index c1db4c6061..88bec7238c 100644 --- a/src/test/data/script_valid.json +++ b/src/test/data/script_valid.json @@ -1,4 +1,13 @@ [ +[" +Format is: [scriptPubKey, scriptSig, flags, ... comments] +It is evaluated as if there was a crediting coinbase transaction with two 0 +pushes as scriptSig, and one output of 0 satoshi and given scriptPubKey, +followed by a spending transaction which spends this output as only input (and +correct prevout hash), using the given scriptSig. All nLockTimes are 0, all +nSequences are max. +"], + ["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], [" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."], [" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], @@ -518,5 +527,128 @@ "P2SH,STRICTENC", "Basic PUSHDATA1 signedness check"], -["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"] +["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"], + +[ + "0x47 0x3044022007415aa37ce7eaa6146001ac8bdefca0ddcba0e37c5dc08c4ac99392124ebac802207d382307fd53f65778b07b9c63b6e196edeadf0be719130c5db21ff1e700d67501", + "0x41 0x0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "P2PK" +], +[ + "0x47 0x3044022069d40999786aeb2fd874f9eb2636461a062dc963471627ed8390a3a5f9556f640220350132a52415ce622f2aadd07f791c591500917ec1f8c5edbc5381ef7942534d01 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508", + "DUP HASH160 0x14 0x1018853670f9f3b0582c5b9ee8ce93764ac32b93 EQUALVERIFY CHECKSIG", + "", + "P2PKH" +], +[ + "0x47 0x30440220519f2a6632ffa134c7811ea2819e9dcc951f0c7baf461f2dffdd09133f3b080a02203ec6bab5eb6619ed7f41b8701d7c6d70cfc83bb26c5c97f54b2ca6e304fc2bb581", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "P2PK anyonecanpay" +], +[ + "0x47 0x30440220279dad2170ffb5639f0a1ea71fc462ee37d75d420d86f84c978bac523c09b7f20220683b2789f5c5528a9e0a0d78f6e40db3f616cf1adb5a5fdef117d5974795cfe201 0x23 0x210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ac", + "HASH160 0x14 0x23b0ad3477f2178bc0b3eed26e4e6316f4e83aa1 EQUAL", + "P2SH", + "P2SH(P2PK)" +], +[ + "0x47 0x3044022066acbfb5ac96b7cbf3f05a2aaf358c32438c45d1d7359dee9fc1ee636940735f02205606a03fd8cbf6a6fcbcba60c8abb1e385c0b5753cb57a97538159106fd3684e01 0x19 0x76a9147cf9c846cd4882efec4bf07e44ebdad495c94f4b88ac", + "HASH160 0x14 0x2df519943d5acc0ef5222091f9dfe3543f489a82 EQUAL", + "", + "P2SH(P2PKH), bad sig but no VERIFY_P2SH" +], +[ + "0 0x47 0x3044022004e791dd30a64c70e55e84e150c002af9feb3ce0ab1f20e86c53d1209003927502205a60453987fcd72aebaaacebc8ce4b15449cdd79e54cc82cefb83e69dbcfeabf01 0x47 0x304402201d021808ce93dd8574cc4f99ae4f11b44305528b0aecbd9f156f08315173643802200944a0ea5c884bd86180aef76d8b1e444860776b251e47d2d6c651a1c6f9930801 0x47 0x30440220446336d7b7de05ebb5683b82b05248ec7d78e88ae8d6125985f5776c887a4cf90220674ab2b2c2f954ba1cf35457d273c90d0c0c1c224d0ae128628740e81129486801", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "3-of-3" +], +[ + "0 0x47 0x30440220288b06d057cf0eac434ed0c3be9257cc0ca144dd99c11cc8f1a49467a37d8e8002203c496c72253c528e6bc81c42e683aba974d46041a96ef7b00915c863eb2a702901 0x47 0x304402207ffb4da33f40cac839a43000a187bd76a1ee5bf95e46dc1534b38bb7bd0321db022038c078f29d1831f8eb68ffdc2634c654fb01c3467b6457b98ad220653bb2478501 0x4c69 0x52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f515082103363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff464053ae", + "HASH160 0x14 0xc9e4a896d149702d0d1695434feddd52e24ad78d EQUAL", + "P2SH", + "P2SH(2-of-3)" +], +[ + "0x47 0x30440220001fff8863c84c0efc8eea5bffb7f388313f966f23a00ad3c0acc30ff5339684022016e6d78f51a3a1c362745931ca40b24f71cba2903dbfe5a6d392a9189127d83701", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "P2PK with too much R padding but no DERSIG" +], +[ + "0x48 0x304502202323d56f293842b544cacedd06baafb999196dfa1c2975314848c158ac606655022100514bd98186b8a3a1cc87f4aff76aed797781389f13f50d87bf95b2df6e488fcc01", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "P2PK with too much S padding but no DERSIG" +], +[ + "0x47 0x30440220d31c24bb6c08a496e7698a08fd41975115d7b55bfaa31cb2d573e09481e59a6702206a691239996434076b78a4e1cf46fc8e993b468a9c77fb1832186aa8040a61a201", + "0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 CHECKSIG", + "", + "P2PK with too little R padding but no DERSIG" +], +[ + "0x47 0x30440220007c2cc7aef1801c2937447703c87ef2a3744209ad98da2abadd4ba8bb2e3ea00220503a275582c9f9e9ff30260c81b7f64b8b696f22105605cc8241fb76a797316201", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG NOT", + "", + "P2PK NOT with bad sig with too much R padding but no DERSIG" +], +[ + "0x48 0x3045022021bf9184d94f208ac9f4757ebca9b1cbebf008cfc244fe5be1360b1b9aba0e92022100e55074f72f3a1bfddf2ea4ea7ba984f78822e136fe04c8f9c1363238e0233bd801", + "0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 CHECKSIG", + "STRICTENC", + "P2PK with high S but no LOW_S" +], +[ + "0x47 0x304402202163bc732c21b7de0251297d3c6c2ece182782e85fc5e19d6036f1130a79051e022033827811634924ebba68767537d78dd7bd9109ae2a89a60587927abdc25eb06401", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG", + "", + "P2PK with hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x3044022078033e4227aa05ded69d8da579966578e230d8a7fb44d5f1a0620c3853c24f78022006a2e3f4d872ac8dfdc529110aa37301d65a76255a4b6cce2992adacd4d2c4e201", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "P2PK NOT with hybrid pubkey" +], +[ + "0x47 0x3044022078d6c447887e88dcbe1bc5b613645280df6f4e5935648bc226e9d91da71b3216022047d6b7ef0949b228fc1b359afb8d50500268711354298217b983c26970790c7601", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "", + "P2PK NOT with invalid hybrid pubkey but no STRICTENC" +], +[ + "0x47 0x304402207592427de20e315d644839754f2a5cca5b978b983a15e6da82109ede01722baa022032ceaf78590faa3f7743821e1b47b897ed1a57f6ee1c8a7519d23774d8de3c4401", + "0x41 0x0679be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8 CHECKSIG NOT", + "STRICTENC", + "P2PK NOT with invalid hybrid pubkey" +], +[ + "0x47 0x304402204649e9517ef0377a8f8270bd423053fd98ddff62d74ea553e9579558abbb75e4022044a2b2344469c12e35ed898987711272b634733dd0f5e051288eceb04bd4669e05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG", + "", + "P2PK with undefined hashtype but no STRICTENC" +], +[ + "0x47 0x304402207f1cf1866a2df0bb4b8d84d0ade72aa3abb6aaab0639d608b23d9e10ead0c48202203caa97f22c3439443eea4b89f7f6729854df0f567a8184d6ecc6e8b6c68c3e9d05", + "0x41 0x048282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f5150811f8a8098557dfe45e8256e830b60ace62d613ac2f7b17bed31b6eaff6e26caf CHECKSIG NOT", + "", + "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC" +], +[ + "0x01 0x01 0x47 0x3044022046ce33d1771b0127dd4c4cef8fdc3218ebdfa60e3793ed700292d8ebd93fb1f402201029d47a414db83e96e31443c2d8b552f971469c4800f5eff7df2f0648521aed01 0x47 0x304402205c53911ad55b054920043962bbda98cf6e57e2db1cd5611138251490baabaa8702201dc80dfceae6007e7772dc13ff6e7ca66a983cb017fe5d46d30118462d83bcf801 0x47 0x304402201937e44a4ec12364f9d32f9d25e7ecbc68aee9ef90069af80efef4c05f6ace9602206c515101c00c75710b32ff7ff8dbaf7c9a0be6e86ed14a0755b47626604f31fd01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG", + "", + "3-of-3 with nonzero dummy but no NULLDUMMY" +], +[ + "0x01 0x01 0x47 0x30440220195038dbc6b2ae1199f86a6777824f7c5149789d85f655a3534a4422b8fba38c02204df9db87d2eb9fe06edc66870d9ac4c9ce673459f9d43cee0347ce4ffb02ee5a01 0x47 0x3044022010a45f30c6fa97a186eba9e6b595ab87d3dfcbf05dcaf1f1b8e3e7bf39515bb802203474e78d3d372e5f5c0f8c257ce8300c4bb8f37c51d4a894e11a91b5817da6ed01 0x47 0x30440220039cffd8e39850f95112662b1220b14b3c0d3d8a2772e13c947bfbf96345a64e02204154bfa77e2c0134d5434353bed82141e5da1cc479954aa288d5f0671480a04b01", + "3 0x21 0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798 0x21 0x038282263212c609d9ea2a6e3e172de238d8c39cabd5ac1ca10646e23fd5f51508 0x21 0x03363d90d447b00c9c99ceac05b6262ee053441c7e55552ffe526bad8f83ff4640 3 CHECKMULTISIG NOT", + "", + "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY" +], + +["The End"] ] diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 8cadcdd716..8a984304f4 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -16,7 +16,8 @@ BOOST_AUTO_TEST_SUITE(getarg_tests) static void ResetArgs(const std::string& strArg) { std::vector<std::string> vecArg; - boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); + if (strArg.size()) + boost::split(vecArg, strArg, boost::is_space(), boost::token_compress_on); // Insert dummy executable name: vecArg.insert(vecArg.begin(), "testbitcoin"); diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 203c20731a..b32f3774fe 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -75,7 +75,7 @@ BOOST_AUTO_TEST_CASE(key_test1) CKey key1C = bsecret1C.GetKey(); BOOST_CHECK(key1C.IsCompressed() == true); CKey key2C = bsecret2C.GetKey(); - BOOST_CHECK(key1C.IsCompressed() == true); + BOOST_CHECK(key2C.IsCompressed() == true); CPubKey pubkey1 = key1. GetPubKey(); CPubKey pubkey2 = key2. GetPubKey(); diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 8863ba4004..70a800af51 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -11,9 +11,9 @@ BOOST_AUTO_TEST_SUITE(main_tests) BOOST_AUTO_TEST_CASE(subsidy_limit_test) { - uint64_t nSum = 0; + CAmount nSum = 0; for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) { - uint64_t nSubsidy = GetBlockValue(nHeight, 0); + CAmount nSubsidy = GetBlockValue(nHeight, 0); BOOST_CHECK(nSubsidy <= 50 * COIN); nSum += nSubsidy * 1000; BOOST_CHECK(MoneyRange(nSum)); diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 9e4669eba9..bad5c13ac2 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -253,6 +253,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) chainActive.Tip()->nHeight--; SetMockTime(0); + mempool.clear(); BOOST_FOREACH(CTransaction *tx, txFirst) delete tx; diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp index cb37740068..5a2ec1cb31 100644 --- a/src/test/multisig_tests.cpp +++ b/src/test/multisig_tests.cpp @@ -82,19 +82,19 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys.clear(); keys += key[0],key[1]; // magic operator+= from boost.assign s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK(VerifyScript(s, a_and_b, txTo[0], 0, flags)); + BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0))); for (int i = 0; i < 4; i++) { keys.clear(); keys += key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags), strprintf("a&b 1: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 1: %d", i)); keys.clear(); keys += key[1],key[i]; s = sign_multisig(a_and_b, keys, txTo[0], 0); - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, txTo[0], 0, flags), strprintf("a&b 2: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 2: %d", i)); } // Test a OR b: @@ -104,16 +104,16 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i]; s = sign_multisig(a_or_b, keys, txTo[1], 0); if (i == 0 || i == 1) - BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, txTo[1], 0, flags), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, txTo[1], 0, flags), strprintf("a|b: %d", i)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); } s.clear(); s << OP_0 << OP_0; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); s.clear(); s << OP_0 << OP_1; - BOOST_CHECK(!VerifyScript(s, a_or_b, txTo[1], 0, flags)); + BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); for (int i = 0; i < 4; i++) @@ -123,9 +123,9 @@ BOOST_AUTO_TEST_CASE(multisig_verify) keys += key[i],key[j]; s = sign_multisig(escrow, keys, txTo[2], 0); if (i < j && i < 3 && j < 3) - BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, txTo[2], 0, flags), strprintf("escrow 1: %d %d", i, j)); + BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 1: %d %d", i, j)); else - BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, txTo[2], 0, flags), strprintf("escrow 2: %d %d", i, j)); + BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 2: %d %d", i, j)); } } diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 1dc2a3d82f..91da0c4420 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -14,7 +14,7 @@ using namespace std; using namespace json_spirit; -extern Array createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL); +extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL); extern Value CallRPC(string args); extern CWallet* pwalletMain; @@ -53,10 +53,10 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig) BOOST_CHECK_THROW(addmultisig(createArgs(1, ""), false), runtime_error); BOOST_CHECK_THROW(addmultisig(createArgs(1, "NotAValidPubkey"), false), runtime_error); - string short1(address1Hex, address1Hex+sizeof(address1Hex)-2); // last byte missing + string short1(address1Hex, address1Hex + sizeof(address1Hex) - 2); // last byte missing BOOST_CHECK_THROW(addmultisig(createArgs(2, short1.c_str()), false), runtime_error); - string short2(address1Hex+1, address1Hex+sizeof(address1Hex)); // first byte missing + string short2(address1Hex + 1, address1Hex + sizeof(address1Hex)); // first byte missing BOOST_CHECK_THROW(addmultisig(createArgs(2, short2.c_str()), false), runtime_error); } @@ -68,26 +68,30 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) LOCK2(cs_main, pwalletMain->cs_wallet); CPubKey demoPubkey = pwalletMain->GenerateNewKey(); - CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); - Value retValue; - string strAccount = "walletDemoAccount"; - string strPurpose = "receive"; - BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ - CWalletDB walletdb(pwalletMain->strWalletFile); - CAccount account; - account.vchPubKey = demoPubkey; - pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose); - walletdb.WriteAccount(strAccount, account); - }); - - - /********************************* - * setaccount - *********************************/ - BOOST_CHECK_NO_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount")); - BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error); - /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */ - BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error); + CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID())); + Value retValue; + string strAccount = "walletDemoAccount"; + string strPurpose = "receive"; + BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */ + CWalletDB walletdb(pwalletMain->strWalletFile); + CAccount account; + account.vchPubKey = demoPubkey; + pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose); + walletdb.WriteAccount(strAccount, account); + }); + + CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey(); + CBitcoinAddress setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID())); + + /********************************* + * setaccount + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("setaccount " + setaccountDemoAddress.ToString() + " nullaccount")); + /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ is not owned by the test wallet. */ + BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ nullaccount"), runtime_error); + BOOST_CHECK_THROW(CallRPC("setaccount"), runtime_error); + /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */ + BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error); /********************************* * listunspent @@ -97,12 +101,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_THROW(CallRPC("listunspent 0 string"), runtime_error); BOOST_CHECK_THROW(CallRPC("listunspent 0 1 not_array"), runtime_error); BOOST_CHECK_THROW(CallRPC("listunspent 0 1 [] extra"), runtime_error); - BOOST_CHECK_NO_THROW(r=CallRPC("listunspent 0 1 []")); + BOOST_CHECK_NO_THROW(r = CallRPC("listunspent 0 1 []")); BOOST_CHECK(r.get_array().empty()); /********************************* - * listreceivedbyaddress - *********************************/ + * listreceivedbyaddress + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress")); BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaddress 0")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress not_int"), runtime_error); @@ -111,8 +115,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_THROW(CallRPC("listreceivedbyaddress 0 true extra"), runtime_error); /********************************* - * listreceivedbyaccount - *********************************/ + * listreceivedbyaccount + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount")); BOOST_CHECK_NO_THROW(CallRPC("listreceivedbyaccount 0")); BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount not_int"), runtime_error); @@ -121,59 +125,58 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); /********************************* - * getrawchangeaddress - *********************************/ + * getrawchangeaddress + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress")); /********************************* - * getnewaddress - *********************************/ + * getnewaddress + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("getnewaddress")); BOOST_CHECK_NO_THROW(CallRPC("getnewaddress getnewaddress_demoaccount")); /********************************* - * getaccountaddress - *********************************/ + * getaccountaddress + *********************************/ BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress \"\"")); - BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account - BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); - BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get()); - - /********************************* - * getaccount - *********************************/ - BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error); - BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString())); - - /********************************* - * signmessage + verifymessage - *********************************/ - BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage")); - BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error); - /* Should throw error because this address is not loaded in the wallet */ - BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error); - - /* missing arguments */ - BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString()), runtime_error); - BOOST_CHECK_THROW(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str()), runtime_error); - /* Illegal address */ - BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error); - /* wrong address */ - BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false); - /* Correct address and signature but wrong message */ - BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false); - /* Correct address, message and signature*/ - BOOST_CHECK(CallRPC("verifymessage "+ demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true); - - /********************************* - * getaddressesbyaccount - *********************************/ - BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error); - BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); - Array arr = retValue.get_array(); - BOOST_CHECK(arr.size() > 0); - BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); + BOOST_CHECK_NO_THROW(CallRPC("getaccountaddress accountThatDoesntExists")); // Should generate a new account + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaccountaddress " + strAccount)); + BOOST_CHECK(CBitcoinAddress(retValue.get_str()).Get() == demoAddress.Get()); + /********************************* + * getaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaccount"), runtime_error); + BOOST_CHECK_NO_THROW(CallRPC("getaccount " + demoAddress.ToString())); + + /********************************* + * signmessage + verifymessage + *********************************/ + BOOST_CHECK_NO_THROW(retValue = CallRPC("signmessage " + demoAddress.ToString() + " mymessage")); + BOOST_CHECK_THROW(CallRPC("signmessage"), runtime_error); + /* Should throw error because this address is not loaded in the wallet */ + BOOST_CHECK_THROW(CallRPC("signmessage 1QFqqMUD55ZV3PJEJZtaKCsQmjLT6JkjvJ mymessage"), runtime_error); + + /* missing arguments */ + BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString()), runtime_error); + BOOST_CHECK_THROW(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str()), runtime_error); + /* Illegal address */ + BOOST_CHECK_THROW(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X " + retValue.get_str() + " mymessage"), runtime_error); + /* wrong address */ + BOOST_CHECK(CallRPC("verifymessage 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ " + retValue.get_str() + " mymessage").get_bool() == false); + /* Correct address and signature but wrong message */ + BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " wrongmessage").get_bool() == false); + /* Correct address, message and signature*/ + BOOST_CHECK(CallRPC("verifymessage " + demoAddress.ToString() + " " + retValue.get_str() + " mymessage").get_bool() == true); + + /********************************* + * getaddressesbyaccount + *********************************/ + BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error); + BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount)); + Array arr = retValue.get_array(); + BOOST_CHECK(arr.size() > 0); + BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); } diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp index e6cf00c2d0..f8361a0dc8 100644 --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -42,7 +42,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) txTo.vin[0].scriptSig = scriptSig; txTo.vout[0].nValue = 1; - return VerifyScript(scriptSig, scriptPubKey, txTo, 0, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE); + return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0)); } @@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(sign) { CScript sigSave = txTo[i].vin[0].scriptSig; txTo[i].vin[0].scriptSig = txTo[j].vin[0].scriptSig; - bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC)(); + bool sigOK = CScriptCheck(CCoins(txFrom, 0), txTo[i], 0, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, false)(); if (i == j) BOOST_CHECK_MESSAGE(sigOK, strprintf("VerifySignature %d %d", i, j)); else @@ -255,7 +255,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) { LOCK(cs_main); CCoinsView coinsDummy; - CCoinsViewCache coins(coinsDummy); + CCoinsViewCache coins(&coinsDummy); CBasicKeyStore keystore; CKey key[6]; vector<CPubKey> keys; @@ -312,8 +312,7 @@ BOOST_AUTO_TEST_CASE(AreInputsStandard) txFrom.vout[6].scriptPubKey = GetScriptForDestination(twentySigops.GetID()); txFrom.vout[6].nValue = 6000; - - coins.SetCoins(txFrom.GetHash(), CCoins(txFrom, 0)); + coins.ModifyCoins(txFrom.GetHash())->FromTx(txFrom, 0); CMutableTransaction txTo; txTo.vout.resize(1); diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index cb543a0cf1..a4b0212494 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -5,12 +5,13 @@ #include "data/script_invalid.json.h" #include "data/script_valid.json.h" +#include "core_io.h" #include "key.h" #include "keystore.h" #include "main.h" #include "script/script.h" #include "script/sign.h" -#include "core_io.h" +#include "util.h" #include <fstream> #include <stdint.h> @@ -33,9 +34,13 @@ using namespace std; using namespace json_spirit; using namespace boost::algorithm; +// Uncomment if you want to output updated JSON tests. +// #define UPDATE_JSON_TESTS + static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int ParseScriptFlags(string strFlags); +string FormatScriptFlags(unsigned int flags); Array read_json(const std::string& jsondata) @@ -52,6 +57,410 @@ read_json(const std::string& jsondata) BOOST_AUTO_TEST_SUITE(script_tests) +CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey) +{ + CMutableTransaction txCredit; + txCredit.nVersion = 1; + txCredit.nLockTime = 0; + txCredit.vin.resize(1); + txCredit.vout.resize(1); + txCredit.vin[0].prevout.SetNull(); + txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0); + txCredit.vin[0].nSequence = std::numeric_limits<unsigned int>::max(); + txCredit.vout[0].scriptPubKey = scriptPubKey; + txCredit.vout[0].nValue = 0; + + return txCredit; +} + +CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit) +{ + CMutableTransaction txSpend; + txSpend.nVersion = 1; + txSpend.nLockTime = 0; + txSpend.vin.resize(1); + txSpend.vout.resize(1); + txSpend.vin[0].prevout.hash = txCredit.GetHash(); + txSpend.vin[0].prevout.n = 0; + txSpend.vin[0].scriptSig = scriptSig; + txSpend.vin[0].nSequence = std::numeric_limits<unsigned int>::max(); + txSpend.vout[0].scriptPubKey = CScript(); + txSpend.vout[0].nValue = 0; + + return txSpend; +} + +void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) +{ + BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0)) == expect, message); +} + +namespace +{ +const unsigned char vchKey0[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; +const unsigned char vchKey1[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0}; +const unsigned char vchKey2[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0}; + +struct KeyData +{ + CKey key0, key0C, key1, key1C, key2, key2C; + CPubKey pubkey0, pubkey0C, pubkey0H; + CPubKey pubkey1, pubkey1C; + CPubKey pubkey2, pubkey2C; + + KeyData() + { + + key0.Set(vchKey0, vchKey0 + 32, false); + key0C.Set(vchKey0, vchKey0 + 32, true); + pubkey0 = key0.GetPubKey(); + pubkey0H = key0.GetPubKey(); + pubkey0C = key0C.GetPubKey(); + *const_cast<unsigned char*>(&pubkey0H[0]) = 0x06 | (pubkey0H[64] & 1); + + key1.Set(vchKey1, vchKey1 + 32, false); + key1C.Set(vchKey1, vchKey1 + 32, true); + pubkey1 = key1.GetPubKey(); + pubkey1C = key1C.GetPubKey(); + + key2.Set(vchKey2, vchKey2 + 32, false); + key2C.Set(vchKey2, vchKey2 + 32, true); + pubkey2 = key2.GetPubKey(); + pubkey2C = key2C.GetPubKey(); + } +}; + +const KeyData keys; + +class TestBuilder +{ +private: + CScript scriptPubKey; + CTransaction creditTx; + CMutableTransaction spendTx; + bool havePush; + std::vector<unsigned char> push; + std::string comment; + int flags; + + void DoPush() + { + if (havePush) { + spendTx.vin[0].scriptSig << push; + havePush = false; + } + } + + void DoPush(const std::vector<unsigned char>& data) + { + DoPush(); + push = data; + havePush = true; + } + +public: + TestBuilder(const CScript& redeemScript, const std::string& comment_, int flags_, bool P2SH = false) : scriptPubKey(redeemScript), havePush(false), comment(comment_), flags(flags_) + { + if (P2SH) { + creditTx = BuildCreditingTransaction(CScript() << OP_HASH160 << redeemScript.GetID() << OP_EQUAL); + } else { + creditTx = BuildCreditingTransaction(redeemScript); + } + spendTx = BuildSpendingTransaction(CScript(), creditTx); + } + + TestBuilder& Add(const CScript& script) + { + spendTx.vin[0].scriptSig += script; + return *this; + } + + TestBuilder& Num(int num) + { + spendTx.vin[0].scriptSig << CScriptNum(num); + return *this; + } + + TestBuilder& Push(const std::string& hex) + { + DoPush(ParseHex(hex)); + return *this; + } + + TestBuilder& PushSig(const CKey& key, int nHashType = SIGHASH_ALL, unsigned int lenR = 32, unsigned int lenS = 32) + { + uint256 hash = SignatureHash(scriptPubKey, spendTx, 0, nHashType); + std::vector<unsigned char> vchSig, r, s; + do { + key.Sign(hash, vchSig, lenS <= 32); + r = std::vector<unsigned char>(vchSig.begin() + 4, vchSig.begin() + 4 + vchSig[3]); + s = std::vector<unsigned char>(vchSig.begin() + 6 + vchSig[3], vchSig.begin() + 6 + vchSig[3] + vchSig[5 + vchSig[3]]); + } while (lenR != r.size() || lenS != s.size()); + vchSig.push_back(static_cast<unsigned char>(nHashType)); + DoPush(vchSig); + return *this; + } + + TestBuilder& Push(const CPubKey& pubkey) + { + DoPush(std::vector<unsigned char>(pubkey.begin(), pubkey.end())); + return *this; + } + + TestBuilder& PushRedeem() + { + DoPush(static_cast<std::vector<unsigned char> >(scriptPubKey)); + return *this; + } + + TestBuilder& EditPush(unsigned int pos, const std::string& hexin, const std::string& hexout) + { + assert(havePush); + std::vector<unsigned char> datain = ParseHex(hexin); + std::vector<unsigned char> dataout = ParseHex(hexout); + assert(pos + datain.size() <= push.size()); + BOOST_CHECK_MESSAGE(std::vector<unsigned char>(push.begin() + pos, push.begin() + pos + datain.size()) == datain, comment); + push.erase(push.begin() + pos, push.begin() + pos + datain.size()); + push.insert(push.begin() + pos, dataout.begin(), dataout.end()); + return *this; + } + + TestBuilder& DamagePush(unsigned int pos) + { + assert(havePush); + assert(pos < push.size()); + push[pos] ^= 1; + return *this; + } + + TestBuilder& Test(bool expect) + { + TestBuilder copy = *this; // Make a copy so we can rollback the push. + DoPush(); + DoTest(creditTx.vout[0].scriptPubKey, spendTx.vin[0].scriptSig, flags, expect, comment); + *this = copy; + return *this; + } + + Array GetJSON() + { + DoPush(); + Array array; + array.push_back(FormatScript(spendTx.vin[0].scriptSig)); + array.push_back(FormatScript(creditTx.vout[0].scriptPubKey)); + array.push_back(FormatScriptFlags(flags)); + array.push_back(comment); + return array; + } + + std::string GetComment() + { + return comment; + } + + const CScript& GetScriptPubKey() + { + return creditTx.vout[0].scriptPubKey; + } +}; +} + +BOOST_AUTO_TEST_CASE(script_build) +{ + std::vector<TestBuilder> good; + std::vector<TestBuilder> bad; + + good.push_back(TestBuilder(CScript() << keys.pubkey0 << OP_CHECKSIG, + "P2PK", 0 + ).PushSig(keys.key0)); + bad.push_back(TestBuilder(CScript() << keys.pubkey0 << OP_CHECKSIG, + "P2PK, bad sig", 0 + ).PushSig(keys.key0).DamagePush(10)); + + good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1C.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH", 0 + ).PushSig(keys.key1).Push(keys.pubkey1C)); + bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey2C.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2PKH, bad pubkey", 0 + ).PushSig(keys.key2).Push(keys.pubkey2C).DamagePush(5)); + + good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG, + "P2PK anyonecanpay", 0 + ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY)); + bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG, + "P2PK anyonecanpay marked with normal hashtype", 0 + ).PushSig(keys.key1, SIGHASH_ALL | SIGHASH_ANYONECANPAY).EditPush(70, "81", "01")); + + good.push_back(TestBuilder(CScript() << keys.pubkey0C << OP_CHECKSIG, + "P2SH(P2PK)", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem()); + bad.push_back(TestBuilder(CScript() << keys.pubkey0C << OP_CHECKSIG, + "P2SH(P2PK), bad redeemscript", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).PushRedeem().DamagePush(10)); + + good.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2SH(P2PKH), bad sig but no VERIFY_P2SH", 0, true + ).PushSig(keys.key0).DamagePush(10).PushRedeem()); + bad.push_back(TestBuilder(CScript() << OP_DUP << OP_HASH160 << keys.pubkey1.GetID() << OP_EQUALVERIFY << OP_CHECKSIG, + "P2SH(P2PKH), bad sig", SCRIPT_VERIFY_P2SH, true + ).PushSig(keys.key0).DamagePush(10).PushRedeem()); + + good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "3-of-3", 0 + ).Num(0).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + bad.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "3-of-3, 2 sigs", 0 + ).Num(0).PushSig(keys.key0).PushSig(keys.key1).Num(0)); + + good.push_back(TestBuilder(CScript() << OP_2 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "P2SH(2-of-3)", SCRIPT_VERIFY_P2SH, true + ).Num(0).PushSig(keys.key1).PushSig(keys.key2).PushRedeem()); + bad.push_back(TestBuilder(CScript() << OP_2 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "P2SH(2-of-3), 1 sig", SCRIPT_VERIFY_P2SH, true + ).Num(0).PushSig(keys.key1).Num(0).PushRedeem()); + + good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much R padding but no DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much R padding", SCRIPT_VERIFY_DERSIG + ).PushSig(keys.key1, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much S padding but no DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too much S padding", SCRIPT_VERIFY_DERSIG + ).PushSig(keys.key1, SIGHASH_ALL).EditPush(1, "44", "45").EditPush(37, "20", "2100")); + good.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too little R padding but no DERSIG", 0 + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + bad.push_back(TestBuilder(CScript() << keys.pubkey1C << OP_CHECKSIG, + "P2PK with too little R padding", SCRIPT_VERIFY_DERSIG + ).PushSig(keys.key1, SIGHASH_ALL, 33, 32).EditPush(1, "45022100", "440220")); + good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG << OP_NOT, + "P2PK NOT with bad sig with too much R padding but no DERSIG", 0 + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); + bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG << OP_NOT, + "P2PK NOT with bad sig with too much R padding", SCRIPT_VERIFY_DERSIG + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000").DamagePush(10)); + bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG << OP_NOT, + "P2PK NOT with too much R padding but no DERSIG", 0 + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG << OP_NOT, + "P2PK NOT with too much R padding", SCRIPT_VERIFY_DERSIG + ).PushSig(keys.key2, SIGHASH_ALL, 31, 32).EditPush(1, "43021F", "44022000")); + + good.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG, + "P2PK with high S but no LOW_S", 0 + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + bad.push_back(TestBuilder(CScript() << keys.pubkey2C << OP_CHECKSIG, + "P2PK with high S", SCRIPT_VERIFY_LOW_S + ).PushSig(keys.key2, SIGHASH_ALL, 32, 33)); + + good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG, + "P2PK with hybrid pubkey but no STRICTENC", 0 + ).PushSig(keys.key0, SIGHASH_ALL)); + bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG, + "P2PK with hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key0, SIGHASH_ALL)); + bad.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT, + "P2PK NOT with hybrid pubkey but no STRICTENC", 0 + ).PushSig(keys.key0, SIGHASH_ALL)); + good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT, + "P2PK NOT with hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key0, SIGHASH_ALL)); + good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid hybrid pubkey but no STRICTENC", 0 + ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); + good.push_back(TestBuilder(CScript() << keys.pubkey0H << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid hybrid pubkey", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key0, SIGHASH_ALL).DamagePush(10)); + + good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG, + "P2PK with undefined hashtype but no STRICTENC", 0 + ).PushSig(keys.key1, 5)); + bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG, + "P2PK with undefined hashtype", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, 5)); + good.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid sig and undefined hashtype but no STRICTENC", 0 + ).PushSig(keys.key1, 5).DamagePush(10)); + bad.push_back(TestBuilder(CScript() << keys.pubkey1 << OP_CHECKSIG << OP_NOT, + "P2PK NOT with invalid sig and undefined hashtype", SCRIPT_VERIFY_STRICTENC + ).PushSig(keys.key1, 5).DamagePush(10)); + + good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "3-of-3 with nonzero dummy but no NULLDUMMY", 0 + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + bad.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG, + "3-of-3 with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2)); + good.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG << OP_NOT, + "3-of-3 NOT with invalid sig and nonzero dummy but no NULLDUMMY", 0 + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); + bad.push_back(TestBuilder(CScript() << OP_3 << keys.pubkey0C << keys.pubkey1C << keys.pubkey2C << OP_3 << OP_CHECKMULTISIG << OP_NOT, + "3-of-3 NOT with invalid sig with nonzero dummy", SCRIPT_VERIFY_NULLDUMMY + ).Num(1).PushSig(keys.key0).PushSig(keys.key1).PushSig(keys.key2).DamagePush(10)); + + std::map<std::string, Array> tests_good; + std::map<std::string, Array> tests_bad; + + { + Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid))); + Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid))); + + BOOST_FOREACH(Value& tv, json_good) { + Array test = tv.get_array(); + if (test.size() >= 4) { + tests_good[test[3].get_str()] = test; + } + } + BOOST_FOREACH(Value& tv, json_bad) { + Array test = tv.get_array(); + if (test.size() >= 4) { + tests_bad[test[3].get_str()] = test; + } + } + } + + std::string strGood; + std::string strBad; + + BOOST_FOREACH(TestBuilder& test, good) { + test.Test(true); + if (tests_good.count(test.GetComment()) == 0) { +#ifndef UPDATE_JSON_TESTS + BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment()); +#endif + strGood += write_string(Value(test.GetJSON()), true) + ",\n"; + } else { + BOOST_CHECK_MESSAGE(ParseScript(tests_good[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_valid test: " + test.GetComment()); + strGood += write_string(Value(tests_good[test.GetComment()]), true) + ",\n"; + } + } + BOOST_FOREACH(TestBuilder& test, bad) { + test.Test(false); + if (tests_bad.count(test.GetComment()) == 0) { +#ifndef UPDATE_JSON_TESTS + BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment()); +#endif + strBad += write_string(Value(test.GetJSON()), true) + ",\n"; + } else { + BOOST_CHECK_MESSAGE(ParseScript(tests_bad[test.GetComment()][1].get_str()) == test.GetScriptPubKey(), "ScriptPubKey mismatch in auto script_invalid test: " + test.GetComment()); + strBad += write_string(Value(tests_bad[test.GetComment()]), true) + ",\n"; + } + } + +#ifdef UPDATE_JSON_TESTS + FILE* valid = fopen("script_valid.json.gen", "w"); + fputs(strGood.c_str(), valid); + fclose(valid); + FILE* invalid = fopen("script_invalid.json.gen", "w"); + fputs(strBad.c_str(), invalid); + fclose(invalid); +#endif +} + BOOST_AUTO_TEST_CASE(script_valid) { // Read tests from test/data/script_valid.json @@ -67,7 +476,9 @@ BOOST_AUTO_TEST_CASE(script_valid) string strTest = write_string(tv, false); if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) { - BOOST_ERROR("Bad test: " << strTest); + if (test.size() != 1) { + BOOST_ERROR("Bad test: " << strTest); + } continue; } string scriptSigString = test[0].get_str(); @@ -76,8 +487,7 @@ BOOST_AUTO_TEST_CASE(script_valid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - CTransaction tx; - BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, tx, 0, scriptflags), strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, true, strTest); } } @@ -90,9 +500,11 @@ BOOST_AUTO_TEST_CASE(script_invalid) { Array test = tv.get_array(); string strTest = write_string(tv, false); - if (test.size() < 2) // Allow size > 2; extra stuff ignored (useful for comments) + if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments) { - BOOST_ERROR("Bad test: " << strTest); + if (test.size() != 1) { + BOOST_ERROR("Bad test: " << strTest); + } continue; } string scriptSigString = test[0].get_str(); @@ -101,8 +513,7 @@ BOOST_AUTO_TEST_CASE(script_invalid) CScript scriptPubKey = ParseScript(scriptPubKeyString); unsigned int scriptflags = ParseScriptFlags(test[2].get_str()); - CTransaction tx; - BOOST_CHECK_MESSAGE(!VerifyScript(scriptSig, scriptPubKey, tx, 0, scriptflags), strTest); + DoTest(scriptPubKey, scriptSig, scriptflags, false, strTest); } } @@ -116,18 +527,18 @@ BOOST_AUTO_TEST_CASE(script_PushData) static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; vector<vector<unsigned char> > directStack; - BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), CTransaction(), 0, true)); + BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker())); vector<vector<unsigned char> > pushdata1Stack; - BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), CTransaction(), 0, true)); + BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker())); BOOST_CHECK(pushdata1Stack == directStack); vector<vector<unsigned char> > pushdata2Stack; - BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), CTransaction(), 0, true)); + BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker())); BOOST_CHECK(pushdata2Stack == directStack); vector<vector<unsigned char> > pushdata4Stack; - BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), CTransaction(), 0, true)); + BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker())); BOOST_CHECK(pushdata4Stack == directStack); } @@ -173,27 +584,19 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) CScript scriptPubKey12; scriptPubKey12 << OP_1 << key1.GetPubKey() << key2.GetPubKey() << OP_2 << OP_CHECKMULTISIG; - CMutableTransaction txFrom12; - txFrom12.vout.resize(1); - txFrom12.vout[0].scriptPubKey = scriptPubKey12; - - CMutableTransaction txTo12; - txTo12.vin.resize(1); - txTo12.vout.resize(1); - txTo12.vin[0].prevout.n = 0; - txTo12.vin[0].prevout.hash = txFrom12.GetHash(); - txTo12.vout[0].nValue = 1; + CMutableTransaction txFrom12 = BuildCreditingTransaction(scriptPubKey12); + CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); txTo12.vout[0].nValue = 2; - BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, txTo12, 0, flags)); + BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, txTo12, 0, flags)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, txTo12, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); } BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) @@ -207,60 +610,52 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) CScript scriptPubKey23; scriptPubKey23 << OP_2 << key1.GetPubKey() << key2.GetPubKey() << key3.GetPubKey() << OP_3 << OP_CHECKMULTISIG; - CMutableTransaction txFrom23; - txFrom23.vout.resize(1); - txFrom23.vout[0].scriptPubKey = scriptPubKey23; - - CMutableTransaction txTo23; - txTo23.vin.resize(1); - txTo23.vout.resize(1); - txTo23.vin[0].prevout.n = 0; - txTo23.vin[0].prevout.hash = txFrom23.GetHash(); - txTo23.vout[0].nValue = 1; + CMutableTransaction txFrom23 = BuildCreditingTransaction(scriptPubKey23); + CMutableTransaction txTo23 = BuildSpendingTransaction(CScript(), txFrom23); std::vector<CKey> keys; keys.push_back(key1); keys.push_back(key2); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key1); keys.push_back(key3); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key2); keys.push_back(key3); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key2); keys.push_back(key2); // Can't re-use sig CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); keys.clear(); // Must have signatures CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); - BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, txTo23, 0, flags)); + BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); } BOOST_AUTO_TEST_CASE(script_combineSigs) @@ -278,17 +673,10 @@ BOOST_AUTO_TEST_CASE(script_combineSigs) keystore.AddKey(key); } - CMutableTransaction txFrom; - txFrom.vout.resize(1); - txFrom.vout[0].scriptPubKey = GetScriptForDestination(keys[0].GetPubKey().GetID()); + CMutableTransaction txFrom = BuildCreditingTransaction(GetScriptForDestination(keys[0].GetPubKey().GetID())); + CMutableTransaction txTo = BuildSpendingTransaction(CScript(), txFrom); CScript& scriptPubKey = txFrom.vout[0].scriptPubKey; - CMutableTransaction txTo; - txTo.vin.resize(1); - txTo.vout.resize(1); - txTo.vin[0].prevout.n = 0; - txTo.vin[0].prevout.hash = txFrom.GetHash(); CScript& scriptSig = txTo.vin[0].scriptSig; - txTo.vout[0].nValue = 1; CScript empty; CScript combined = CombineSignatures(scriptPubKey, txTo, 0, empty, empty); diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 68fad8d038..afd63d2717 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -31,7 +31,7 @@ struct TestingSetup { TestingSetup() { fPrintToDebugLog = false; // don't want to write to debug.log file - SelectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::UNITTEST); noui_connect(); #ifdef ENABLE_WALLET bitdb.MakeMock(); @@ -41,7 +41,7 @@ struct TestingSetup { mapArgs["-datadir"] = pathTemp.string(); pblocktree = new CBlockTreeDB(1 << 20, true); pcoinsdbview = new CCoinsViewDB(1 << 23, true); - pcoinsTip = new CCoinsViewCache(*pcoinsdbview); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); InitBlockIndex(); #ifdef ENABLE_WALLET bool fFirstRun; diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 41d8ee9f19..18cb8f3d1b 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -17,6 +17,7 @@ #include <boost/algorithm/string/classification.hpp> #include <boost/algorithm/string/split.hpp> #include <boost/test/unit_test.hpp> +#include <boost/assign/list_of.hpp> #include "json/json_spirit_writer_template.h" using namespace std; @@ -26,22 +27,23 @@ using namespace boost::algorithm; // In script_tests.cpp extern Array read_json(const std::string& jsondata); -unsigned int ParseScriptFlags(string strFlags){ +static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of + (string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE) + (string("P2SH"), (unsigned int)SCRIPT_VERIFY_P2SH) + (string("STRICTENC"), (unsigned int)SCRIPT_VERIFY_STRICTENC) + (string("DERSIG"), (unsigned int)SCRIPT_VERIFY_DERSIG) + (string("LOW_S"), (unsigned int)SCRIPT_VERIFY_LOW_S) + (string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY); + +unsigned int ParseScriptFlags(string strFlags) +{ + if (strFlags.empty()) { + return 0; + } unsigned int flags = 0; vector<string> words; split(words, strFlags, is_any_of(",")); - // Note how NOCACHE is not included as it is a runtime-only flag. - static map<string, unsigned int> mapFlagNames; - if (mapFlagNames.size() == 0) - { - mapFlagNames["NONE"] = SCRIPT_VERIFY_NONE; - mapFlagNames["P2SH"] = SCRIPT_VERIFY_P2SH; - mapFlagNames["STRICTENC"] = SCRIPT_VERIFY_STRICTENC; - mapFlagNames["LOW_S"] = SCRIPT_VERIFY_LOW_S; - mapFlagNames["NULLDUMMY"] = SCRIPT_VERIFY_NULLDUMMY; - } - BOOST_FOREACH(string word, words) { if (!mapFlagNames.count(word)) @@ -52,6 +54,22 @@ unsigned int ParseScriptFlags(string strFlags){ return flags; } +string FormatScriptFlags(unsigned int flags) +{ + if (flags == 0) { + return ""; + } + string ret; + std::map<string, unsigned int>::const_iterator it = mapFlagNames.begin(); + while (it != mapFlagNames.end()) { + if (flags & it->second) { + ret += it->first + ","; + } + it++; + } + return ret.substr(0, ret.size() - 1); +} + BOOST_AUTO_TEST_SUITE(transaction_tests) BOOST_AUTO_TEST_CASE(tx_valid) @@ -121,7 +139,7 @@ BOOST_AUTO_TEST_CASE(tx_valid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - tx, i, verify_flags), + verify_flags, SignatureChecker(tx, i)), strTest); } } @@ -194,7 +212,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid) unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], - tx, i, verify_flags); + verify_flags, SignatureChecker(tx, i)); } BOOST_CHECK_MESSAGE(!fValid, strTest); @@ -225,7 +243,7 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests) // paid to a TX_PUBKEYHASH. // static std::vector<CMutableTransaction> -SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet) +SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet) { std::vector<CMutableTransaction> dummyTransactions; dummyTransactions.resize(2); @@ -244,14 +262,14 @@ SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsView & coinsRet) dummyTransactions[0].vout[0].scriptPubKey << key[0].GetPubKey() << OP_CHECKSIG; dummyTransactions[0].vout[1].nValue = 50*CENT; dummyTransactions[0].vout[1].scriptPubKey << key[1].GetPubKey() << OP_CHECKSIG; - coinsRet.SetCoins(dummyTransactions[0].GetHash(), CCoins(dummyTransactions[0], 0)); + coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0); dummyTransactions[1].vout.resize(2); dummyTransactions[1].vout[0].nValue = 21*CENT; dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID()); dummyTransactions[1].vout[1].nValue = 22*CENT; dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID()); - coinsRet.SetCoins(dummyTransactions[1].GetHash(), CCoins(dummyTransactions[1], 0)); + coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0); return dummyTransactions; } @@ -260,7 +278,7 @@ BOOST_AUTO_TEST_CASE(test_Get) { CBasicKeyStore keystore; CCoinsView coinsDummy; - CCoinsViewCache coins(coinsDummy); + CCoinsViewCache coins(&coinsDummy); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); CMutableTransaction t1; @@ -295,7 +313,7 @@ BOOST_AUTO_TEST_CASE(test_IsStandard) LOCK(cs_main); CBasicKeyStore keystore; CCoinsView coinsDummy; - CCoinsViewCache coins(coinsDummy); + CCoinsViewCache coins(&coinsDummy); std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins); CMutableTransaction t; diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index e077c9de3b..61daa0a3fe 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -9,6 +9,7 @@ #include "sync.h" #include "utilstrencodings.h" #include "utilmoneystr.h" +#include "version.h" #include <stdint.h> #include <vector> @@ -171,7 +172,7 @@ BOOST_AUTO_TEST_CASE(util_FormatMoney) BOOST_AUTO_TEST_CASE(util_ParseMoney) { - int64_t ret = 0; + CAmount ret = 0; BOOST_CHECK(ParseMoney("0.0", ret)); BOOST_CHECK_EQUAL(ret, 0); @@ -341,4 +342,15 @@ BOOST_AUTO_TEST_CASE(test_FormatParagraph) BOOST_CHECK_EQUAL(FormatParagraph("test test", 4, 4), "test\n test"); } +BOOST_AUTO_TEST_CASE(test_FormatSubVersion) +{ + std::vector<std::string> comments; + comments.push_back(std::string("comment1")); + std::vector<std::string> comments2; + comments2.push_back(std::string("comment1")); + comments2.push_back(std::string("comment2")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/")); + BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/")); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/wallet_tests.cpp b/src/test/wallet_tests.cpp index 3887efbd0d..90fc470e06 100644 --- a/src/test/wallet_tests.cpp +++ b/src/test/wallet_tests.cpp @@ -28,7 +28,7 @@ BOOST_AUTO_TEST_SUITE(wallet_tests) static CWallet wallet; static vector<COutput> vCoins; -static void add_coin(int64_t nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) +static void add_coin(const CAmount& nValue, int nAge = 6*24, bool fIsFromMe = false, int nInput=0) { static int nextLockTime = 0; CMutableTransaction tx; @@ -66,7 +66,7 @@ static bool equal_sets(CoinSet a, CoinSet b) BOOST_AUTO_TEST_CASE(coin_selection_tests) { CoinSet setCoinsRet, setCoinsRet2; - int64_t nValueRet; + CAmount nValueRet; LOCK(wallet.cs_wallet); diff --git a/src/txdb.cpp b/src/txdb.cpp index 79838b6116..cb9f150011 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -33,12 +33,6 @@ bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) const { return db.Read(make_pair('c', txid), coins); } -bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) { - CLevelDBBatch batch; - BatchWriteCoins(batch, txid, coins); - return db.WriteBatch(batch); -} - bool CCoinsViewDB::HaveCoins(const uint256 &txid) const { return db.Exists(make_pair('c', txid)); } @@ -50,24 +44,23 @@ uint256 CCoinsViewDB::GetBestBlock() const { return hashBestChain; } -bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) { - CLevelDBBatch batch; - BatchWriteHashBestChain(batch, hashBlock); - return db.WriteBatch(batch); -} - bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { - LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size()); - CLevelDBBatch batch; + size_t count = 0; + size_t changed = 0; for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { - BatchWriteCoins(batch, it->first, it->second); + if (it->second.flags & CCoinsCacheEntry::DIRTY) { + BatchWriteCoins(batch, it->first, it->second.coins); + changed++; + } + count++; CCoinsMap::iterator itOld = it++; mapCoins.erase(itOld); } if (hashBlock != uint256(0)) BatchWriteHashBestChain(batch, hashBlock); + LogPrint("coindb", "Committing %u changed transactions (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); return db.WriteBatch(batch); } @@ -117,7 +110,7 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const { CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); stats.hashBlock = GetBestBlock(); ss << stats.hashBlock; - int64_t nTotalAmount = 0; + CAmount nTotalAmount = 0; while (pcursor->Valid()) { boost::this_thread::interruption_point(); try { diff --git a/src/txdb.h b/src/txdb.h index f0b6b9e1dd..8f2bd9af4d 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -33,10 +33,8 @@ public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool SetCoins(const uint256 &txid, const CCoins &coins); bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - bool SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats) const; }; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 52d07bf6a0..fa1802ad31 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -7,6 +7,7 @@ #include "core.h" #include "util.h" +#include "utilmoneystr.h" #include <boost/circular_buffer.hpp> @@ -18,7 +19,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(): nHeight = MEMPOOL_HEIGHT; } -CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, int64_t _nFee, +CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, unsigned int _nHeight): tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight) @@ -36,7 +37,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other) double CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const { - int64_t nValueIn = tx.GetValueOut()+nFee; + CAmount nValueIn = tx.GetValueOut()+nFee; double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize; double dResult = dPriority + deltaPriority; return dResult; @@ -601,24 +602,24 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein) return true; } -void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, int64_t nFeeDelta) +void CTxMemPool::PrioritiseTransaction(const uint256 hash, const string strHash, double dPriorityDelta, const CAmount& nFeeDelta) { { LOCK(cs); - std::pair<double, int64_t> &deltas = mapDeltas[hash]; + std::pair<double, CAmount> &deltas = mapDeltas[hash]; deltas.first += dPriorityDelta; deltas.second += nFeeDelta; } - LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, nFeeDelta); + LogPrintf("PrioritiseTransaction: %s priority += %f, fee += %d\n", strHash, dPriorityDelta, FormatMoney(nFeeDelta)); } -void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta) +void CTxMemPool::ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta) { LOCK(cs); - std::map<uint256, std::pair<double, int64_t> >::iterator pos = mapDeltas.find(hash); + std::map<uint256, std::pair<double, CAmount> >::iterator pos = mapDeltas.find(hash); if (pos == mapDeltas.end()) return; - const std::pair<double, int64_t> &deltas = pos->second; + const std::pair<double, CAmount> &deltas = pos->second; dPriorityDelta += deltas.first; nFeeDelta += deltas.second; } @@ -630,7 +631,7 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash) } -CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } +CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never diff --git a/src/txmempool.h b/src/txmempool.h index b9d50ee0bc..ad190eea9d 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -29,7 +29,7 @@ class CTxMemPoolEntry { private: CTransaction tx; - int64_t nFee; // Cached to avoid expensive parent-transaction lookups + CAmount nFee; // Cached to avoid expensive parent-transaction lookups size_t nTxSize; // ... and avoid recomputing tx size size_t nModSize; // ... and modified size for priority int64_t nTime; // Local time when entering the mempool @@ -37,14 +37,14 @@ private: unsigned int nHeight; // Chain height when entering the mempool public: - CTxMemPoolEntry(const CTransaction& _tx, int64_t _nFee, + CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _dPriority, unsigned int _nHeight); CTxMemPoolEntry(); CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return this->tx; } double GetPriority(unsigned int currentHeight) const; - int64_t GetFee() const { return nFee; } + CAmount GetFee() const { return nFee; } size_t GetTxSize() const { return nTxSize; } int64_t GetTime() const { return nTime; } unsigned int GetHeight() const { return nHeight; } @@ -52,6 +52,19 @@ public: class CMinerPolicyEstimator; +/** An inpoint - a combination of a transaction and an index n into its vin */ +class CInPoint +{ +public: + const CTransaction* ptx; + uint32_t n; + + CInPoint() { SetNull(); } + CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; } + void SetNull() { ptx = NULL; n = (uint32_t) -1; } + bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); } +}; + /* * CTxMemPool stores valid-according-to-the-current-best-chain * transactions that may be included in the next block. @@ -76,7 +89,7 @@ public: mutable CCriticalSection cs; std::map<uint256, CTxMemPoolEntry> mapTx; std::map<COutPoint, CInPoint> mapNextTx; - std::map<uint256, std::pair<double, int64_t> > mapDeltas; + std::map<uint256, std::pair<double, CAmount> > mapDeltas; CTxMemPool(const CFeeRate& _minRelayFee); ~CTxMemPool(); @@ -102,8 +115,8 @@ public: void AddTransactionsUpdated(unsigned int n); /** Affect CreateNewBlock prioritisation of transactions */ - void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, int64_t nFeeDelta); - void ApplyDeltas(const uint256 hash, double &dPriorityDelta, int64_t &nFeeDelta); + void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta); + void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta); void ClearPrioritisation(const uint256 hash); unsigned long size() @@ -144,7 +157,7 @@ protected: CTxMemPool &mempool; public: - CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); + CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn); bool GetCoins(const uint256 &txid, CCoins &coins) const; bool HaveCoins(const uint256 &txid) const; }; diff --git a/src/util.cpp b/src/util.cpp index ae7767a1f5..544ffc98b8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -470,6 +470,7 @@ void ReadConfigFile(map<string, string>& mapSettingsRet, ClearDatadirCache(); } +#ifndef WIN32 boost::filesystem::path GetPidFile() { boost::filesystem::path pathPidFile(GetArg("-pid", "bitcoind.pid")); @@ -477,7 +478,6 @@ boost::filesystem::path GetPidFile() return pathPidFile; } -#ifndef WIN32 void CreatePidFile(const boost::filesystem::path &path, pid_t pid) { FILE* file = fopen(path.string().c_str(), "w"); @@ -616,7 +616,7 @@ void ShrinkDebugFile() { // Restart the file with some of the end std::vector <char> vch(200000,0); - fseek(file, -vch.size(), SEEK_END); + fseek(file, -((long)vch.size()), SEEK_END); int nBytes = fread(begin_ptr(vch), 1, vch.size(), file); fclose(file); diff --git a/src/util.h b/src/util.h index e72c99adc7..4b2415278b 100644 --- a/src/util.h +++ b/src/util.h @@ -93,8 +93,8 @@ bool TryCreateDirectory(const boost::filesystem::path& p); boost::filesystem::path GetDefaultDataDir(); const boost::filesystem::path &GetDataDir(bool fNetSpecific = true); boost::filesystem::path GetConfigFile(); -boost::filesystem::path GetPidFile(); #ifndef WIN32 +boost::filesystem::path GetPidFile(); void CreatePidFile(const boost::filesystem::path &path, pid_t pid); #endif void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map<std::string, std::vector<std::string> >& mapMultiSettingsRet); diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp index c169355f05..1a5635bfb8 100644 --- a/src/utilmoneystr.cpp +++ b/src/utilmoneystr.cpp @@ -10,7 +10,7 @@ using namespace std; -string FormatMoney(int64_t n, bool fPlus) +string FormatMoney(const CAmount& n, bool fPlus) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. @@ -34,12 +34,12 @@ string FormatMoney(int64_t n, bool fPlus) } -bool ParseMoney(const string& str, int64_t& nRet) +bool ParseMoney(const string& str, CAmount& nRet) { return ParseMoney(str.c_str(), nRet); } -bool ParseMoney(const char* pszIn, int64_t& nRet) +bool ParseMoney(const char* pszIn, CAmount& nRet) { string strWhole; int64_t nUnits = 0; @@ -73,7 +73,7 @@ bool ParseMoney(const char* pszIn, int64_t& nRet) if (nUnits < 0 || nUnits > COIN) return false; int64_t nWhole = atoi64(strWhole); - int64_t nValue = nWhole*COIN + nUnits; + CAmount nValue = nWhole*COIN + nUnits; nRet = nValue; return true; diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h index f0c61aa138..65415afd3f 100644 --- a/src/utilmoneystr.h +++ b/src/utilmoneystr.h @@ -12,8 +12,10 @@ #include <stdint.h> #include <string> -std::string FormatMoney(int64_t n, bool fPlus=false); -bool ParseMoney(const std::string& str, int64_t& nRet); -bool ParseMoney(const char* pszIn, int64_t& nRet); +#include "amount.h" + +std::string FormatMoney(const CAmount& n, bool fPlus=false); +bool ParseMoney(const std::string& str, CAmount& nRet); +bool ParseMoney(const char* pszIn, CAmount& nRet); #endif // BITCOIN_UTILMONEYSTR_H diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 2cec3023b5..81e156f43f 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -9,14 +9,14 @@ #include <errno.h> #include <limits> - -#include <boost/foreach.hpp> +#include <cstdlib> +#include <cstring> using namespace std; // safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything // even possibly remotely dangerous like & or > -static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@"); +static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@()"); string SanitizeString(const string& str) { string strResult; @@ -53,9 +53,9 @@ signed char HexDigit(char c) bool IsHex(const string& str) { - BOOST_FOREACH(char c, str) + for(std::string::const_iterator it(str.begin()); it != str.end(); ++it) { - if (HexDigit(c) < 0) + if (HexDigit(*it) < 0) return false; } return (str.size() > 0) && (str.size()%2 == 0); diff --git a/src/version.cpp b/src/version.cpp index 95632fdab7..d12b681e5c 100644 --- a/src/version.cpp +++ b/src/version.cpp @@ -8,8 +8,6 @@ #include <string> -#include <boost/algorithm/string/join.hpp> - // Name of client reported in the 'version' message. Report the same name // for both bitcoind and bitcoin-qt, to make it harder for attackers to // target servers or GUI users specifically. @@ -94,7 +92,13 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const ss << "/"; ss << name << ":" << FormatVersion(nClientVersion); if (!comments.empty()) - ss << "(" << boost::algorithm::join(comments, "; ") << ")"; + { + std::vector<std::string>::const_iterator it(comments.begin()); + ss << "(" << *it; + for(++it; it != comments.end(); ++it) + ss << "; " << *it; + ss << ")"; + } ss << "/"; return ss.str(); } diff --git a/src/wallet.cpp b/src/wallet.cpp index 6bfaec3681..19e43f6ec2 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -15,6 +15,8 @@ #include "util.h" #include "utilmoneystr.h" +#include <assert.h> + #include <boost/algorithm/string/replace.hpp> #include <boost/thread.hpp> @@ -35,8 +37,8 @@ CFeeRate CWallet::minTxFee = CFeeRate(10000); // Override with -mintxfee struct CompareValueOnly { - bool operator()(const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t1, - const pair<int64_t, pair<const CWalletTx*, unsigned int> >& t2) const + bool operator()(const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t1, + const pair<CAmount, pair<const CWalletTx*, unsigned int> >& t2) const { return t1.first < t2.first; } @@ -87,6 +89,13 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) AssertLockHeld(cs_wallet); // mapKeyMetadata if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; + + // check if we need to remove from watch-only + CScript script; + script = GetScriptForDestination(pubkey.GetID()); + if (HaveWatchOnly(script)) + RemoveWatchOnly(script); + if (!fFileBacked) return true; if (!IsCrypted()) { @@ -169,6 +178,20 @@ bool CWallet::AddWatchOnly(const CScript &dest) return CWalletDB(strWalletFile).WriteWatchOnly(dest); } +bool CWallet::RemoveWatchOnly(const CScript &dest) +{ + AssertLockHeld(cs_wallet); + if (!CCryptoKeyStore::RemoveWatchOnly(dest)) + return false; + if (!HaveWatchOnly()) + NotifyWatchonlyChanged(false); + if (fFileBacked) + if (!CWalletDB(strWalletFile).EraseWatchOnly(dest)) + return false; + + return true; +} + bool CWallet::LoadWatchOnly(const CScript &dest) { return CCryptoKeyStore::AddWatchOnly(dest); @@ -426,17 +449,25 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) mapMasterKeys[++nMasterKeyMaxID] = kMasterKey; if (fFileBacked) { + assert(!pwalletdbEncryption); pwalletdbEncryption = new CWalletDB(strWalletFile); - if (!pwalletdbEncryption->TxnBegin()) + if (!pwalletdbEncryption->TxnBegin()) { + delete pwalletdbEncryption; + pwalletdbEncryption = NULL; return false; + } pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey); } if (!EncryptKeys(vMasterKey)) { - if (fFileBacked) + if (fFileBacked) { pwalletdbEncryption->TxnAbort(); - exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet. + delete pwalletdbEncryption; + } + // We now probably have half of our keys encrypted in memory, and half not... + // die and let the user reload their unencrypted wallet. + assert(false); } // Encryption was introduced in version 0.4.0 @@ -444,8 +475,12 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (fFileBacked) { - if (!pwalletdbEncryption->TxnCommit()) - exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet. + if (!pwalletdbEncryption->TxnCommit()) { + delete pwalletdbEncryption; + // We now have keys encrypted in memory, but no on disk... + // die to avoid confusion and let the user reload their unencrypted wallet. + assert(false); + } delete pwalletdbEncryption; pwalletdbEncryption = NULL; @@ -646,7 +681,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl CWalletTx wtx(this,tx); // Get merkle branch if transaction was found in a block if (pblock) - wtx.SetMerkleBranch(pblock); + wtx.SetMerkleBranch(*pblock); return AddToWallet(wtx); } } @@ -697,7 +732,7 @@ isminetype CWallet::IsMine(const CTxIn &txin) const return ISMINE_NO; } -int64_t CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const +CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const { { LOCK(cs_wallet); @@ -781,7 +816,7 @@ int CWalletTx::GetRequestCount() const } void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, - list<COutputEntry>& listSent, int64_t& nFee, string& strSentAccount, const isminefilter& filter) const + list<COutputEntry>& listSent, CAmount& nFee, string& strSentAccount, const isminefilter& filter) const { nFee = 0; listReceived.clear(); @@ -789,10 +824,10 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, strSentAccount = strFromAccount; // Compute fee: - int64_t nDebit = GetDebit(filter); + CAmount nDebit = GetDebit(filter); if (nDebit > 0) // debit>0 means we signed/sent this transaction { - int64_t nValueOut = GetValueOut(); + CAmount nValueOut = GetValueOut(); nFee = nDebit - nValueOut; } @@ -835,12 +870,12 @@ void CWalletTx::GetAmounts(list<COutputEntry>& listReceived, } -void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nReceived, - int64_t& nSent, int64_t& nFee, const isminefilter& filter) const +void CWalletTx::GetAccountAmounts(const string& strAccount, CAmount& nReceived, + CAmount& nSent, CAmount& nFee, const isminefilter& filter) const { nReceived = nSent = nFee = 0; - int64_t allFee; + CAmount allFee; string strSentAccount; list<COutputEntry> listReceived; list<COutputEntry> listSent; @@ -1011,9 +1046,9 @@ void CWallet::ResendWalletTransactions() // -int64_t CWallet::GetBalance() const +CAmount CWallet::GetBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1027,9 +1062,9 @@ int64_t CWallet::GetBalance() const return nTotal; } -int64_t CWallet::GetUnconfirmedBalance() const +CAmount CWallet::GetUnconfirmedBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1042,9 +1077,9 @@ int64_t CWallet::GetUnconfirmedBalance() const return nTotal; } -int64_t CWallet::GetImmatureBalance() const +CAmount CWallet::GetImmatureBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1056,9 +1091,9 @@ int64_t CWallet::GetImmatureBalance() const return nTotal; } -int64_t CWallet::GetWatchOnlyBalance() const +CAmount CWallet::GetWatchOnlyBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1068,13 +1103,13 @@ int64_t CWallet::GetWatchOnlyBalance() const nTotal += pcoin->GetAvailableWatchOnlyCredit(); } } - + return nTotal; } -int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const +CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1087,9 +1122,9 @@ int64_t CWallet::GetUnconfirmedWatchOnlyBalance() const return nTotal; } -int64_t CWallet::GetImmatureWatchOnlyBalance() const +CAmount CWallet::GetImmatureWatchOnlyBalance() const { - int64_t nTotal = 0; + CAmount nTotal = 0; { LOCK2(cs_main, cs_wallet); for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) @@ -1137,8 +1172,8 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const } } -static void ApproximateBestSubset(vector<pair<int64_t, pair<const CWalletTx*,unsigned int> > >vValue, int64_t nTotalLower, int64_t nTargetValue, - vector<char>& vfBest, int64_t& nBest, int iterations = 1000) +static void ApproximateBestSubset(vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > >vValue, const CAmount& nTotalLower, const CAmount& nTargetValue, + vector<char>& vfBest, CAmount& nBest, int iterations = 1000) { vector<char> vfIncluded; @@ -1150,7 +1185,7 @@ static void ApproximateBestSubset(vector<pair<int64_t, pair<const CWalletTx*,uns for (int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++) { vfIncluded.assign(vValue.size(), false); - int64_t nTotal = 0; + CAmount nTotal = 0; bool fReachedTarget = false; for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++) { @@ -1183,18 +1218,18 @@ static void ApproximateBestSubset(vector<pair<int64_t, pair<const CWalletTx*,uns } } -bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, - set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const +bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, vector<COutput> vCoins, + set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const { setCoinsRet.clear(); nValueRet = 0; // List of values less than target - pair<int64_t, pair<const CWalletTx*,unsigned int> > coinLowestLarger; - coinLowestLarger.first = std::numeric_limits<int64_t>::max(); + pair<CAmount, pair<const CWalletTx*,unsigned int> > coinLowestLarger; + coinLowestLarger.first = std::numeric_limits<CAmount>::max(); coinLowestLarger.second.first = NULL; - vector<pair<int64_t, pair<const CWalletTx*,unsigned int> > > vValue; - int64_t nTotalLower = 0; + vector<pair<CAmount, pair<const CWalletTx*,unsigned int> > > vValue; + CAmount nTotalLower = 0; random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt); @@ -1209,9 +1244,9 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT continue; int i = output.i; - int64_t n = pcoin->vout[i].nValue; + CAmount n = pcoin->vout[i].nValue; - pair<int64_t,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i)); + pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i)); if (n == nTargetValue) { @@ -1252,7 +1287,7 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT // Solve subset sum by stochastic approximation sort(vValue.rbegin(), vValue.rend(), CompareValueOnly()); vector<char> vfBest; - int64_t nBest; + CAmount nBest; ApproximateBestSubset(vValue, nTotalLower, nTargetValue, vfBest, nBest, 1000); if (nBest != nTargetValue && nTotalLower >= nTargetValue + CENT) @@ -1284,7 +1319,7 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT return true; } -bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl* coinControl) const +bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl* coinControl) const { vector<COutput> vCoins; AvailableCoins(vCoins, true, coinControl); @@ -1310,11 +1345,11 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign -bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, - CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) +bool CWallet::CreateTransaction(const vector<pair<CScript, CAmount> >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) { - int64_t nValue = 0; - BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend) + CAmount nValue = 0; + BOOST_FOREACH (const PAIRTYPE(CScript, CAmount)& s, vecSend) { if (nValue < 0) { @@ -1343,10 +1378,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, txNew.vout.clear(); wtxNew.fFromMe = true; - int64_t nTotalValue = nValue + nFeeRet; + CAmount nTotalValue = nValue + nFeeRet; double dPriority = 0; // vouts to the payees - BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend) + BOOST_FOREACH (const PAIRTYPE(CScript, CAmount)& s, vecSend) { CTxOut txout(s.second, s.first); if (txout.IsDust(::minRelayTxFee)) @@ -1359,7 +1394,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, // Choose coins to use set<pair<const CWalletTx*,unsigned int> > setCoins; - int64_t nValueIn = 0; + CAmount nValueIn = 0; if (!SelectCoins(nTotalValue, setCoins, nValueIn, coinControl)) { strFailReason = _("Insufficient funds"); @@ -1367,14 +1402,14 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, } BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins) { - int64_t nCredit = pcoin.first->vout[pcoin.second].nValue; + CAmount nCredit = pcoin.first->vout[pcoin.second].nValue; //The priority after the next block (depth+1) is used instead of the current, //reflecting an assumption the user would accept a bit more delay for //a chance at a free transaction. dPriority += (double)nCredit * (pcoin.first->GetDepthInMainChain()+1); } - int64_t nChange = nValueIn - nValue - nFeeRet; + CAmount nChange = nValueIn - nValue - nFeeRet; if (nChange > 0) { @@ -1450,7 +1485,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, } dPriority = wtxNew.ComputePriority(dPriority, nBytes); - int64_t nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool); + CAmount nFeeNeeded = GetMinimumFee(nBytes, nTxConfirmTarget, mempool); if (nFeeRet >= nFeeNeeded) break; // Done, enough fee included. @@ -1481,10 +1516,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, return true; } -bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, - CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) +bool CWallet::CreateTransaction(CScript scriptPubKey, const CAmount& nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl) { - vector< pair<CScript, int64_t> > vecSend; + vector< pair<CScript, CAmount> > vecSend; vecSend.push_back(make_pair(scriptPubKey, nValue)); return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet, strFailReason, coinControl); } @@ -1539,7 +1574,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) -string CWallet::SendMoney(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew) +string CWallet::SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew) { // Check amount if (nValue <= 0) @@ -1560,7 +1595,7 @@ string CWallet::SendMoney(const CTxDestination &address, int64_t nValue, CWallet // Create and send the transaction CReserveKey reservekey(this); - int64_t nFeeRequired; + CAmount nFeeRequired; if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) { if (nValue + nFeeRequired > GetBalance()) @@ -1576,10 +1611,10 @@ string CWallet::SendMoney(const CTxDestination &address, int64_t nValue, CWallet -int64_t CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) +CAmount CWallet::GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool) { // payTxFee is user-set "I want to pay this much" - int64_t nFeeNeeded = payTxFee.GetFee(nTxBytes); + CAmount nFeeNeeded = payTxFee.GetFee(nTxBytes); // User didn't set: use -txconfirmtarget to estimate... if (nFeeNeeded == 0) nFeeNeeded = pool.estimateFee(nConfirmTarget).GetFee(nTxBytes); @@ -1838,9 +1873,9 @@ int64_t CWallet::GetOldestKeyPoolTime() return keypool.nTime; } -std::map<CTxDestination, int64_t> CWallet::GetAddressBalances() +std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() { - map<CTxDestination, int64_t> balances; + map<CTxDestination, CAmount> balances; { LOCK(cs_wallet); @@ -1866,7 +1901,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances() if(!ExtractDestination(pcoin->vout[i].scriptPubKey, addr)) continue; - int64_t n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue; + CAmount n = IsSpent(walletEntry.first, i) ? 0 : pcoin->vout[i].nValue; if (!balances.count(addr)) balances[addr] = 0; @@ -2229,48 +2264,34 @@ CWalletKey::CWalletKey(int64_t nExpires) nTimeExpires = nExpires; } -int CMerkleTx::SetMerkleBranch(const CBlock* pblock) +int CMerkleTx::SetMerkleBranch(const CBlock& block) { AssertLockHeld(cs_main); CBlock blockTmp; - if (pblock == NULL) { - CCoins coins; - if (pcoinsTip->GetCoins(GetHash(), coins)) { - CBlockIndex *pindex = chainActive[coins.nHeight]; - if (pindex) { - if (!ReadBlockFromDisk(blockTmp, pindex)) - return 0; - pblock = &blockTmp; - } - } - } - - if (pblock) { - // Update the tx's hashBlock - hashBlock = pblock->GetHash(); - - // Locate the transaction - for (nIndex = 0; nIndex < (int)pblock->vtx.size(); nIndex++) - if (pblock->vtx[nIndex] == *(CTransaction*)this) - break; - if (nIndex == (int)pblock->vtx.size()) - { - vMerkleBranch.clear(); - nIndex = -1; - LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); - return 0; - } + // Update the tx's hashBlock + hashBlock = block.GetHash(); - // Fill in merkle branch - vMerkleBranch = pblock->GetMerkleBranch(nIndex); + // Locate the transaction + for (nIndex = 0; nIndex < (int)block.vtx.size(); nIndex++) + if (block.vtx[nIndex] == *(CTransaction*)this) + break; + if (nIndex == (int)block.vtx.size()) + { + vMerkleBranch.clear(); + nIndex = -1; + LogPrintf("ERROR: SetMerkleBranch() : couldn't find tx in block\n"); + return 0; } + // Fill in merkle branch + vMerkleBranch = block.GetMerkleBranch(nIndex); + // Is the tx in a block that's in the main chain BlockMap::iterator mi = mapBlockIndex.find(hashBlock); if (mi == mapBlockIndex.end()) return 0; - CBlockIndex* pindex = (*mi).second; + const CBlockIndex* pindex = (*mi).second; if (!pindex || !chainActive.Contains(pindex)) return 0; diff --git a/src/wallet.h b/src/wallet.h index 3461446b8b..fa8a94dfc1 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -30,9 +30,9 @@ extern unsigned int nTxConfirmTarget; extern bool bSpendZeroConfChange; // -paytxfee default -static const int64_t DEFAULT_TRANSACTION_FEE = 0; +static const CAmount DEFAULT_TRANSACTION_FEE = 0; // -paytxfee will warn if called with a higher fee than this amount (in satoshis) per KB -static const int nHighTransactionFeeWarning = 0.01 * COIN; +static const CAmount nHighTransactionFeeWarning = 0.01 * COIN; // Largest (in bytes) free transaction we're willing to create static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; @@ -98,7 +98,7 @@ public: class CWallet : public CCryptoKeyStore, public CWalletInterface { private: - bool SelectCoins(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl = NULL) const; + bool SelectCoins(const CAmount& nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, const CCoinControl *coinControl = NULL) const; CWalletDB *pwalletdbEncryption; @@ -143,6 +143,7 @@ public: { SetNull(); } + CWallet(std::string strWalletFileIn) { SetNull(); @@ -150,6 +151,13 @@ public: strWalletFile = strWalletFileIn; fFileBacked = true; } + + ~CWallet() + { + delete pwalletdbEncryption; + pwalletdbEncryption = NULL; + } + void SetNull() { nWalletVersion = FEATURE_BASE; @@ -182,7 +190,7 @@ public: bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const; - bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const; + bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet) const; bool IsSpent(const uint256& hash, unsigned int n) const; @@ -222,6 +230,7 @@ public: // Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnly(const CScript &dest); + bool RemoveWatchOnly(const CScript &dest); // Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) bool LoadWatchOnly(const CScript &dest); @@ -253,21 +262,21 @@ public: int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(); - int64_t GetBalance() const; - int64_t GetUnconfirmedBalance() const; - int64_t GetImmatureBalance() const; - int64_t GetWatchOnlyBalance() const; - int64_t GetUnconfirmedWatchOnlyBalance() const; - int64_t GetImmatureWatchOnlyBalance() const; - bool CreateTransaction(const std::vector<std::pair<CScript, int64_t> >& vecSend, - CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL); - bool CreateTransaction(CScript scriptPubKey, int64_t nValue, - CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL); + CAmount GetBalance() const; + CAmount GetUnconfirmedBalance() const; + CAmount GetImmatureBalance() const; + CAmount GetWatchOnlyBalance() const; + CAmount GetUnconfirmedWatchOnlyBalance() const; + CAmount GetImmatureWatchOnlyBalance() const; + bool CreateTransaction(const std::vector<std::pair<CScript, CAmount> >& vecSend, + CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL); + bool CreateTransaction(CScript scriptPubKey, const CAmount& nValue, + CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, std::string& strFailReason, const CCoinControl *coinControl = NULL); bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey); - std::string SendMoney(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew); + std::string SendMoney(const CTxDestination &address, CAmount nValue, CWalletTx& wtxNew); static CFeeRate minTxFee; - static int64_t GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool); + static CAmount GetMinimumFee(unsigned int nTxBytes, unsigned int nConfirmTarget, const CTxMemPool& pool); bool NewKeyPool(); bool TopUpKeyPool(unsigned int kpSize = 0); @@ -279,24 +288,24 @@ public: void GetAllReserveKeys(std::set<CKeyID>& setAddress) const; std::set< std::set<CTxDestination> > GetAddressGroupings(); - std::map<CTxDestination, int64_t> GetAddressBalances(); + std::map<CTxDestination, CAmount> GetAddressBalances(); std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const; isminetype IsMine(const CTxIn& txin) const; - int64_t GetDebit(const CTxIn& txin, const isminefilter& filter) const; + CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; isminetype IsMine(const CTxOut& txout) const { return ::IsMine(*this, txout.scriptPubKey); } - int64_t GetCredit(const CTxOut& txout, const isminefilter& filter) const + CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const { if (!MoneyRange(txout.nValue)) throw std::runtime_error("CWallet::GetCredit() : value out of range"); return ((IsMine(txout) & filter) ? txout.nValue : 0); } bool IsChange(const CTxOut& txout) const; - int64_t GetChange(const CTxOut& txout) const + CAmount GetChange(const CTxOut& txout) const { if (!MoneyRange(txout.nValue)) throw std::runtime_error("CWallet::GetChange() : value out of range"); @@ -313,9 +322,9 @@ public: { return (GetDebit(tx, ISMINE_ALL) > 0); } - int64_t GetDebit(const CTransaction& tx, const isminefilter& filter) const + CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const { - int64_t nDebit = 0; + CAmount nDebit = 0; BOOST_FOREACH(const CTxIn& txin, tx.vin) { nDebit += GetDebit(txin, filter); @@ -324,9 +333,9 @@ public: } return nDebit; } - int64_t GetCredit(const CTransaction& tx, const isminefilter& filter) const + CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const { - int64_t nCredit = 0; + CAmount nCredit = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { nCredit += GetCredit(txout, filter); @@ -335,9 +344,9 @@ public: } return nCredit; } - int64_t GetChange(const CTransaction& tx) const + CAmount GetChange(const CTransaction& tx) const { - int64_t nChange = 0; + CAmount nChange = 0; BOOST_FOREACH(const CTxOut& txout, tx.vout) { nChange += GetChange(txout); @@ -457,7 +466,7 @@ static void WriteOrderPos(const int64_t& nOrderPos, mapValue_t& mapValue) struct COutputEntry { CTxDestination destination; - int64_t amount; + CAmount amount; int vout; }; @@ -504,7 +513,7 @@ public: READWRITE(nIndex); } - int SetMerkleBranch(const CBlock* pblock=NULL); + int SetMerkleBranch(const CBlock& block); // Return depth of transaction in blockchain: // -1 : not in blockchain, and not in memory pool (conflicted transaction) @@ -545,15 +554,15 @@ public: mutable bool fImmatureWatchCreditCached; mutable bool fAvailableWatchCreditCached; mutable bool fChangeCached; - mutable int64_t nDebitCached; - mutable int64_t nCreditCached; - mutable int64_t nImmatureCreditCached; - mutable int64_t nAvailableCreditCached; - mutable int64_t nWatchDebitCached; - mutable int64_t nWatchCreditCached; - mutable int64_t nImmatureWatchCreditCached; - mutable int64_t nAvailableWatchCreditCached; - mutable int64_t nChangeCached; + mutable CAmount nDebitCached; + mutable CAmount nCreditCached; + mutable CAmount nImmatureCreditCached; + mutable CAmount nAvailableCreditCached; + mutable CAmount nWatchDebitCached; + mutable CAmount nWatchCreditCached; + mutable CAmount nImmatureWatchCreditCached; + mutable CAmount nAvailableWatchCreditCached; + mutable CAmount nChangeCached; CWalletTx() { @@ -670,12 +679,12 @@ public: } // filter decides which addresses will count towards the debit - int64_t GetDebit(const isminefilter& filter) const + CAmount GetDebit(const isminefilter& filter) const { if (vin.empty()) return 0; - int64_t debit = 0; + CAmount debit = 0; if(filter & ISMINE_SPENDABLE) { if (fDebitCached) @@ -701,21 +710,40 @@ public: return debit; } - int64_t GetCredit(bool fUseCache=true) const + CAmount GetCredit(const isminefilter& filter) const { // Must wait until coinbase is safely deep enough in the chain before valuing it if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; - // GetBalance can assume transactions in mapWallet won't change - if (fUseCache && fCreditCached) - return nCreditCached; - nCreditCached = pwallet->GetCredit(*this, ISMINE_ALL); - fCreditCached = true; - return nCreditCached; + int64_t credit = 0; + if (filter & ISMINE_SPENDABLE) + { + // GetBalance can assume transactions in mapWallet won't change + if (fCreditCached) + credit += nCreditCached; + else + { + nCreditCached = pwallet->GetCredit(*this, ISMINE_SPENDABLE); + fCreditCached = true; + credit += nCreditCached; + } + } + if (filter & ISMINE_WATCH_ONLY) + { + if (fWatchCreditCached) + credit += nWatchCreditCached; + else + { + nWatchCreditCached = pwallet->GetCredit(*this, ISMINE_WATCH_ONLY); + fWatchCreditCached = true; + credit += nWatchCreditCached; + } + } + return credit; } - int64_t GetImmatureCredit(bool fUseCache=true) const + CAmount GetImmatureCredit(bool fUseCache=true) const { if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { @@ -729,7 +757,7 @@ public: return 0; } - int64_t GetAvailableCredit(bool fUseCache=true) const + CAmount GetAvailableCredit(bool fUseCache=true) const { if (pwallet == 0) return 0; @@ -741,7 +769,7 @@ public: if (fUseCache && fAvailableCreditCached) return nAvailableCreditCached; - int64_t nCredit = 0; + CAmount nCredit = 0; uint256 hashTx = GetHash(); for (unsigned int i = 0; i < vout.size(); i++) { @@ -759,7 +787,7 @@ public: return nCredit; } - int64_t GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const + CAmount GetImmatureWatchOnlyCredit(const bool& fUseCache=true) const { if (IsCoinBase() && GetBlocksToMaturity() > 0 && IsInMainChain()) { @@ -773,7 +801,7 @@ public: return 0; } - int64_t GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const + CAmount GetAvailableWatchOnlyCredit(const bool& fUseCache=true) const { if (pwallet == 0) return 0; @@ -785,7 +813,7 @@ public: if (fUseCache && fAvailableWatchCreditCached) return nAvailableWatchCreditCached; - int64_t nCredit = 0; + CAmount nCredit = 0; for (unsigned int i = 0; i < vout.size(); i++) { if (!pwallet->IsSpent(GetHash(), i)) @@ -802,7 +830,7 @@ public: return nCredit; } - int64_t GetChange() const + CAmount GetChange() const { if (fChangeCached) return nChangeCached; @@ -812,10 +840,10 @@ public: } void GetAmounts(std::list<COutputEntry>& listReceived, - std::list<COutputEntry>& listSent, int64_t& nFee, std::string& strSentAccount, const isminefilter& filter) const; + std::list<COutputEntry>& listSent, CAmount& nFee, std::string& strSentAccount, const isminefilter& filter) const; - void GetAccountAmounts(const std::string& strAccount, int64_t& nReceived, - int64_t& nSent, int64_t& nFee, const isminefilter& filter) const; + void GetAccountAmounts(const std::string& strAccount, CAmount& nReceived, + CAmount& nSent, CAmount& nFee, const isminefilter& filter) const; bool IsFromMe(const isminefilter& filter) const { @@ -949,7 +977,7 @@ class CAccountingEntry { public: std::string strAccount; - int64_t nCreditDebit; + CAmount nCreditDebit; int64_t nTime; std::string strOtherAccount; std::string strComment; diff --git a/src/walletdb.cpp b/src/walletdb.cpp index a84f44db01..ffddd8106b 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -15,11 +15,11 @@ #include <boost/filesystem.hpp> #include <boost/foreach.hpp> +#include <boost/scoped_ptr.hpp> #include <boost/thread.hpp> -using namespace std; using namespace boost; - +using namespace std; static uint64_t nAccountingEntryNumber = 0; @@ -121,6 +121,12 @@ bool CWalletDB::WriteWatchOnly(const CScript &dest) return Write(std::make_pair(std::string("watchs"), dest), '1'); } +bool CWalletDB::EraseWatchOnly(const CScript &dest) +{ + nWalletDBUpdated++; + return Erase(std::make_pair(std::string("watchs"), dest)); +} + bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) { nWalletDBUpdated++; @@ -179,7 +185,7 @@ bool CWalletDB::WriteAccount(const string& strAccount, const CAccount& account) bool CWalletDB::WriteAccountingEntry(const uint64_t nAccEntryNum, const CAccountingEntry& acentry) { - return Write(boost::make_tuple(string("acentry"), acentry.strAccount, nAccEntryNum), acentry); + return Write(std::make_pair(std::string("acentry"), std::make_pair(acentry.strAccount, nAccEntryNum)), acentry); } bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) @@ -187,12 +193,12 @@ bool CWalletDB::WriteAccountingEntry(const CAccountingEntry& acentry) return WriteAccountingEntry(++nAccountingEntryNumber, acentry); } -int64_t CWalletDB::GetAccountCreditDebit(const string& strAccount) +CAmount CWalletDB::GetAccountCreditDebit(const string& strAccount) { list<CAccountingEntry> entries; ListAccountCreditDebit(strAccount, entries); - int64_t nCreditDebit = 0; + CAmount nCreditDebit = 0; BOOST_FOREACH (const CAccountingEntry& entry, entries) nCreditDebit += entry.nCreditDebit; @@ -212,7 +218,7 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin // Read next record CDataStream ssKey(SER_DISK, CLIENT_VERSION); if (fFlags == DB_SET_RANGE) - ssKey << boost::make_tuple(string("acentry"), (fAllAccounts? string("") : strAccount), uint64_t(0)); + ssKey << std::make_pair(std::string("acentry"), std::make_pair((fAllAccounts ? string("") : strAccount), uint64_t(0))); CDataStream ssValue(SER_DISK, CLIENT_VERSION); int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags); fFlags = DB_NEXT; @@ -391,13 +397,6 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, wss.fAnyUnordered = true; pwallet->AddToWallet(wtx, true); - //// debug print - //LogPrintf("LoadWallet %s\n", wtx.GetHash().ToString()); - //LogPrintf(" %12d %s %s %s\n", - // wtx.vout[0].nValue, - // DateTimeStrFormat("%Y-%m-%d %H:%M:%S", wtx.GetBlockTime()), - // wtx.hashBlock.ToString(), - // wtx.mapValue["message"]); } else if (strType == "acentry") { @@ -708,7 +707,6 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) DBErrors CWalletDB::FindWalletTx(CWallet* pwallet, vector<uint256>& vTxHash, vector<CWalletTx>& vWtx) { pwallet->vchDefaultKey = CPubKey(); - CWalletScanState wss; bool fNoncriticalErrors = false; DBErrors result = DB_LOAD_OK; @@ -926,7 +924,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size()); bool fSuccess = allOK; - Db* pdbCopy = new Db(&dbenv.dbenv, 0); + boost::scoped_ptr<Db> pdbCopy(new Db(&dbenv.dbenv, 0)); int ret = pdbCopy->open(NULL, // Txn pointer filename.c_str(), // Filename "main", // Logical db name @@ -967,7 +965,6 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) } ptxn->commit(0); pdbCopy->close(0); - delete pdbCopy; return fSuccess; } @@ -980,11 +977,11 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename) bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value) { nWalletDBUpdated++; - return Write(boost::make_tuple(std::string("destdata"), address, key), value); + return Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); } bool CWalletDB::EraseDestData(const std::string &address, const std::string &key) { nWalletDBUpdated++; - return Erase(boost::make_tuple(string("destdata"), address, key)); + return Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key))); } diff --git a/src/walletdb.h b/src/walletdb.h index 2c5b608f3d..7ff41c7c8d 100644 --- a/src/walletdb.h +++ b/src/walletdb.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_WALLETDB_H #define BITCOIN_WALLETDB_H +#include "amount.h" #include "db.h" #include "key.h" #include "keystore.h" @@ -95,6 +96,7 @@ public: bool WriteCScript(const uint160& hash, const CScript& redeemScript); bool WriteWatchOnly(const CScript &script); + bool EraseWatchOnly(const CScript &script); bool WriteBestBlock(const CBlockLocator& locator); bool ReadBestBlock(CBlockLocator& locator); @@ -118,7 +120,7 @@ public: bool EraseDestData(const std::string &address, const std::string &key); bool WriteAccountingEntry(const CAccountingEntry& acentry); - int64_t GetAccountCreditDebit(const std::string& strAccount); + CAmount GetAccountCreditDebit(const std::string& strAccount); void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries); DBErrors ReorderTransactions(CWallet* pwallet); |