diff options
-rw-r--r-- | src/Makefile.test.include | 8 | ||||
-rw-r--r-- | src/ecwrapper.cpp | 2 | ||||
-rw-r--r-- | src/ecwrapper.h | 4 | ||||
-rw-r--r-- | src/main.cpp | 23 | ||||
-rw-r--r-- | src/main.h | 29 | ||||
-rw-r--r-- | src/miner.cpp | 4 | ||||
-rw-r--r-- | src/qt/optionsdialog.h | 5 | ||||
-rw-r--r-- | src/rpcblockchain.cpp | 2 | ||||
-rw-r--r-- | src/rpcmining.cpp | 36 | ||||
-rw-r--r-- | src/rpcprotocol.h | 11 | ||||
-rw-r--r-- | src/rpcserver.h | 2 | ||||
-rw-r--r-- | src/test/miner_tests.cpp | 2 | ||||
-rw-r--r-- | src/txmempool.cpp | 6 | ||||
-rw-r--r-- | src/utilstrencodings.cpp | 4 |
14 files changed, 96 insertions, 42 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 340eb9f1a7..6a8d9e58a4 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -42,8 +42,8 @@ BITCOIN_TESTS =\ test/bloom_tests.cpp \ test/checkblock_tests.cpp \ test/Checkpoints_tests.cpp \ - test/compress_tests.cpp \ test/coins_tests.cpp \ + test/compress_tests.cpp \ test/crypto_tests.cpp \ test/DoS_tests.cpp \ test/getarg_tests.cpp \ @@ -58,7 +58,9 @@ BITCOIN_TESTS =\ test/rpc_tests.cpp \ test/script_P2SH_tests.cpp \ test/script_tests.cpp \ + test/scriptnum_tests.cpp \ test/serialize_tests.cpp \ + test/sighash_tests.cpp \ test/sigopcount_tests.cpp \ test/skiplist_tests.cpp \ test/test_bitcoin.cpp \ @@ -66,9 +68,7 @@ BITCOIN_TESTS =\ test/transaction_tests.cpp \ test/uint256_tests.cpp \ test/univalue_tests.cpp \ - test/util_tests.cpp \ - test/scriptnum_tests.cpp \ - test/sighash_tests.cpp + test/util_tests.cpp if ENABLE_WALLET BITCOIN_TESTS += \ diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp index e5db670927..ebaa350264 100644 --- a/src/ecwrapper.cpp +++ b/src/ecwrapper.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 "ecwrapper.h" diff --git a/src/ecwrapper.h b/src/ecwrapper.h index 072da4a942..e2d1e7edc4 100644 --- a/src/ecwrapper.h +++ b/src/ecwrapper.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 BITCOIN_EC_WRAPPER_H @@ -43,4 +43,4 @@ public: static bool SanityCheck(); }; -#endif +#endif // BITCOIN_EC_WRAPPER_H diff --git a/src/main.cpp b/src/main.cpp index 008a059103..37891f3b0d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -152,6 +152,8 @@ struct CMainSignals { boost::signals2::signal<void (const uint256 &)> Inventory; // Tells listeners to broadcast their data. boost::signals2::signal<void ()> Broadcast; + // Notifies listeners of a block validation result + boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; } g_signals; } // anon namespace @@ -163,9 +165,11 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); + g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); @@ -175,6 +179,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterAllValidationInterfaces() { + g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); g_signals.SetBestChain.disconnect_all_slots(); @@ -1864,7 +1869,9 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * { CCoinsViewCache view(pcoinsTip); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); - if (!ConnectBlock(*pblock, state, pindexNew, view)) { + bool rv = ConnectBlock(*pblock, state, pindexNew, view); + g_signals.BlockChecked(*pblock, state); + if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); @@ -2504,7 +2511,7 @@ void CBlockIndex::BuildSkip() pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); } -bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) { // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -2513,7 +2520,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl LOCK(cs_main); MarkBlockAsReceived(pblock->GetHash()); if (!checked) { - return error("ProcessBlock() : CheckBlock FAILED"); + return error("%s : CheckBlock FAILED", __func__); } // Store to disk @@ -2523,11 +2530,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } if (!ret) - return error("ProcessBlock() : AcceptBlock FAILED"); + return error("%s : AcceptBlock FAILED", __func__); } if (!ActivateBestChain(state, pblock)) - return error("ProcessBlock() : ActivateBestChain failed"); + return error("%s : ActivateBestChain failed", __func__); return true; } @@ -3136,7 +3143,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) // process in case the block isn't known yet if (mapBlockIndex.count(hash) == 0) { CValidationState state; - if (ProcessBlock(state, NULL, &block, dbp)) + if (ProcessNewBlock(state, NULL, &block, dbp)) nLoaded++; if (state.IsError()) break; @@ -3156,7 +3163,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessBlock(dummy, NULL, &block, &it->second)) + if (ProcessNewBlock(dummy, NULL, &block, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -3934,7 +3941,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(inv); CValidationState state; - ProcessBlock(state, pfrom, &block); + ProcessNewBlock(state, pfrom, &block); int nDoS; if (state.IsInvalid(nDoS)) { pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), diff --git a/src/main.h b/src/main.h index 1941ca7059..1bb0919817 100644 --- a/src/main.h +++ b/src/main.h @@ -39,8 +39,15 @@ #include <boost/unordered_map.hpp> class CBlockIndex; +class CBlockTreeDB; class CBloomFilter; class CInv; +class CScriptCheck; +class CValidationInterface; +class CValidationState; + +struct CBlockTemplate; +struct CNodeStateStats; /** The maximum allowed size for a serialized block, in bytes (network rule) */ static const unsigned int MAX_BLOCK_SIZE = 1000000; @@ -128,15 +135,6 @@ extern CBlockIndex *pindexBestHeader; // Minimum disk space required - used in CheckDiskSpace() static const uint64_t nMinDiskSpace = 52428800; - -class CBlockTreeDB; -class CScriptCheck; -class CValidationState; -class CValidationInterface; -struct CNodeStateStats; - -struct CBlockTemplate; - /** Register a wallet to receive updates from core */ void RegisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister a wallet from core */ @@ -151,8 +149,16 @@ void RegisterNodeSignals(CNodeSignals& nodeSignals); /** Unregister a network node */ void UnregisterNodeSignals(CNodeSignals& nodeSignals); -/** Process an incoming block */ -bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); +/** Process an incoming block. This only returns after the best known valid + block is made active. Note that it does not, however, guarantee that the + specific block passed to it has been checked for validity! + @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state iff pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface - this will have its BlockChecked method called whenever *any* block completes validation. + @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid. + @param[in] pblock The block we want to process. + @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location. + @return True if state.IsValid() +*/ +bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ @@ -651,6 +657,7 @@ protected: virtual void UpdatedTransaction(const uint256 &hash) {}; virtual void Inventory(const uint256 &hash) {}; virtual void ResendWalletTransactions() {}; + virtual void BlockChecked(const CBlock&, const CValidationState&) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); diff --git a/src/miner.cpp b/src/miner.cpp index 0235de3ab3..b5bfa9c7be 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -428,8 +428,8 @@ bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) // Process this block the same as if we had received it from another node CValidationState state; - if (!ProcessBlock(state, NULL, pblock)) - return error("BitcoinMiner : ProcessBlock, block not accepted"); + if (!ProcessNewBlock(state, NULL, pblock)) + return error("BitcoinMiner : ProcessNewBlock, block not accepted"); return true; } diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h index 39c53f4391..2abd92cae5 100644 --- a/src/qt/optionsdialog.h +++ b/src/qt/optionsdialog.h @@ -7,10 +7,13 @@ #include <QDialog> -class QDataWidgetMapper; class OptionsModel; class QValidatedLineEdit; +QT_BEGIN_NAMESPACE +class QDataWidgetMapper; +QT_END_NAMESPACE + namespace Ui { class OptionsDialog; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 78f5569895..a7cd63bd95 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -474,7 +474,7 @@ struct CompareBlocksByHeight bool operator()(const CBlockIndex* a, const CBlockIndex* b) const { /* Make sure that unequal blocks with the same height do not compare - equal. Use the pointers themselves to make a distinction. */ + equal. Use the pointers themselves to make a distinction. */ if (a->nHeight != b->nHeight) return (a->nHeight > b->nHeight); diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index 8af3c46348..0be4e06164 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -527,6 +527,24 @@ Value getblocktemplate(const Array& params, bool fHelp) return result; } +class submitblock_StateCatcher : public CValidationInterface +{ +public: + uint256 hash; + bool found; + CValidationState state; + + submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}; + +protected: + virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) { + if (block.GetHash() != hash) + return; + found = true; + state = stateIn; + }; +}; + Value submitblock(const Array& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) @@ -559,8 +577,22 @@ Value submitblock(const Array& params, bool fHelp) } CValidationState state; - bool fAccepted = ProcessBlock(state, NULL, &pblock); - if (!fAccepted) + submitblock_StateCatcher sc(pblock.GetHash()); + RegisterValidationInterface(&sc); + bool fAccepted = ProcessNewBlock(state, NULL, &pblock); + UnregisterValidationInterface(&sc); + if (fAccepted) + { + if (!sc.found) + return "inconclusive"; + state = sc.state; + } + if (state.IsError()) + { + std::string strRejectReason = state.GetRejectReason(); + throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason); + } + if (state.IsInvalid()) return "rejected"; // TODO: report validation state return Value::null; diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h index a9adb58803..9117248506 100644 --- a/src/rpcprotocol.h +++ b/src/rpcprotocol.h @@ -49,9 +49,14 @@ enum RPCErrorCode RPC_INVALID_PARAMETER = -8, // Invalid, missing or duplicate parameter RPC_DATABASE_ERROR = -20, // Database error RPC_DESERIALIZATION_ERROR = -22, // Error parsing or validating structure in raw format - RPC_TRANSACTION_ERROR = -25, // General error during transaction submission - RPC_TRANSACTION_REJECTED = -26, // Transaction was rejected by network rules - RPC_TRANSACTION_ALREADY_IN_CHAIN= -27, // Transaction already in chain + RPC_VERIFY_ERROR = -25, // General error during transaction or block submission + RPC_VERIFY_REJECTED = -26, // Transaction or block was rejected by network rules + RPC_VERIFY_ALREADY_IN_CHAIN = -27, // Transaction already in chain + + // Aliases for backward compatibility + RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR, + RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED, + RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN, // P2P client errors RPC_CLIENT_NOT_CONNECTED = -9, // Bitcoin is not connected diff --git a/src/rpcserver.h b/src/rpcserver.h index cc444cef1f..dc46637399 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -7,8 +7,8 @@ #define _BITCOINRPC_SERVER_H_ #include "amount.h" -#include "uint256.h" #include "rpcprotocol.h" +#include "uint256.h" #include <list> #include <map> diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 93b7fe189a..032ae983ce 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) pblock->hashMerkleRoot = pblock->BuildMerkleTree(); pblock->nNonce = blockinfo[i].nonce; CValidationState state; - BOOST_CHECK(ProcessBlock(state, NULL, pblock)); + BOOST_CHECK(ProcessNewBlock(state, NULL, pblock)); BOOST_CHECK(state.IsValid()); pblock->hashPrevBlock = pblock->GetHash(); } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index d3d9cb8a01..b5070d5104 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -332,7 +332,7 @@ public: size_t numEntries; filein >> numEntries; if (numEntries <= 0 || numEntries > 10000) - throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entires."); + throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entires."); std::vector<CBlockAverage> fileHistory; @@ -343,8 +343,8 @@ public: fileHistory.push_back(entry); } - //Now that we've processed the entire fee estimate data file and not - //thrown any errors, we can copy it to our history + // Now that we've processed the entire fee estimate data file and not + // thrown any errors, we can copy it to our history nBestSeenHeight = nFileBestSeenHeight; history = fileHistory; assert(history.size() > 0); diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index 81e156f43f..15094e5999 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -7,10 +7,10 @@ #include "tinyformat.h" -#include <errno.h> -#include <limits> #include <cstdlib> #include <cstring> +#include <errno.h> +#include <limits> using namespace std; |