diff options
-rw-r--r-- | COPYING | 2 | ||||
-rw-r--r-- | README.md | 37 | ||||
-rw-r--r-- | doc/README.md | 2 | ||||
-rw-r--r-- | doc/assets-attribution.md | 32 | ||||
-rw-r--r-- | doc/developer-notes.md (renamed from doc/coding.md) | 48 | ||||
-rw-r--r-- | doc/gitian-building.md | 2 | ||||
-rw-r--r-- | src/Makefile.qt.include | 7 | ||||
-rw-r--r-- | src/Makefile.test.include | 7 | ||||
-rw-r--r-- | src/bitcoin-tx.cpp | 6 | ||||
-rw-r--r-- | src/chainparams.cpp | 1 | ||||
-rw-r--r-- | src/coins.cpp | 22 | ||||
-rw-r--r-- | src/coins.h | 6 | ||||
-rw-r--r-- | src/core_io.h | 1 | ||||
-rw-r--r-- | src/core_read.cpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 149 | ||||
-rw-r--r-- | src/main.h | 21 | ||||
-rw-r--r-- | src/miner.cpp | 3 | ||||
-rw-r--r-- | src/qt/forms/addressbookpage.ui | 2 | ||||
-rw-r--r-- | src/qt/forms/optionsdialog.ui | 2 | ||||
-rw-r--r-- | src/rpcmining.cpp | 3 | ||||
-rw-r--r-- | src/rpcmisc.cpp | 5 | ||||
-rw-r--r-- | src/rpcserver.cpp | 16 | ||||
-rw-r--r-- | src/rpcwallet.cpp | 4 | ||||
-rw-r--r-- | src/test/data/bitcoin-util-test.json | 10 | ||||
-rw-r--r-- | src/test/data/txcreatesign.hex | 1 | ||||
-rw-r--r-- | src/test/rpc_wallet_tests.cpp | 37 | ||||
-rw-r--r-- | src/txmempool.cpp | 7 | ||||
-rw-r--r-- | src/undo.h | 14 |
28 files changed, 257 insertions, 195 deletions
@@ -1,4 +1,4 @@ -Copyright (c) 2009-2014 Bitcoin Developers +Copyright (c) 2009-2015 Bitcoin Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ submitter will be asked to start a discussion (if they haven't already) on the The patch will be accepted if there is broad consensus that it is a good thing. Developers should expect to rework and resubmit patches if the code doesn't -match the project's coding conventions (see [doc/coding.md](doc/coding.md)) or are +match the project's coding conventions (see [doc/developer-notes.md](doc/developer-notes.md)) or are controversial. The `master` branch is regularly built and tested, but is not guaranteed to be @@ -85,38 +85,3 @@ Translations are periodically pulled from Transifex and merged into the git repo pull from Transifex would automatically overwrite them again. Translators should also subscribe to the [mailing list](https://groups.google.com/forum/#!forum/bitcoin-translators). - -Development tips and tricks ---------------------------- - -**compiling for debugging** - -Run configure with the --enable-debug option, then make. Or run configure with -CXXFLAGS="-g -ggdb -O0" or whatever debug flags you need. - -**debug.log** - -If the code is behaving strangely, take a look in the debug.log file in the data directory; -error and debugging messages are written there. - -The -debug=... command-line option controls debugging; running with just -debug will turn -on all categories (and give you a very large debug.log file). - -The Qt code routes qDebug() output to debug.log under category "qt": run with -debug=qt -to see it. - -**testnet and regtest modes** - -Run with the -testnet option to run with "play bitcoins" on the test network, if you -are testing multi-machine code that needs to operate across the internet. - -If you are testing something that can run on one machine, run with the -regtest option. -In regression test mode, blocks can be created on-demand; see qa/rpc-tests/ for tests -that run in -regtest mode. - -**DEBUG_LOCKORDER** - -Bitcoin Core is a multithreaded application, and deadlocks or other multithreading bugs -can be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure -CXXFLAGS="-DDEBUG_LOCKORDER -g") inserts run-time checks to keep track of which locks -are held, and adds warnings to the debug.log file if inconsistencies are detected. diff --git a/doc/README.md b/doc/README.md index ecb8dc80fd..1696518f87 100644 --- a/doc/README.md +++ b/doc/README.md @@ -51,7 +51,7 @@ Development --------------------- The Bitcoin repo's [root README](https://github.com/bitcoin/bitcoin/blob/master/README.md) contains relevant information on the development process and automated testing. -- [Coding Guidelines](coding.md) +- [Developer Notes](developer-notes.md) - [Multiwallet Qt Development](multiwallet-qt.md) - [Release Notes](release-notes.md) - [Release Process](release-process.md) diff --git a/doc/assets-attribution.md b/doc/assets-attribution.md index 6c5f91a834..31fe4e5b7a 100644 --- a/doc/assets-attribution.md +++ b/doc/assets-attribution.md @@ -1,14 +1,5 @@ The following is a list of assets used in the bitcoin source and their proper attribution. -[Wladimir van der Laan](https://github.com/laanwj) ------------------------ -#### Info -* License: MIT - -### Assets Used - src/qt/res/icons/watch*.png, src/qt/res/icons/tx_in.png, - src/qt/res/icons/tx_inout.png, - [Typicons/Stephen Hutchings](http://typicons.com) ----------------------- @@ -30,7 +21,7 @@ The following is a list of assets used in the bitcoin source and their proper at src/qt/res/icons/overview.png, src/qt/res/icons/quit.png, src/qt/res/icons/receive.png, src/qt/res/icons/remove.png, src/qt/res/icons/send.png, src/qt/res/icons/synced.png, - src/qt/res/icons/transaction*.png, src/qt/res/icons/tx_input.png, + src/qt/res/icons/transaction*.png, src/qt/res/icons/tx_output.png, Jonas Schnelli ----------------------- @@ -38,18 +29,19 @@ Jonas Schnelli ### Info * Designer: Jonas Schnelli * Bitcoin Icon: (based on the original bitcoin logo from Bitboy) -* Some icons are based on Stephan Hutchings Typicons +* Some icons are based on Stephan Hutchings Typicons (these are under CC BY-SA license) * License: MIT ### Assets Used src/qt/res/icons/about.png, src/qt/res/icons/about_qt.png, - src/qt/res/icons/clock*.png, src/qt/res/icons/connect[0-3].png, - src/qt/res/icons/eye_minus.png, src/qt/res/icons/verify.png, - src/qt/res/icons/eye_plus.png, src/qt/res/icons/tx_inout.png, - src/qt/res/icons/tx_output.png, src/qt/res/icons/bitcoin.icns, - src/qt/res/src/bitcoin.svg, src/qt/res/src/bitcoin.ico, - src/qt/res/src/bitcoin.png, src/qt/res/src/bitcoin_testnet.png, - docs/bitcoin_logo_doxygen.png, src/qt/res/src/tx*.svg, - src/qt/res/src/connect*.svg, src/qt/res/src/clock*.svg, - src/qt/res/src/mine.svg, src/qt/res/src/qt.svg, + src/qt/res/icons/bitcoin.icns, src/qt/res/icons/bitcoin.ico, + src/qt/res/icons/bitcoin.png, src/qt/res/icons/clock*.png, + src/qt/res/icons/connect[0-3].png, src/qt/res/icons/eye_minus.png, + src/qt/res/icons/eye_plus.png, src/qt/res/icons/verify.png, + src/qt/res/icons/tx_inout.png, src/qt/res/icons/tx_input.png, + src/qt/res/icons/unit_btc.png, src/qt/res/icons/unit_mbtc.png, + src/qt/res/icons/unit_ubtc.png, src/qt/res/src/verify.svg + src/qt/res/src/bitcoin.svg, src/qt/res/src/clock*.svg, + src/qt/res/src/connect*.svg, src/qt/res/src/mine.svg, + src/qt/res/src/qt.svg, src/qt/res/src/tx*.svg, src/qt/res/src/verify.svg, diff --git a/doc/coding.md b/doc/developer-notes.md index 43294dbe4c..eaeb90da1d 100644 --- a/doc/coding.md +++ b/doc/developer-notes.md @@ -89,6 +89,41 @@ Not OK (used plenty in the current source, but not picked up): A full list of comment syntaxes picked up by doxygen can be found at http://www.stack.nl/~dimitri/doxygen/manual/docblocks.html, but if possible use one of the above styles. +Development tips and tricks +--------------------------- + +**compiling for debugging** + +Run configure with the --enable-debug option, then make. Or run configure with +CXXFLAGS="-g -ggdb -O0" or whatever debug flags you need. + +**debug.log** + +If the code is behaving strangely, take a look in the debug.log file in the data directory; +error and debugging messages are written there. + +The -debug=... command-line option controls debugging; running with just -debug will turn +on all categories (and give you a very large debug.log file). + +The Qt code routes qDebug() output to debug.log under category "qt": run with -debug=qt +to see it. + +**testnet and regtest modes** + +Run with the -testnet option to run with "play bitcoins" on the test network, if you +are testing multi-machine code that needs to operate across the internet. + +If you are testing something that can run on one machine, run with the -regtest option. +In regression test mode, blocks can be created on-demand; see qa/rpc-tests/ for tests +that run in -regtest mode. + +**DEBUG_LOCKORDER** + +Bitcoin Core is a multithreaded application, and deadlocks or other multithreading bugs +can be very difficult to track down. Compiling with -DDEBUG_LOCKORDER (configure +CXXFLAGS="-DDEBUG_LOCKORDER -g") inserts run-time checks to keep track of which locks +are held, and adds warnings to the debug.log file if inconsistencies are detected. + Locking/mutex usage notes ------------------------- @@ -136,3 +171,16 @@ Threads - BitcoinMiner : Generates bitcoins (if wallet is enabled). - Shutdown : Does an orderly shutdown of everything. + +Pull Request Terminology +------------------------ + +Concept ACK - Agree with the idea and overall direction, but haven't reviewed the code changes or tested them. + +utACK (untested ACK) - Reviewed and agree with the code changes but haven't actually tested them. + +Tested ACK - Reviewed the code changes and have verified the functionality or bug fix. + +ACK - A loose ACK can be confusing. It's best to avoid them unless it's a documentation/comment only change in which case there is nothing to test/verify; therefore the tested/untested distinction is not there. + +NACK - Disagree with the code changes/concept. Should be accompanied by an explanation. diff --git a/doc/gitian-building.md b/doc/gitian-building.md index defddedc6e..1312979cac 100644 --- a/doc/gitian-building.md +++ b/doc/gitian-building.md @@ -83,7 +83,7 @@ Unixy OSes by entering the following in a terminal: After creating the VM, we need to configure it. -- Click the `Settings` button, then go to the `Network` tab. Adapter 1 should be attacked to `NAT`. +- Click the `Settings` button, then go to the `Network` tab. Adapter 1 should be attached to `NAT`. ![](gitian-building/network_settings.png) diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 806b4f9556..1192b7bd4e 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -278,8 +278,11 @@ BITCOIN_QT_CPP = \ qt/scicon.cpp \ qt/splashscreen.cpp \ qt/trafficgraphwidget.cpp \ - qt/utilitydialog.cpp \ - qt/winshutdownmonitor.cpp + qt/utilitydialog.cpp + +if TARGET_WINDOWS +BITCOIN_QT_CPP += qt/winshutdownmonitor.cpp +endif if ENABLE_WALLET BITCOIN_QT_CPP += \ diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 9e9f478d8f..5f388e2806 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -1,4 +1,4 @@ -TESTS += test/test_bitcoin test/bitcoin-util-test.py +TESTS += test/test_bitcoin bin_PROGRAMS += test/test_bitcoin TEST_SRCDIR = test TEST_BINARY=test/test_bitcoin$(EXEEXT) @@ -14,7 +14,8 @@ EXTRA_DIST += \ test/data/tt-locktime317000-out.hex \ test/data/tx394b54bb.hex \ test/data/txcreate1.hex \ - test/data/txcreate2.hex + test/data/txcreate2.hex \ + test/data/txcreatesign.hex JSON_TEST_FILES = \ test/data/script_valid.json \ @@ -105,6 +106,8 @@ bitcoin_test_clean : FORCE rm -f $(CLEAN_BITCOIN_TEST) $(test_test_bitcoin_OBJECTS) $(TEST_BINARY) check-local: + @echo "Running test/bitcoin-util-test.py..." + $(AM_V_at)srcdir=$(srcdir) PYTHONPATH=$(builddir)/test $(srcdir)/test/bitcoin-util-test.py $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check %.json.h: %.json diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 337cd44cd9..05a85810ec 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -368,7 +368,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) // Add previous txouts given in the RPC call: if (!registers.count("prevtxs")) throw runtime_error("prevtxs register variable must be set."); - UniValue prevtxsObj = registers["privatekeys"]; + UniValue prevtxsObj = registers["prevtxs"]; { for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) { UniValue prevOut = prevtxsObj[previdx]; @@ -379,13 +379,13 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr) if (!prevOut.checkObject(types)) throw runtime_error("prevtxs internal object typecheck fail"); - uint256 txid = ParseHashUV(prevOut, "txid"); + uint256 txid = ParseHashUV(prevOut["txid"], "txid"); int nOut = atoi(prevOut["vout"].getValStr()); if (nOut < 0) throw runtime_error("vout must be positive"); - vector<unsigned char> pkData(ParseHexUV(prevOut, "scriptPubKey")); + vector<unsigned char> pkData(ParseHexUV(prevOut["scriptPubKey"], "scriptPubKey")); CScript scriptPubKey(pkData.begin(), pkData.end()); { diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7562509bd5..f4bc6e1d70 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -156,7 +156,6 @@ public: vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); - vSeeds.push_back(CDNSSeedData("bitnodes.io", "seed.bitnodes.io")); vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); base58Prefixes[PUBKEY_ADDRESS] = list_of(0); diff --git a/src/coins.cpp b/src/coins.cpp index bc430c9c7e..f4599ff39d 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -31,29 +31,15 @@ void CCoins::CalcMaskSize(unsigned int &nBytes, unsigned int &nNonzeroBytes) con nBytes += nLastUsedByte; } -bool CCoins::Spend(const COutPoint &out, CTxInUndo &undo) { - if (out.n >= vout.size()) - return false; - if (vout[out.n].IsNull()) +bool CCoins::Spend(uint32_t nPos) +{ + if (nPos >= vout.size() || vout[nPos].IsNull()) return false; - undo = CTxInUndo(vout[out.n]); - vout[out.n].SetNull(); + vout[nPos].SetNull(); Cleanup(); - if (vout.size() == 0) { - undo.nHeight = nHeight; - undo.fCoinBase = fCoinBase; - undo.nVersion = this->nVersion; - } return true; } -bool CCoins::Spend(int nPos) { - CTxInUndo undo; - COutPoint out(0, nPos); - return Spend(out, undo); -} - - bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) const { return false; } uint256 CCoinsView::GetBestBlock() const { return uint256(0); } diff --git a/src/coins.h b/src/coins.h index 9b73ae3a87..2be52ad171 100644 --- a/src/coins.h +++ b/src/coins.h @@ -9,7 +9,6 @@ #include "compressor.h" #include "serialize.h" #include "uint256.h" -#include "undo.h" #include <assert.h> #include <stdint.h> @@ -237,11 +236,8 @@ public: Cleanup(); } - //! mark an outpoint spent, and construct undo information - bool Spend(const COutPoint &out, CTxInUndo &undo); - //! mark a vout spent - bool Spend(int nPos); + bool Spend(uint32_t nPos); //! check whether a particular output is still available bool IsAvailable(unsigned int nPos) const { diff --git a/src/core_io.h b/src/core_io.h index e0620e86b6..0989cf7437 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -19,6 +19,7 @@ extern CScript ParseScript(std::string s); extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); extern uint256 ParseHashUV(const UniValue& v, const std::string& strName); +extern uint256 ParseHashStr(const std::string&, const std::string& strName); extern std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); // core_write.cpp diff --git a/src/core_read.cpp b/src/core_read.cpp index a49705e045..7999030662 100644 --- a/src/core_read.cpp +++ b/src/core_read.cpp @@ -131,6 +131,11 @@ uint256 ParseHashUV(const UniValue& v, const string& strName) string strHex; if (v.isStr()) strHex = v.getValStr(); + return ParseHashStr(strHex, strName); // Note: ParseHashStr("") throws a runtime_error +} + +uint256 ParseHashStr(const std::string& strHex, const std::string& strName) +{ if (!IsHex(strHex)) // Note: IsHex("") is false throw runtime_error(strName+" must be hexadecimal string (not '"+strHex+"')"); diff --git a/src/main.cpp b/src/main.cpp index 2410230ef4..5c0f0116d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -17,6 +17,7 @@ #include "txdb.h" #include "txmempool.h" #include "ui_interface.h" +#include "undo.h" #include "util.h" #include "utilmoneystr.h" @@ -926,11 +927,11 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa *pfMissingInputs = false; if (!CheckTransaction(tx, state)) - return error("AcceptToMemoryPool: : CheckTransaction failed"); + return error("AcceptToMemoryPool: CheckTransaction failed"); // Coinbase is only valid in a block, not as a loose transaction if (tx.IsCoinBase()) - return state.DoS(100, error("AcceptToMemoryPool: : coinbase as individual tx"), + return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"), REJECT_INVALID, "coinbase"); // Rather not work on nonstandard transactions (unless -testnet/-regtest) @@ -1000,7 +1001,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // Check for non-standard pay-to-script-hash in inputs if (Params().RequireStandard() && !AreInputsStandard(tx, view)) - return error("AcceptToMemoryPool: : nonstandard transaction input"); + return error("AcceptToMemoryPool: nonstandard transaction input"); // Check that the transaction doesn't have an excessive number of // sigops, making it impossible to mine. Since the coinbase transaction @@ -1076,7 +1077,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // can be exploited as a DoS attack. if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) { - return error("AcceptToMemoryPool: : BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); + return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } // Store transaction in memory @@ -1383,9 +1384,20 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach if (!tx.IsCoinBase()) { txundo.vprevout.reserve(tx.vin.size()); BOOST_FOREACH(const CTxIn &txin, tx.vin) { - txundo.vprevout.push_back(CTxInUndo()); - bool ret = inputs.ModifyCoins(txin.prevout.hash)->Spend(txin.prevout, txundo.vprevout.back()); - assert(ret); + CCoinsModifier coins = inputs.ModifyCoins(txin.prevout.hash); + unsigned nPos = txin.prevout.n; + + if (nPos >= coins->vout.size() || coins->vout[nPos].IsNull()) + assert(false); + // mark an outpoint spent, and construct undo information + txundo.vprevout.push_back(CTxInUndo(coins->vout[nPos])); + coins->Spend(nPos); + if (coins->vout.size() == 0) { + CTxInUndo& undo = txundo.vprevout.back(); + undo.nHeight = coins->nHeight; + undo.fCoinBase = coins->fCoinBase; + undo.nVersion = coins->nVersion; + } } } @@ -1393,6 +1405,12 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach inputs.ModifyCoins(tx.GetHash())->FromTx(tx, nHeight); } +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight) +{ + CTxUndo txundo; + UpdateCoins(tx, state, inputs, txundo, nHeight); +} + bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingSignatureChecker(*ptxTo, nIn, cacheStore), &error)) { @@ -1503,7 +1521,63 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi return true; } +namespace { + +bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock) +{ + // Open history file to append + CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); + if (fileout.IsNull()) + return error("%s : OpenUndoFile failed", __func__); + + // Write index header + unsigned int nSize = fileout.GetSerializeSize(blockundo); + fileout << FLATDATA(Params().MessageStart()) << nSize; + + // Write undo data + long fileOutPos = ftell(fileout.Get()); + if (fileOutPos < 0) + return error("%s : ftell failed", __func__); + pos.nPos = (unsigned int)fileOutPos; + fileout << blockundo; + + // calculate & write checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + fileout << hasher.GetHash(); + return true; +} + +bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uint256& hashBlock) +{ + // Open history file to read + CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); + if (filein.IsNull()) + return error("%s : OpenBlockFile failed", __func__); + + // Read block + uint256 hashChecksum; + try { + filein >> blockundo; + filein >> hashChecksum; + } + catch (const std::exception& e) { + return error("%s : Deserialize or I/O error - %s", __func__, e.what()); + } + + // Verify checksum + CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); + hasher << hashBlock; + hasher << blockundo; + if (hashChecksum != hasher.GetHash()) + return error("%s : Checksum mismatch", __func__); + + return true; +} + +} // anon namespace bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean) { @@ -1518,7 +1592,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex CDiskBlockPos pos = pindex->GetUndoPos(); if (pos.IsNull()) return error("DisconnectBlock() : no undo data available"); - if (!blockUndo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) + if (!UndoReadFromDisk(blockUndo, pos, pindex->pprev->GetBlockHash())) return error("DisconnectBlock() : failure reading undo data"); if (blockUndo.vtxundo.size() + 1 != block.vtx.size()) @@ -1760,7 +1834,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CDiskBlockPos pos; 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())) + if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash())) return state.Abort("Failed to write undo data"); // update nUndoPos in block index @@ -2926,7 +3000,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth CBlockUndo undo; CDiskBlockPos pos = pindex->GetUndoPos(); if (!pos.IsNull()) { - if (!undo.ReadFromDisk(pos, pindex->pprev->GetBlockHash())) + if (!UndoReadFromDisk(undo, pos, pindex->pprev->GetBlockHash())) return error("VerifyDB() : *** found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); } } @@ -4491,61 +4565,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle) return true; } - -bool CBlockUndo::WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock) -{ - // Open history file to append - CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION); - if (fileout.IsNull()) - return error("CBlockUndo::WriteToDisk : OpenUndoFile failed"); - - // Write index header - unsigned int nSize = fileout.GetSerializeSize(*this); - fileout << FLATDATA(Params().MessageStart()) << nSize; - - // Write undo data - long fileOutPos = ftell(fileout.Get()); - if (fileOutPos < 0) - return error("CBlockUndo::WriteToDisk : ftell failed"); - pos.nPos = (unsigned int)fileOutPos; - fileout << *this; - - // calculate & write checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - fileout << hasher.GetHash(); - - return true; -} - -bool CBlockUndo::ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock) -{ - // Open history file to read - CAutoFile filein(OpenUndoFile(pos, true), SER_DISK, CLIENT_VERSION); - if (filein.IsNull()) - return error("CBlockUndo::ReadFromDisk : OpenBlockFile failed"); - - // Read block - uint256 hashChecksum; - try { - filein >> *this; - filein >> hashChecksum; - } - catch (const std::exception& e) { - return error("%s : Deserialize or I/O error - %s", __func__, e.what()); - } - - // Verify checksum - CHashWriter hasher(SER_GETHASH, PROTOCOL_VERSION); - hasher << hashBlock; - hasher << *this; - if (hashChecksum != hasher.GetHash()) - return error("CBlockUndo::ReadFromDisk : Checksum mismatch"); - - return true; -} - std::string CBlockFileInfo::ToString() const { return strprintf("CBlockFileInfo(blocks=%u, size=%u, heights=%u...%u, time=%s...%s)", nBlocks, nSize, nHeightFirst, nHeightLast, DateTimeStrFormat("%Y-%m-%d", nTimeFirst), DateTimeStrFormat("%Y-%m-%d", nTimeLast)); } diff --git a/src/main.h b/src/main.h index 662d5756f7..9049f5bb7d 100644 --- a/src/main.h +++ b/src/main.h @@ -25,7 +25,6 @@ #include "tinyformat.h" #include "txmempool.h" #include "uint256.h" -#include "undo.h" #include <algorithm> #include <exception> @@ -290,7 +289,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi 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); +void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); /** Context-independent validity checks */ bool CheckTransaction(const CTransaction& tx, CValidationState& state); @@ -302,24 +301,6 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason); bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0); -/** Undo information for a CBlock */ -class CBlockUndo -{ -public: - std::vector<CTxUndo> vtxundo; // for all but the coinbase - - ADD_SERIALIZE_METHODS; - - template <typename Stream, typename Operation> - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(vtxundo); - } - - bool WriteToDisk(CDiskBlockPos &pos, const uint256 &hashBlock); - bool ReadFromDisk(const CDiskBlockPos &pos, const uint256 &hashBlock); -}; - - /** * Closure representing one script verification * Note that this stores references to the spending transaction diff --git a/src/miner.cpp b/src/miner.cpp index 2133b13e62..0ac974d6e1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -279,8 +279,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true)) continue; - CTxUndo txundo; - UpdateCoins(tx, state, view, txundo, nHeight); + UpdateCoins(tx, state, view, nHeight); // Added pblock->vtx.push_back(tx); diff --git a/src/qt/forms/addressbookpage.ui b/src/qt/forms/addressbookpage.ui index 52fdc6ef06..264edeb720 100644 --- a/src/qt/forms/addressbookpage.ui +++ b/src/qt/forms/addressbookpage.ui @@ -27,7 +27,7 @@ <enum>Qt::CustomContextMenu</enum> </property> <property name="toolTip"> - <string>Double-click to edit address or label</string> + <string>Right-click to edit address or label</string> </property> <property name="tabKeyNavigation"> <bool>false</bool> diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui index 19421dc813..55c4f5ac58 100644 --- a/src/qt/forms/optionsdialog.ui +++ b/src/qt/forms/optionsdialog.ui @@ -330,7 +330,7 @@ <item> <widget class="QCheckBox" name="minimizeOnClose"> <property name="toolTip"> - <string>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Quit in the menu.</string> + <string>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</string> </property> <property name="text"> <string>M&inimize on close</string> diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 17552bc388..35760f9af0 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -288,8 +288,7 @@ Value prioritisetransaction(const Array& params, bool fHelp) + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000") ); - uint256 hash; - hash.SetHex(params[0].get_str()); + uint256 hash = ParseHashStr(params[0].get_str(), "txid"); CAmount nAmount = params[2].get_int64(); diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index b8805b9d51..7c08a5c246 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -162,6 +162,7 @@ Value validateaddress(const Array& params, bool fHelp) "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n" + " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"isscript\" : true|false, (boolean) If the key is a script\n" " \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n" @@ -183,6 +184,10 @@ Value validateaddress(const Array& params, bool fHelp) CTxDestination dest = address.Get(); string currentAddress = address.ToString(); ret.push_back(Pair("address", currentAddress)); + + CScript scriptPubKey = GetScriptForDestination(dest); + ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); + #ifdef ENABLE_WALLET isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c5d74afba9..210c7fe973 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -650,14 +650,16 @@ void StartRPCThreads() bool fListening = false; std::string strerr; + std::string straddress; BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints) { - asio::ip::address bindAddress = endpoint.address(); - LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", bindAddress.to_string(), endpoint.port(), bBindAny); - boost::system::error_code v6_only_error; - boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service)); - try { + asio::ip::address bindAddress = endpoint.address(); + straddress = bindAddress.to_string(); + LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", straddress, endpoint.port(), bBindAny); + boost::system::error_code v6_only_error; + boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service)); + acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); @@ -678,8 +680,8 @@ void StartRPCThreads() } catch (const boost::system::system_error& e) { - LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", bindAddress.to_string(), endpoint.port(), e.what()); - strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), bindAddress.to_string(), endpoint.port(), e.what()); + LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", straddress, endpoint.port(), e.what()); + strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), straddress, endpoint.port(), e.what()); } } diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp index 63da8a20b5..56be6dba13 100644 --- a/src/rpcwallet.cpp +++ b/src/rpcwallet.cpp @@ -1103,7 +1103,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp) "\nResult:\n" "[\n" " {\n" - " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" + " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"address\" : \"receivingaddress\", (string) The receiving address\n" " \"account\" : \"accountname\", (string) The account of the receiving address. The default account is \"\".\n" " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n" @@ -1135,7 +1135,7 @@ Value listreceivedbyaccount(const Array& params, bool fHelp) "\nResult:\n" "[\n" " {\n" - " \"involvesWatchonly\" : \"true\", (bool) Only returned if imported addresses were involved in transaction\n" + " \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n" " \"account\" : \"accountname\", (string) The account name of the receiving account\n" " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n" " \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n" diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index f8424b72a3..6090421cb6 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -46,5 +46,15 @@ { "exec": "./bitcoin-tx", "args": ["-create", "outscript=0:"], "output_cmp": "txcreate2.hex" + }, + { "exec": "./bitcoin-tx", + "args": + ["-create", + "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", + "set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]", + "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]", + "sign=ALL", + "outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"], + "output_cmp": "txcreatesign.hex" } ] diff --git a/src/test/data/txcreatesign.hex b/src/test/data/txcreatesign.hex new file mode 100644 index 0000000000..56ce28a865 --- /dev/null +++ b/src/test/data/txcreatesign.hex @@ -0,0 +1 @@ +01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000 diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index a83bd120ca..57c49c2dfc 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -93,6 +93,13 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) /* 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X (33 chars) is an illegal address (should be 34 chars) */ BOOST_CHECK_THROW(CallRPC("setaccount 1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4X nullaccount"), runtime_error); + + /********************************* + * getbalance + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("getbalance")); + BOOST_CHECK_NO_THROW(CallRPC("getbalance " + demoAddress.ToString())); + /********************************* * listunspent *********************************/ @@ -125,6 +132,35 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK_THROW(CallRPC("listreceivedbyaccount 0 true extra"), runtime_error); /********************************* + * listsinceblock + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listsinceblock")); + + /********************************* + * listtransactions + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listtransactions")); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString())); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20")); + BOOST_CHECK_NO_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " 20 0")); + BOOST_CHECK_THROW(CallRPC("listtransactions " + demoAddress.ToString() + " not_int"), runtime_error); + + /********************************* + * listlockunspent + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listlockunspent")); + + /********************************* + * listaccounts + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listaccounts")); + + /********************************* + * listaddressgroupings + *********************************/ + BOOST_CHECK_NO_THROW(CallRPC("listaddressgroupings")); + + /********************************* * getrawchangeaddress *********************************/ BOOST_CHECK_NO_THROW(CallRPC("getrawchangeaddress")); @@ -179,5 +215,4 @@ BOOST_AUTO_TEST_CASE(rpc_wallet) BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get()); } - BOOST_AUTO_TEST_SUITE_END() diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 3071ab025c..01bf1ec080 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -585,9 +585,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const if (fDependsWait) waitingOnDependants.push_back(&it->second); else { - CValidationState state; CTxUndo undo; + CValidationState state; assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL)); - UpdateCoins(tx, state, mempoolDuplicate, undo, 1000000); + UpdateCoins(tx, state, mempoolDuplicate, 1000000); } } unsigned int stepsSinceLastRemove = 0; @@ -601,8 +601,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const assert(stepsSinceLastRemove < waitingOnDependants.size()); } else { assert(CheckInputs(entry->GetTx(), state, mempoolDuplicate, false, 0, false, NULL)); - CTxUndo undo; - UpdateCoins(entry->GetTx(), state, mempoolDuplicate, undo, 1000000); + UpdateCoins(entry->GetTx(), state, mempoolDuplicate, 1000000); stepsSinceLastRemove = 0; } } diff --git a/src/undo.h b/src/undo.h index e6d8fd5862..1c4ed95bf2 100644 --- a/src/undo.h +++ b/src/undo.h @@ -68,4 +68,18 @@ public: } }; +/** Undo information for a CBlock */ +class CBlockUndo +{ +public: + std::vector<CTxUndo> vtxundo; // for all but the coinbase + + ADD_SERIALIZE_METHODS; + + template <typename Stream, typename Operation> + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(vtxundo); + } +}; + #endif // BITCOIN_UNDO_H |