diff options
44 files changed, 583 insertions, 348 deletions
diff --git a/.travis.yml b/.travis.yml index 9c18729b42..44ea7b62d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,18 +27,18 @@ matrix: include: - compiler: ": ARM" env: HOST=arm-linux-gnueabihf PACKAGES="g++-arm-linux-gnueabihf" DEP_OPTS="NO_QT=1" GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" + - compiler: ": Win32" + env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" + - compiler: ": 32-bit + dash" + env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" + - compiler: ": Win64" + env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" - compiler: ": bitcoind" env: HOST=x86_64-unknown-linux-gnu PACKAGES="bc" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports CPPFLAGS=-DDEBUG_LOCKORDER" - compiler: ": No wallet" env: HOST=x86_64-unknown-linux-gnu DEP_OPTS="NO_WALLET=1" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports" - - compiler: ": 32-bit + dash" - env: HOST=i686-pc-linux-gnu PACKAGES="g++-multilib bc" RUN_TESTS=true GOAL="install" BITCOIN_CONFIG="--enable-glibc-back-compat --enable-reduce-exports LDFLAGS=-static-libstdc++" USE_SHELL="/bin/dash" - compiler: ": Cross-Mac" env: HOST=x86_64-apple-darwin11 PACKAGES="cmake libcap-dev libz-dev libbz2-dev" BITCOIN_CONFIG="--enable-reduce-exports" OSX_SDK=10.9 GOAL="deploy" - - compiler: ": Win64" - env: HOST=x86_64-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 binutils-mingw-w64-x86-64 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" - - compiler: ": Win32" - env: HOST=i686-w64-mingw32 PACKAGES="nsis gcc-mingw-w64-i686 g++-mingw-w64-i686 binutils-mingw-w64-i686 mingw-w64-dev wine bc" RUN_TESTS=true GOAL="deploy" BITCOIN_CONFIG="--enable-gui --enable-reduce-exports" MAKEJOBS="-j2" install: - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi - if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi diff --git a/qa/rpc-tests/invalidateblock.py b/qa/rpc-tests/invalidateblock.py index a8bfbe6e6c..ccfcf00e30 100755 --- a/qa/rpc-tests/invalidateblock.py +++ b/qa/rpc-tests/invalidateblock.py @@ -16,15 +16,17 @@ class InvalidateTest(BitcoinTestFramework): def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) - initialize_chain_clean(self.options.tmpdir, 2) + initialize_chain_clean(self.options.tmpdir, 3) def setup_network(self): self.nodes = [] self.is_network_split = False self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"])) self.nodes.append(start_node(1, self.options.tmpdir, ["-debug"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-debug"])) def run_test(self): + print "Make sure we repopulate setBlockIndexCandidates after InvalidateBlock:" print "Mine 4 blocks on Node 0" self.nodes[0].setgenerate(True, 4) assert(self.nodes[0].getblockcount() == 4) @@ -36,7 +38,7 @@ class InvalidateTest(BitcoinTestFramework): print "Connect nodes to force a reorg" connect_nodes_bi(self.nodes,0,1) - sync_blocks(self.nodes) + sync_blocks(self.nodes[0:2]) assert(self.nodes[0].getblockcount() == 6) badhash = self.nodes[1].getblockhash(2) @@ -47,5 +49,28 @@ class InvalidateTest(BitcoinTestFramework): if (newheight != 4 or newhash != besthash): raise AssertionError("Wrong tip for node0, hash %s, height %d"%(newhash,newheight)) + print "\nMake sure we won't reorg to a lower work chain:" + connect_nodes_bi(self.nodes,1,2) + print "Sync node 2 to node 1 so both have 6 blocks" + sync_blocks(self.nodes[1:3]) + assert(self.nodes[2].getblockcount() == 6) + print "Invalidate block 5 on node 1 so its tip is now at 4" + self.nodes[1].invalidateblock(self.nodes[1].getblockhash(5)) + assert(self.nodes[1].getblockcount() == 4) + print "Invalidate block 3 on node 2, so its tip is now 2" + self.nodes[2].invalidateblock(self.nodes[2].getblockhash(3)) + assert(self.nodes[2].getblockcount() == 2) + print "..and then mine a block" + self.nodes[2].setgenerate(True, 1) + print "Verify all nodes are at the right height" + time.sleep(5) + for i in xrange(3): + print i,self.nodes[i].getblockcount() + assert(self.nodes[2].getblockcount() == 3) + assert(self.nodes[0].getblockcount() == 4) + node1height = self.nodes[1].getblockcount() + if node1height < 4: + raise AssertionError("Node 1 reorged to a lower height: %d"%node1height) + if __name__ == '__main__': InvalidateTest().main() diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index dc4e0f77bd..01e9fa57b2 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -16,6 +16,7 @@ # h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1 # i) have node1 mine a block # j) check balances - node0 should have 0, node2 should have 100 +# k) test ResendWalletTransactions - create transactions, startup fourth node, make sure it syncs # from test_framework import BitcoinTestFramework @@ -26,7 +27,7 @@ class WalletTest (BitcoinTestFramework): def setup_chain(self): print("Initializing test directory "+self.options.tmpdir) - initialize_chain_clean(self.options.tmpdir, 3) + initialize_chain_clean(self.options.tmpdir, 4) def setup_network(self, split=False): self.nodes = start_nodes(3, self.options.tmpdir) @@ -132,5 +133,23 @@ class WalletTest (BitcoinTestFramework): assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')) assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000')) + # Test ResendWalletTransactions: + # Create a couple of transactions, then start up a fourth + # node (nodes[3]) and ask nodes[0] to rebroadcast. + # EXPECT: nodes[3] should have those transactions in its mempool. + txid1 = self.nodes[0].sendtoaddress(self.nodes[1].getnewaddress(), 1) + txid2 = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1) + sync_mempools(self.nodes) + + self.nodes.append(start_node(3, self.options.tmpdir)) + connect_nodes_bi(self.nodes, 0, 3) + sync_blocks(self.nodes) + + relayed = self.nodes[0].resendwallettransactions() + assert_equal(set(relayed), set([txid1, txid2])) + sync_mempools(self.nodes) + + assert(txid1 in self.nodes[3].getrawmempool()) + if __name__ == '__main__': WalletTest ().main () diff --git a/src/Makefile.am b/src/Makefile.am index d1a8efaa6a..37184b6286 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -87,8 +87,8 @@ BITCOIN_CORE_H = \ coins.h \ compat.h \ compressor.h \ + consensus/params.h \ core_io.h \ - crypter.h \ wallet/db.h \ eccryptoverify.h \ ecwrapper.h \ @@ -139,7 +139,9 @@ BITCOIN_CORE_H = \ utilmoneystr.h \ utilstrencodings.h \ utiltime.h \ + validationinterface.h \ version.h \ + wallet/crypter.h \ wallet/walletdb.h \ wallet/wallet.h \ wallet/wallet_ismine.h \ @@ -191,6 +193,7 @@ libbitcoin_server_a_SOURCES = \ timedata.cpp \ txdb.cpp \ txmempool.cpp \ + validationinterface.cpp \ $(JSON_H) \ $(BITCOIN_CORE_H) @@ -198,8 +201,8 @@ libbitcoin_server_a_SOURCES = \ # when wallet enabled libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_wallet_a_SOURCES = \ + wallet/crypter.cpp \ wallet/db.cpp \ - crypter.cpp \ wallet/rpcdump.cpp \ wallet/rpcwallet.cpp \ wallet/wallet.cpp \ diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 2bc8976510..3e20d9f8f2 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -101,6 +101,14 @@ class CMainParams : public CChainParams { public: CMainParams() { strNetworkID = "main"; + consensus.nSubsidyHalvingInterval = 210000; + consensus.nMajorityEnforceBlockUpgrade = 750; + consensus.nMajorityRejectBlockOutdated = 950; + consensus.nMajorityWindow = 1000; + consensus.powLimit = ~arith_uint256(0) >> 32; + consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks + consensus.nPowTargetSpacing = 10 * 60; + consensus.fPowAllowMinDifficultyBlocks = false; /** * The message start string is designed to be unlikely to occur in normal data. * The characters are rarely used upper ASCII, not valid as UTF-8, and produce @@ -112,14 +120,7 @@ public: pchMessageStart[3] = 0xd9; vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); nDefaultPort = 8333; - bnProofOfWorkLimit = ~arith_uint256(0) >> 32; - nSubsidyHalvingInterval = 210000; - nEnforceBlockUpgradeMajority = 750; - nRejectBlockOutdatedMajority = 950; - nToCheckBlockUpgradeMajority = 1000; nMinerThreads = 0; - nTargetTimespan = 14 * 24 * 60 * 60; // two weeks - nTargetSpacing = 10 * 60; /** * Build the genesis block. Note that the output of the genesis coinbase cannot @@ -146,8 +147,8 @@ public: genesis.nBits = 0x1d00ffff; genesis.nNonce = 2083236893; - hashGenesisBlock = genesis.GetHash(); - assert(hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")); assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")); vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be")); @@ -167,7 +168,6 @@ public: fRequireRPCPassword = true; fMiningRequiresPeers = true; fDefaultCheckMemPool = false; - fAllowMinDifficultyBlocks = false; fRequireStandard = true; fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = false; @@ -187,24 +187,23 @@ class CTestNetParams : public CMainParams { public: CTestNetParams() { strNetworkID = "test"; + consensus.nMajorityEnforceBlockUpgrade = 51; + consensus.nMajorityRejectBlockOutdated = 75; + consensus.nMajorityWindow = 100; + consensus.fPowAllowMinDifficultyBlocks = true; pchMessageStart[0] = 0x0b; pchMessageStart[1] = 0x11; pchMessageStart[2] = 0x09; pchMessageStart[3] = 0x07; vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); nDefaultPort = 18333; - nEnforceBlockUpgradeMajority = 51; - nRejectBlockOutdatedMajority = 75; - nToCheckBlockUpgradeMajority = 100; nMinerThreads = 0; - nTargetTimespan = 14 * 24 * 60 * 60; //! two weeks - nTargetSpacing = 10 * 60; //! Modify the testnet genesis block so the timestamp is valid for a later start. genesis.nTime = 1296688602; genesis.nNonce = 414098458; - hashGenesisBlock = genesis.GetHash(); - assert(hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); + consensus.hashGenesisBlock = genesis.GetHash(); + assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); vFixedSeeds.clear(); vSeeds.clear(); @@ -224,7 +223,6 @@ public: fRequireRPCPassword = true; fMiningRequiresPeers = true; fDefaultCheckMemPool = false; - fAllowMinDifficultyBlocks = true; fRequireStandard = false; fMineBlocksOnDemand = false; fTestnetToBeDeprecatedFieldRPC = true; @@ -243,24 +241,22 @@ class CRegTestParams : public CTestNetParams { public: CRegTestParams() { strNetworkID = "regtest"; + consensus.nSubsidyHalvingInterval = 150; + consensus.nMajorityEnforceBlockUpgrade = 750; + consensus.nMajorityRejectBlockOutdated = 950; + consensus.nMajorityWindow = 1000; + consensus.powLimit = ~arith_uint256(0) >> 1; pchMessageStart[0] = 0xfa; pchMessageStart[1] = 0xbf; pchMessageStart[2] = 0xb5; pchMessageStart[3] = 0xda; - nSubsidyHalvingInterval = 150; - nEnforceBlockUpgradeMajority = 750; - nRejectBlockOutdatedMajority = 950; - nToCheckBlockUpgradeMajority = 1000; nMinerThreads = 1; - nTargetTimespan = 14 * 24 * 60 * 60; //! two weeks - nTargetSpacing = 10 * 60; - bnProofOfWorkLimit = ~arith_uint256(0) >> 1; genesis.nTime = 1296688602; genesis.nBits = 0x207fffff; genesis.nNonce = 2; - hashGenesisBlock = genesis.GetHash(); + consensus.hashGenesisBlock = genesis.GetHash(); nDefaultPort = 18444; - assert(hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); + assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")); vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds. vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds. @@ -268,7 +264,6 @@ public: fRequireRPCPassword = false; fMiningRequiresPeers = false; fDefaultCheckMemPool = true; - fAllowMinDifficultyBlocks = true; fRequireStandard = false; fMineBlocksOnDemand = true; fTestnetToBeDeprecatedFieldRPC = false; diff --git a/src/chainparams.h b/src/chainparams.h index 134dcd6558..aa2ec1e301 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -6,11 +6,12 @@ #ifndef BITCOIN_CHAINPARAMS_H #define BITCOIN_CHAINPARAMS_H +#include "arith_uint256.h" #include "chainparamsbase.h" #include "checkpoints.h" +#include "consensus/params.h" #include "primitives/block.h" #include "protocol.h" -#include "arith_uint256.h" #include <vector> @@ -39,16 +40,16 @@ public: MAX_BASE58_TYPES }; - const uint256& HashGenesisBlock() const { return hashGenesisBlock; } + const Consensus::Params& GetConsensus() const { return consensus; } + const uint256& HashGenesisBlock() const { return consensus.hashGenesisBlock; } const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; } const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; } int GetDefaultPort() const { return nDefaultPort; } - const arith_uint256& ProofOfWorkLimit() const { return bnProofOfWorkLimit; } - int SubsidyHalvingInterval() const { return nSubsidyHalvingInterval; } - /** Used to check majorities for block version upgrade */ - int EnforceBlockUpgradeMajority() const { return nEnforceBlockUpgradeMajority; } - int RejectBlockOutdatedMajority() const { return nRejectBlockOutdatedMajority; } - int ToCheckBlockUpgradeMajority() const { return nToCheckBlockUpgradeMajority; } + const arith_uint256& ProofOfWorkLimit() const { return consensus.powLimit; } + int SubsidyHalvingInterval() const { return consensus.nSubsidyHalvingInterval; } + int EnforceBlockUpgradeMajority() const { return consensus.nMajorityEnforceBlockUpgrade; } + int RejectBlockOutdatedMajority() const { return consensus.nMajorityRejectBlockOutdated; } + int ToCheckBlockUpgradeMajority() const { return consensus.nMajorityWindow; } /** Used if GenerateBitcoins is called with a negative number of threads */ int DefaultMinerThreads() const { return nMinerThreads; } @@ -59,12 +60,12 @@ public: /** Default value for -checkmempool argument */ bool DefaultCheckMemPool() const { return fDefaultCheckMemPool; } /** Allow mining of a min-difficulty block */ - bool AllowMinDifficultyBlocks() const { return fAllowMinDifficultyBlocks; } + bool AllowMinDifficultyBlocks() const { return consensus.fPowAllowMinDifficultyBlocks; } /** Make standard checks */ bool RequireStandard() const { return fRequireStandard; } - int64_t TargetTimespan() const { return nTargetTimespan; } - int64_t TargetSpacing() const { return nTargetSpacing; } - int64_t DifficultyAdjustmentInterval() const { return nTargetTimespan / nTargetSpacing; } + int64_t TargetTimespan() const { return consensus.nPowTargetTimespan; } + int64_t TargetSpacing() const { return consensus.nPowTargetSpacing; } + int64_t DifficultyAdjustmentInterval() const { return consensus.nPowTargetTimespan / consensus.nPowTargetSpacing; } /** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */ bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; } /** In the future use NetworkIDString() for RPC fields */ @@ -78,18 +79,11 @@ public: protected: CChainParams() {} - uint256 hashGenesisBlock; + Consensus::Params consensus; CMessageHeader::MessageStartChars pchMessageStart; //! Raw pub key bytes for the broadcast alert signing key. std::vector<unsigned char> vAlertPubKey; int nDefaultPort; - arith_uint256 bnProofOfWorkLimit; - int nSubsidyHalvingInterval; - int nEnforceBlockUpgradeMajority; - int nRejectBlockOutdatedMajority; - int nToCheckBlockUpgradeMajority; - int64_t nTargetTimespan; - int64_t nTargetSpacing; int nMinerThreads; std::vector<CDNSSeedData> vSeeds; std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES]; @@ -99,7 +93,6 @@ protected: bool fRequireRPCPassword; bool fMiningRequiresPeers; bool fDefaultCheckMemPool; - bool fAllowMinDifficultyBlocks; bool fRequireStandard; bool fMineBlocksOnDemand; bool fTestnetToBeDeprecatedFieldRPC; diff --git a/src/consensus/params.h b/src/consensus/params.h new file mode 100644 index 0000000000..c4cfa48c7e --- /dev/null +++ b/src/consensus/params.h @@ -0,0 +1,32 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-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. + +#ifndef BITCOIN_CONSENSUS_CONSENSUS_PARAMS_H +#define BITCOIN_CONSENSUS_CONSENSUS_PARAMS_H + +#include "arith_uint256.h" +#include "uint256.h" + +namespace Consensus { +/** + * Parameters that influence chain consensus. + */ +struct Params { + uint256 hashGenesisBlock; + int nSubsidyHalvingInterval; + /** Used to check majorities for block version upgrade */ + int nMajorityEnforceBlockUpgrade; + int nMajorityRejectBlockOutdated; + int nMajorityWindow; + /** Proof of work parameters */ + arith_uint256 powLimit; + bool fPowAllowMinDifficultyBlocks; + int64_t nPowTargetSpacing; + int64_t nPowTargetTimespan; + int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; } +}; +} // namespace Consensus + +#endif // BITCOIN_CONSENSUS_CONSENSUS_PARAMS_H diff --git a/src/init.cpp b/src/init.cpp index 95ec45015f..2a13af6690 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -23,6 +23,7 @@ #include "ui_interface.h" #include "util.h" #include "utilmoneystr.h" +#include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" diff --git a/src/keystore.cpp b/src/keystore.cpp index 7531737e04..3bae24b7b9 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -5,7 +5,6 @@ #include "keystore.h" -#include "crypter.h" #include "key.h" #include "util.h" diff --git a/src/main.cpp b/src/main.cpp index 94cf213490..3ceacf32e7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,9 +5,9 @@ #include "main.h" -#include "arith_uint256.h" #include "addrman.h" #include "alert.h" +#include "arith_uint256.h" #include "chainparams.h" #include "checkpoints.h" #include "checkqueue.h" @@ -21,6 +21,7 @@ #include "undo.h" #include "util.h" #include "utilmoneystr.h" +#include "validationinterface.h" #include <sstream> @@ -158,68 +159,6 @@ namespace { ////////////////////////////////////////////////////////////////////////////// // -// dispatching functions -// - -// These functions dispatch to one or all registered wallets - -namespace { - -struct CMainSignals { - /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ - boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction; - /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */ - boost::signals2::signal<void (const uint256 &)> EraseTransaction; - /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ - boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; - /** Notifies listeners of a new active block chain. */ - boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; - /** Notifies listeners about an inventory item being seen on the network. */ - 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 - -void RegisterValidationInterface(CValidationInterface* pwalletIn) { - g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); - g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); - g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - 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)); - g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); - g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); -} - -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(); - g_signals.UpdatedTransaction.disconnect_all_slots(); - g_signals.EraseTransaction.disconnect_all_slots(); - g_signals.SyncTransaction.disconnect_all_slots(); -} - -void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { - g_signals.SyncTransaction(tx, pblock); -} - -////////////////////////////////////////////////////////////////////////////// -// // Registration of network node signals. // @@ -1219,7 +1158,7 @@ bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos) } // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits)) + if (!CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString()); return true; @@ -1897,7 +1836,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Watch for changes to the previous coinbase transaction. static uint256 hashPrevBestCoinBase; - g_signals.UpdatedTransaction(hashPrevBestCoinBase); + GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); hashPrevBestCoinBase = block.vtx[0].GetHash(); int64_t nTime4 = GetTimeMicros(); nTimeCallbacks += nTime4 - nTime3; @@ -1956,7 +1895,7 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) { return state.Abort("Failed to write to coin database"); // Update best block in wallet (so we can detect restored wallets). if (mode != FLUSH_STATE_IF_NEEDED) { - g_signals.SetBestChain(chainActive.GetLocator()); + GetMainSignals().SetBestChain(chainActive.GetLocator()); } nLastWrite = GetTimeMicros(); } @@ -2080,7 +2019,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * CCoinsViewCache view(pcoinsTip); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); bool rv = ConnectBlock(*pblock, state, pindexNew, view); - g_signals.BlockChecked(*pblock, state); + GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); @@ -2320,7 +2259,7 @@ bool InvalidateBlock(CValidationState& state, CBlockIndex *pindex) { // add them again. BlockMap::iterator it = mapBlockIndex.begin(); while (it != mapBlockIndex.end()) { - if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && setBlockIndexCandidates.value_comp()(chainActive.Tip(), it->second)) { + if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->nChainTx && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) { setBlockIndexCandidates.insert(it->second); } it++; @@ -2523,7 +2462,7 @@ bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigne bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits)) + if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, Params().GetConsensus())) return state.DoS(50, error("CheckBlockHeader(): proof of work failed"), REJECT_INVALID, "high-hash"); @@ -2606,7 +2545,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta int nHeight = pindexPrev->nHeight+1; // Check proof of work - if ((block.nBits != GetNextWorkRequired(pindexPrev, &block))) + if (block.nBits != GetNextWorkRequired(pindexPrev, &block, Params().GetConsensus())) return state.DoS(100, error("%s: incorrect proof of work", __func__), REJECT_INVALID, "bad-diffbits"); @@ -3471,7 +3410,7 @@ void static ProcessGetData(CNode* pfrom) } // Track requests for our stuff. - g_signals.Inventory(inv.hash); + GetMainSignals().Inventory(inv.hash); if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) break; @@ -3765,7 +3704,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, } // Track requests for our stuff - g_signals.Inventory(inv.hash); + GetMainSignals().Inventory(inv.hash); if (pfrom->nSendSize > (SendBufferSize() * 2)) { Misbehaving(pfrom->GetId(), 50); @@ -4536,7 +4475,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // transactions become unconfirmed and spams other nodes. if (!fReindex && !fImporting && !IsInitialBlockDownload()) { - g_signals.Broadcast(); + GetMainSignals().Broadcast(nTimeBestReceived); } // diff --git a/src/main.h b/src/main.h index 936cd43e99..3ef042895d 100644 --- a/src/main.h +++ b/src/main.h @@ -17,7 +17,6 @@ #include "primitives/block.h" #include "primitives/transaction.h" #include "net.h" -#include "pow.h" #include "script/script.h" #include "script/sigcache.h" #include "script/standard.h" @@ -116,7 +115,6 @@ extern BlockMap mapBlockIndex; extern uint64_t nLastBlockTx; extern uint64_t nLastBlockSize; extern const std::string strMessageMagic; -extern int64_t nTimeBestReceived; extern CWaitableCriticalSection csBestBlock; extern CConditionVariable cvBlockChange; extern bool fImporting; @@ -133,15 +131,6 @@ extern CBlockIndex *pindexBestHeader; /** Minimum disk space required - used in CheckDiskSpace() */ static const uint64_t nMinDiskSpace = 52428800; -/** Register a wallet to receive updates from core */ -void RegisterValidationInterface(CValidationInterface* pwalletIn); -/** Unregister a wallet from core */ -void UnregisterValidationInterface(CValidationInterface* pwalletIn); -/** Unregister all wallets from core */ -void UnregisterAllValidationInterfaces(); -/** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); - /** Register with a network node to receive its signals */ void RegisterNodeSignals(CNodeSignals& nodeSignals); /** Unregister a network node */ @@ -152,7 +141,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals); * 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 if 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[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 if 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 (see validationinterface.h) - 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. @@ -177,7 +166,12 @@ bool LoadBlockIndex(); void UnloadBlockIndex(); /** Process protocol messages received from a given node */ bool ProcessMessages(CNode* pfrom); -/** Send queued protocol messages to be sent to a give node */ +/** + * Send queued protocol messages to be sent to a give node. + * + * @param[in] pto The node which we are sending messages to. + * @param[in] fSendTrickle When true send the trickled data, otherwise trickle the data until true. + */ bool SendMessages(CNode* pto, bool fSendTrickle); /** Run an instance of the script checking thread */ void ThreadScriptCheck(); @@ -512,19 +506,4 @@ extern CCoinsViewCache *pcoinsTip; /** Global variable that points to the active block tree (protected by cs_main) */ extern CBlockTreeDB *pblocktree; - -class CValidationInterface { -protected: - virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}; - virtual void EraseFromWallet(const uint256 &hash) {}; - virtual void SetBestChain(const CBlockLocator &locator) {}; - 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(); -}; - #endif // BITCOIN_MAIN_H diff --git a/src/miner.cpp b/src/miner.cpp index 01212b19c4..cf08b78229 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -84,7 +84,7 @@ void UpdateTime(CBlockHeader* pblock, const CBlockIndex* pindexPrev) // Updating time can change work required on testnet: if (Params().AllowMinDifficultyBlocks()) - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); } CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) @@ -326,7 +326,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); diff --git a/src/net.cpp b/src/net.cpp index 0723ee218a..11c2cd07d9 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1406,7 +1406,7 @@ void ThreadMessageHandler() { TRY_LOCK(pnode->cs_vSend, lockSend); if (lockSend) - g_signals.SendMessages(pnode, pnode == pnodeTrickle); + g_signals.SendMessages(pnode, pnode == pnodeTrickle || pnode->fWhitelisted); } boost::this_thread::interruption_point(); } diff --git a/src/pow.cpp b/src/pow.cpp index eb899ffc94..3c5a8d9d96 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -7,34 +7,33 @@ #include "arith_uint256.h" #include "chain.h" -#include "chainparams.h" #include "primitives/block.h" #include "uint256.h" #include "util.h" -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock) +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { - unsigned int nProofOfWorkLimit = Params().ProofOfWorkLimit().GetCompact(); + unsigned int nProofOfWorkLimit = params.powLimit.GetCompact(); // Genesis block if (pindexLast == NULL) return nProofOfWorkLimit; // Only change once per difficulty adjustment interval - if ((pindexLast->nHeight+1) % Params().DifficultyAdjustmentInterval() != 0) + if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0) { - if (Params().AllowMinDifficultyBlocks()) + if (params.fPowAllowMinDifficultyBlocks) { // Special difficulty rule for testnet: // If the new block's timestamp is more than 2* 10 minutes // then allow mining of a min-difficulty block. - if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + Params().TargetSpacing()*2) + if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2) return nProofOfWorkLimit; else { // Return the last non-special-min-difficulty-rules-block const CBlockIndex* pindex = pindexLast; - while (pindex->pprev && pindex->nHeight % Params().DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) + while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit) pindex = pindex->pprev; return pindex->nBits; } @@ -44,22 +43,22 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead // Go back by what we want to be 14 days worth of blocks const CBlockIndex* pindexFirst = pindexLast; - for (int i = 0; pindexFirst && i < Params().DifficultyAdjustmentInterval()-1; i++) + for (int i = 0; pindexFirst && i < params.DifficultyAdjustmentInterval()-1; i++) pindexFirst = pindexFirst->pprev; assert(pindexFirst); - return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime()); + return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params); } -unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime) +unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params) { // Limit adjustment step int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); - if (nActualTimespan < Params().TargetTimespan()/4) - nActualTimespan = Params().TargetTimespan()/4; - if (nActualTimespan > Params().TargetTimespan()*4) - nActualTimespan = Params().TargetTimespan()*4; + if (nActualTimespan < params.nPowTargetTimespan/4) + nActualTimespan = params.nPowTargetTimespan/4; + if (nActualTimespan > params.nPowTargetTimespan*4) + nActualTimespan = params.nPowTargetTimespan*4; // Retarget arith_uint256 bnNew; @@ -67,21 +66,21 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF bnNew.SetCompact(pindexLast->nBits); bnOld = bnNew; bnNew *= nActualTimespan; - bnNew /= Params().TargetTimespan(); + bnNew /= params.nPowTargetTimespan; - if (bnNew > Params().ProofOfWorkLimit()) - bnNew = Params().ProofOfWorkLimit(); + if (bnNew > params.powLimit) + bnNew = params.powLimit; /// debug print LogPrintf("GetNextWorkRequired RETARGET\n"); - LogPrintf("Params().TargetTimespan() = %d nActualTimespan = %d\n", Params().TargetTimespan(), nActualTimespan); + LogPrintf("params.nPowTargetTimespan = %d nActualTimespan = %d\n", params.nPowTargetTimespan, nActualTimespan); LogPrintf("Before: %08x %s\n", pindexLast->nBits, bnOld.ToString()); LogPrintf("After: %08x %s\n", bnNew.GetCompact(), bnNew.ToString()); return bnNew.GetCompact(); } -bool CheckProofOfWork(uint256 hash, unsigned int nBits) +bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params& params) { bool fNegative; bool fOverflow; @@ -90,7 +89,7 @@ bool CheckProofOfWork(uint256 hash, unsigned int nBits) bnTarget.SetCompact(nBits, &fNegative, &fOverflow); // Check range - if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) + if (fNegative || bnTarget == 0 || fOverflow || bnTarget > params.powLimit) return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount @@ -6,6 +6,8 @@ #ifndef BITCOIN_POW_H #define BITCOIN_POW_H +#include "consensus/params.h" + #include <stdint.h> class CBlockHeader; @@ -13,11 +15,11 @@ class CBlockIndex; class uint256; class arith_uint256; -unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock); -unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime); +unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&); +unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&); /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */ -bool CheckProofOfWork(uint256 hash, unsigned int nBits); +bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&); arith_uint256 GetBlockProof(const CBlockIndex& block); #endif // BITCOIN_POW_H diff --git a/src/protocol.h b/src/protocol.h index e838c0d363..fd23eae1fc 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -67,7 +67,14 @@ public: /** nServices flags */ enum { + // NODE_NETWORK means that the node is capable of serving the block chain. It is currently + // set by all Bitcoin Core nodes, and is unset by SPV clients or other peers that just want + // network services but don't provide them. NODE_NETWORK = (1 << 0), + // NODE_GETUTXO means the node is capable of responding to the getutxo protocol request. + // Bitcoin Core does not support this but a patch set called Bitcoin XT does. + // See BIP 64 for details on how this is implemented. + NODE_GETUTXO = (1 << 1), // Bits 24-31 are reserved for temporary experiments. Just pick a bit that // isn't getting used, or one not being used much, and notify the diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 9573fe43df..8e20836c65 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -10,6 +10,8 @@ #include "base58.h" #include "wallet/wallet.h" +#include <boost/foreach.hpp> + #include <QFont> #include <QDebug> diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index 9db0a75971..a5ee81db6c 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -878,10 +878,13 @@ QString formatServicesStr(quint64 mask) switch (check) { case NODE_NETWORK: - strList.append(QObject::tr("NETWORK")); + strList.append("NETWORK"); + break; + case NODE_GETUTXO: + strList.append("GETUTXO"); break; default: - strList.append(QString("%1[%2]").arg(QObject::tr("UNKNOWN")).arg(check)); + strList.append(QString("%1[%2]").arg("UNKNOWN").arg(check)); } } } diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index 40d6e16f51..ad489de343 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -10,6 +10,7 @@ #include "base58.h" #include "chainparams.h" +#include "main.h" #include "ui_interface.h" #include "util.h" #include "wallet/wallet.h" diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp index ccde44fb29..29c971ec79 100644 --- a/src/qt/rpcconsole.cpp +++ b/src/qt/rpcconsole.cpp @@ -357,7 +357,6 @@ void RPCConsole::clear() ui->messagesWidget->document()->setDefaultStyleSheet( "table { }" "td.time { color: #808080; padding-top: 3px; } " - "td.message { font-family: monospace; font-size: 12px; } " // Todo: Remove fixed font-size "td.cmd-request { color: #006060; } " "td.cmd-error { color: red; } " "b { color: #006060; } " diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index 28c8fb95f6..774667d4ac 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -17,6 +17,7 @@ #include "base58.h" #include "coincontrol.h" +#include "main.h" #include "ui_interface.h" #include "wallet/wallet.h" diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp index 76da6904a9..ce166f3672 100644 --- a/src/qt/signverifymessagedialog.cpp +++ b/src/qt/signverifymessagedialog.cpp @@ -12,6 +12,7 @@ #include "base58.h" #include "init.h" +#include "main.h" // For strMessageMagic #include "wallet/wallet.h" #include <string> diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index 19e3fc0dc2..9db5ad0fd4 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -5,11 +5,14 @@ #include "transactionrecord.h" #include "base58.h" +#include "main.h" #include "timedata.h" #include "wallet/wallet.h" #include <stdint.h> +#include <boost/foreach.hpp> + /* Return positive answer if transaction should be shown in list. */ bool TransactionRecord::showTransaction(const CWalletTx &wtx) diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index a07acea9aa..fcba7e222d 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -13,6 +13,7 @@ #include "pow.h" #include "rpcserver.h" #include "util.h" +#include "validationinterface.h" #ifdef ENABLE_WALLET #include "wallet/db.h" #include "wallet/wallet.h" @@ -180,7 +181,7 @@ Value setgenerate(const Array& params, bool fHelp) LOCK(cs_main); IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce); } - while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) { + while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) { // Yes, there is a chance every nonce could fail to satisfy the -regtest // target -- 1 in 2^(2^32). That ain't gonna happen. ++pblock->nNonce; diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index ba71725222..d30fa32eb4 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -333,6 +333,9 @@ static const CRPCCommand vRPCCommands[] = { "hidden", "invalidateblock", &invalidateblock, true, false }, { "hidden", "reconsiderblock", &reconsiderblock, true, false }, { "hidden", "setmocktime", &setmocktime, true, false }, +#ifdef ENABLE_WALLET + { "hidden", "resendwallettransactions", &resendwallettransactions, true, true }, +#endif #ifdef ENABLE_WALLET /* Wallet */ diff --git a/src/rpcserver.h b/src/rpcserver.h index f63438ecb8..7011d41fc1 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -207,6 +207,7 @@ extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool f extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp); +extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp); extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp); diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 14119f7e2c..eab629cd91 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -17,22 +17,31 @@ using namespace std; typedef vector<unsigned char> valtype; -bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), checker(txTo, nIn) {} + +bool TransactionSignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& address, const CScript& scriptCode) const { CKey key; - if (!keystore.GetKey(address, key)) + if (!keystore->GetKey(address, key)) return false; - vector<unsigned char> vchSig; + uint256 hash = SignatureHash(scriptCode, *txTo, nIn, nHashType); if (!key.Sign(hash, vchSig)) return false; vchSig.push_back((unsigned char)nHashType); - scriptSigRet << vchSig; + return true; +} +static bool Sign1(const CKeyID& address, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) +{ + vector<unsigned char> vchSig; + if (!creator.CreateSig(vchSig, address, scriptCode)) + return false; + scriptSigRet << vchSig; return true; } -bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet) +static bool SignN(const vector<valtype>& multisigdata, const BaseSignatureCreator& creator, const CScript& scriptCode, CScript& scriptSigRet) { int nSigned = 0; int nRequired = multisigdata.front()[0]; @@ -40,20 +49,20 @@ bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint2 { const valtype& pubkey = multisigdata[i]; CKeyID keyID = CPubKey(pubkey).GetID(); - if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) + if (Sign1(keyID, creator, scriptCode, scriptSigRet)) ++nSigned; } return nSigned==nRequired; } /** - * Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type. + * Sign scriptPubKey using signature made with creator. * Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed), * unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script. * Returns false if scriptPubKey could not be completely satisfied. */ -bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType, - CScript& scriptSigRet, txnouttype& whichTypeRet) +static bool SignStep(const BaseSignatureCreator& creator, const CScript& scriptPubKey, + CScript& scriptSigRet, txnouttype& whichTypeRet) { scriptSigRet.clear(); @@ -69,39 +78,32 @@ bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash return false; case TX_PUBKEY: keyID = CPubKey(vSolutions[0]).GetID(); - return Sign1(keyID, keystore, hash, nHashType, scriptSigRet); + return Sign1(keyID, creator, scriptPubKey, scriptSigRet); case TX_PUBKEYHASH: keyID = CKeyID(uint160(vSolutions[0])); - if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet)) + if (!Sign1(keyID, creator, scriptPubKey, scriptSigRet)) return false; else { CPubKey vch; - keystore.GetPubKey(keyID, vch); + creator.KeyStore().GetPubKey(keyID, vch); scriptSigRet << ToByteVector(vch); } return true; case TX_SCRIPTHASH: - return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet); + return creator.KeyStore().GetCScript(uint160(vSolutions[0]), scriptSigRet); case TX_MULTISIG: scriptSigRet << OP_0; // workaround CHECKMULTISIG bug - return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet)); + return (SignN(vSolutions, creator, scriptPubKey, scriptSigRet)); } return false; } -bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& fromPubKey, CScript& scriptSig) { - assert(nIn < txTo.vin.size()); - CTxIn& txin = txTo.vin[nIn]; - - // Leave out the signature from the hash, since a signature can't sign itself. - // The checksig op will also drop the signatures from its hash. - uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType); - txnouttype whichType; - if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType)) + if (!SignStep(creator, fromPubKey, scriptSig, whichType)) return false; if (whichType == TX_SCRIPTHASH) @@ -109,21 +111,29 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl // Solver returns the subscript that need to be evaluated; // the final scriptSig is the signatures from that // and then the serialized subscript: - CScript subscript = txin.scriptSig; - - // Recompute txn hash using subscript in place of scriptPubKey: - uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType); + CScript subscript = scriptSig; txnouttype subType; bool fSolved = - Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH; + SignStep(creator, subscript, scriptSig, subType) && subType != TX_SCRIPTHASH; // Append serialized subscript whether or not it is completely signed: - txin.scriptSig << static_cast<valtype>(subscript); + scriptSig << static_cast<valtype>(subscript); if (!fSolved) return false; } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn)); + return VerifyScript(scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker()); +} + +bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType) +{ + assert(nIn < txTo.vin.size()); + CTxIn& txin = txTo.vin[nIn]; + + CTransaction txToConst(txTo); + TransactionSignatureCreator creator(&keystore, &txToConst, nIn, nHashType); + + return ProduceSignature(creator, fromPubKey, txin.scriptSig); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) @@ -144,7 +154,7 @@ static CScript PushAll(const vector<valtype>& values) return result; } -static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, +static CScript CombineMultisig(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const vector<valtype>& vSolutions, const vector<valtype>& sigs1, const vector<valtype>& sigs2) { @@ -174,7 +184,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey)) + if (checker.CheckSig(sig, pubkey, scriptPubKey)) { sigs[pubkey] = sig; break; @@ -199,7 +209,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& return result; } -static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, +static CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const txnouttype txType, const vector<valtype>& vSolutions, vector<valtype>& sigs1, vector<valtype>& sigs2) { @@ -233,12 +243,12 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction Solver(pubKey2, txType2, vSolutions2); sigs1.pop_back(); sigs2.pop_back(); - CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2); + CScript result = CombineSignatures(pubKey2, checker, txType2, vSolutions2, sigs1, sigs2); result << spk; return result; } case TX_MULTISIG: - return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2); + return CombineMultisig(scriptPubKey, checker, vSolutions, sigs1, sigs2); } return CScript(); @@ -247,6 +257,13 @@ static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2) { + TransactionSignatureChecker checker(&txTo, nIn); + return CombineSignatures(scriptPubKey, checker, scriptSig1, scriptSig2); +} + +CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, + const CScript& scriptSig1, const CScript& scriptSig2) +{ txnouttype txType; vector<vector<unsigned char> > vSolutions; Solver(scriptPubKey, txType, vSolutions); @@ -256,5 +273,5 @@ CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, vector<valtype> stack2; EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker()); - return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2); + return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2); } diff --git a/src/script/sign.h b/src/script/sign.h index e197d5fab3..0c4cf61e5e 100644 --- a/src/script/sign.h +++ b/src/script/sign.h @@ -8,19 +8,52 @@ #include "script/interpreter.h" +class CKeyID; class CKeyStore; class CScript; class CTransaction; struct CMutableTransaction; +/** Virtual base class for signature creators. */ +class BaseSignatureCreator { +protected: + const CKeyStore* keystore; + +public: + BaseSignatureCreator(const CKeyStore* keystoreIn) : keystore(keystoreIn) {} + const CKeyStore& KeyStore() const { return *keystore; }; + virtual ~BaseSignatureCreator() {} + virtual const BaseSignatureChecker& Checker() const =0; + + /** Create a singular (non-script) signature. */ + virtual bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const =0; +}; + +/** A signature creator for transactions. */ +class TransactionSignatureCreator : public BaseSignatureCreator { + const CTransaction* txTo; + unsigned int nIn; + int nHashType; + const TransactionSignatureChecker checker; + +public: + TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, int nHashTypeIn=SIGHASH_ALL); + const BaseSignatureChecker& Checker() const { return checker; } + bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const; +}; + +/** Produce a script signature using a generic signature creator. */ +bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig); + +/** Produce a script signature for a transaction. */ bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL); -/** - * Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders, - * combine them intelligently and return the result. - */ +/** Combine two script signatures using a generic signature checker, intelligently, possibly with OP_0 placeholders. */ +CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecker& checker, const CScript& scriptSig1, const CScript& scriptSig2); + +/** Combine two script signatures on transactions. */ CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2); #endif // BITCOIN_SCRIPT_SIGN_H diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp index 7b197c527d..4ce1591c35 100644 --- a/src/test/pow_tests.cpp +++ b/src/test/pow_tests.cpp @@ -17,51 +17,56 @@ BOOST_FIXTURE_TEST_SUITE(pow_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(get_next_work) { SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); int64_t nLastRetargetTime = 1261130161; // Block #30240 CBlockIndex pindexLast; pindexLast.nHeight = 32255; pindexLast.nTime = 1262152739; // Block #32255 pindexLast.nBits = 0x1d00ffff; - BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00d86a); + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00d86a); } /* Test the constraint on the upper bound for next work */ BOOST_AUTO_TEST_CASE(get_next_work_pow_limit) { SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); int64_t nLastRetargetTime = 1231006505; // Block #0 CBlockIndex pindexLast; pindexLast.nHeight = 2015; pindexLast.nTime = 1233061996; // Block #2015 pindexLast.nBits = 0x1d00ffff; - BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00ffff); + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00ffff); } /* Test the constraint on the lower bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_lower_limit_actual) { SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); int64_t nLastRetargetTime = 1279008237; // Block #66528 CBlockIndex pindexLast; pindexLast.nHeight = 68543; pindexLast.nTime = 1279297671; // Block #68543 pindexLast.nBits = 0x1c05a3f4; - BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1c0168fd); + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1c0168fd); } /* Test the constraint on the upper bound for actual time taken */ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual) { SelectParams(CBaseChainParams::MAIN); + const Consensus::Params& params = Params().GetConsensus(); + int64_t nLastRetargetTime = 1263163443; // NOTE: Not an actual block time CBlockIndex pindexLast; pindexLast.nHeight = 46367; pindexLast.nTime = 1269211443; // Block #46367 pindexLast.nBits = 0x1c387f6f; - BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime), 0x1d00e1fd); + BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index d97bea8bd2..4d5e92cbd4 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -6,6 +6,7 @@ #include "rpcclient.h" #include "base58.h" +#include "main.h" #include "wallet/wallet.h" #include "test/test_bitcoin.h" diff --git a/src/txdb.cpp b/src/txdb.cpp index da271bd5d1..df9ff8d8c9 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -5,6 +5,9 @@ #include "txdb.h" +#include "chainparams.h" +#include "hash.h" +#include "main.h" #include "pow.h" #include "uint256.h" @@ -222,7 +225,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nStatus = diskindex.nStatus; pindexNew->nTx = diskindex.nTx; - if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits)) + if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, Params().GetConsensus())) return error("LoadBlockIndex(): CheckProofOfWork failed: %s", pindexNew->ToString()); pcursor->Next(); diff --git a/src/txdb.h b/src/txdb.h index f6b6b84fcf..86e1c5d831 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -6,15 +6,17 @@ #ifndef BITCOIN_TXDB_H #define BITCOIN_TXDB_H +#include "coins.h" #include "leveldbwrapper.h" -#include "main.h" #include <map> #include <string> #include <utility> #include <vector> -class CCoins; +class CBlockFileInfo; +class CBlockIndex; +struct CDiskTxPos; class uint256; //! -dbcache default (MiB) diff --git a/src/util.cpp b/src/util.cpp index 792f00b61d..4192e44ae1 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -723,18 +723,18 @@ void RenameThread(const char* name) void SetupEnvironment() { -#ifndef WIN32 - try - { -#if BOOST_FILESYSTEM_VERSION == 3 - boost::filesystem::path::codecvt(); // Raises runtime error if current locale is invalid -#else // boost filesystem v2 - std::locale(); // Raises runtime error if current locale is invalid -#endif + // On most POSIX systems (e.g. Linux, but not BSD) the environment's locale + // may be invalid, in which case the "C" locale is used as fallback. +#if !defined(WIN32) && !defined(MAC_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) + try { + std::locale(""); // Raises a runtime error if current locale is invalid } catch (const std::runtime_error&) { - setenv("LC_ALL", "C", 1); // Force C locale + std::locale::global(std::locale("C")); } #endif + // The path locale is lazy initialized and to avoid deinitialization errors + // in multithreading environments, it is set explicitly by the main thread. + boost::filesystem::path::imbue(std::locale()); } void SetThreadPriority(int nPriority) diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp new file mode 100644 index 0000000000..aa9aefb0de --- /dev/null +++ b/src/validationinterface.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-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 "validationinterface.h" + +static CMainSignals g_signals; + +CMainSignals& GetMainSignals() +{ + return g_signals; +} + +void RegisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); + g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); + 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, _1)); + 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, _1)); + g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); + g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); + g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); + g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); + g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); +} + +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(); + g_signals.UpdatedTransaction.disconnect_all_slots(); + g_signals.EraseTransaction.disconnect_all_slots(); + g_signals.SyncTransaction.disconnect_all_slots(); +} + +void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { + g_signals.SyncTransaction(tx, pblock); +} diff --git a/src/validationinterface.h b/src/validationinterface.h new file mode 100644 index 0000000000..b4c93d72ca --- /dev/null +++ b/src/validationinterface.h @@ -0,0 +1,62 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-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. + +#ifndef BITCOIN_VALIDATIONINTERFACE_H +#define BITCOIN_VALIDATIONINTERFACE_H + +#include <boost/signals2/signal.hpp> + +class CBlock; +struct CBlockLocator; +class CTransaction; +class CValidationInterface; +class CValidationState; +class uint256; + +// These functions dispatch to one or all registered wallets + +/** Register a wallet to receive updates from core */ +void RegisterValidationInterface(CValidationInterface* pwalletIn); +/** Unregister a wallet from core */ +void UnregisterValidationInterface(CValidationInterface* pwalletIn); +/** Unregister all wallets from core */ +void UnregisterAllValidationInterfaces(); +/** Push an updated transaction to all registered wallets */ +void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); + +class CValidationInterface { +protected: + virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}; + virtual void EraseFromWallet(const uint256 &hash) {}; + virtual void SetBestChain(const CBlockLocator &locator) {}; + virtual void UpdatedTransaction(const uint256 &hash) {}; + virtual void Inventory(const uint256 &hash) {}; + virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}; + virtual void BlockChecked(const CBlock&, const CValidationState&) {}; + friend void ::RegisterValidationInterface(CValidationInterface*); + friend void ::UnregisterValidationInterface(CValidationInterface*); + friend void ::UnregisterAllValidationInterfaces(); +}; + +struct CMainSignals { + /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ + boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction; + /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */ + boost::signals2::signal<void (const uint256 &)> EraseTransaction; + /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ + boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; + /** Notifies listeners of a new active block chain. */ + boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; + /** Notifies listeners about an inventory item being seen on the network. */ + boost::signals2::signal<void (const uint256 &)> Inventory; + /** Tells listeners to broadcast their data. */ + boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast; + /** Notifies listeners of a block validation result */ + boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; +}; + +CMainSignals& GetMainSignals(); + +#endif // BITCOIN_VALIDATIONINTERFACE_H diff --git a/src/crypter.cpp b/src/wallet/crypter.cpp index c7f7e21679..c7f7e21679 100644 --- a/src/crypter.cpp +++ b/src/wallet/crypter.cpp diff --git a/src/crypter.h b/src/wallet/crypter.h index 32746b00df..32746b00df 100644 --- a/src/crypter.h +++ b/src/wallet/crypter.h diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 36946b7dcc..53cfcf0961 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -148,7 +148,7 @@ void CDBEnv::MakeMock() fMockDb = true; } -CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)) +CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile)) { LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); @@ -165,7 +165,7 @@ CDBEnv::VerifyResult CDBEnv::Verify(std::string strFile, bool (*recoverFunc)(CDB return (fRecovered ? RECOVER_OK : RECOVER_FAIL); } -bool CDBEnv::Salvage(std::string strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult) +bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector<CDBEnv::KeyValPair>& vResult) { LOCK(cs_db); assert(mapFileUseCount.count(strFile) == 0); diff --git a/src/wallet/db.h b/src/wallet/db.h index 71133f9699..0c2c139d89 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -59,7 +59,7 @@ public: enum VerifyResult { VERIFY_OK, RECOVER_OK, RECOVER_FAIL }; - VerifyResult Verify(std::string strFile, bool (*recoverFunc)(CDBEnv& dbenv, std::string strFile)); + VerifyResult Verify(const std::string& strFile, bool (*recoverFunc)(CDBEnv& dbenv, const std::string& strFile)); /** * Salvage data from a file that Verify says is bad. * fAggressive sets the DB_AGGRESSIVE flag (see berkeley DB->verify() method documentation). @@ -68,7 +68,7 @@ public: * for huge databases. */ typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair; - bool Salvage(std::string strFile, bool fAggressive, std::vector<KeyValPair>& vResult); + bool Salvage(const std::string& strFile, bool fAggressive, std::vector<KeyValPair>& vResult); bool Open(const boost::filesystem::path& path); void Close(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5502b0b261..29f3eda15d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6,10 +6,11 @@ #include "amount.h" #include "base58.h" #include "core_io.h" -#include "rpcserver.h" #include "init.h" +#include "main.h" #include "net.h" #include "netbase.h" +#include "rpcserver.h" #include "timedata.h" #include "util.h" #include "utilmoneystr.h" @@ -2095,3 +2096,25 @@ Value getwalletinfo(const Array& params, bool fHelp) obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); return obj; } + +Value resendwallettransactions(const Array& params, bool fHelp) +{ + if (fHelp || params.size() != 0) + throw runtime_error( + "resendwallettransactions\n" + "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n" + "Intended only for testing; the wallet code periodically re-broadcasts\n" + "automatically.\n" + "Returns array of transaction ids that were re-broadcast.\n" + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime()); + Array result; + BOOST_FOREACH(const uint256& txid, txids) + { + result.push_back(txid.ToString()); + } + return result; +} diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 44b416d496..a10123002e 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -8,6 +8,7 @@ #include "base58.h" #include "checkpoints.h" #include "coincontrol.h" +#include "main.h" #include "net.h" #include "script/script.h" #include "script/sign.h" @@ -345,7 +346,7 @@ void CWallet::Flush(bool shutdown) bitdb.Flush(shutdown); } -bool CWallet::Verify(const string walletFile, string& warningString, string& errorString) +bool CWallet::Verify(const string& walletFile, string& warningString, string& errorString) { if (!bitdb.Open(GetDataDir())) { @@ -817,6 +818,18 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const return 0; } +isminetype CWallet::IsMine(const CTxOut& txout) const +{ + return ::IsMine(*this, txout.scriptPubKey); +} + +CAmount CWallet::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 CWallet::IsChange(const CTxOut& txout) const { // TODO: fix handling of 'change' outputs. The assumption is that any @@ -839,6 +852,62 @@ bool CWallet::IsChange(const CTxOut& txout) const return false; } +CAmount CWallet::GetChange(const CTxOut& txout) const +{ + if (!MoneyRange(txout.nValue)) + throw std::runtime_error("CWallet::GetChange(): value out of range"); + return (IsChange(txout) ? txout.nValue : 0); +} + +bool CWallet::IsMine(const CTransaction& tx) const +{ + BOOST_FOREACH(const CTxOut& txout, tx.vout) + if (IsMine(txout)) + return true; + return false; +} + +bool CWallet::IsFromMe(const CTransaction& tx) const +{ + return (GetDebit(tx, ISMINE_ALL) > 0); +} + +CAmount CWallet::GetDebit(const CTransaction& tx, const isminefilter& filter) const +{ + CAmount nDebit = 0; + BOOST_FOREACH(const CTxIn& txin, tx.vin) + { + nDebit += GetDebit(txin, filter); + if (!MoneyRange(nDebit)) + throw std::runtime_error("CWallet::GetDebit(): value out of range"); + } + return nDebit; +} + +CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) const +{ + CAmount nCredit = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nCredit += GetCredit(txout, filter); + if (!MoneyRange(nCredit)) + throw std::runtime_error("CWallet::GetCredit(): value out of range"); + } + return nCredit; +} + +CAmount CWallet::GetChange(const CTransaction& tx) const +{ + CAmount nChange = 0; + BOOST_FOREACH(const CTxOut& txout, tx.vout) + { + nChange += GetChange(txout); + if (!MoneyRange(nChange)) + throw std::runtime_error("CWallet::GetChange(): value out of range"); + } + return nChange; +} + int64_t CWalletTx::GetTxTime() const { int64_t n = nTimeSmart; @@ -1045,15 +1114,17 @@ void CWallet::ReacceptWalletTransactions() } } -void CWalletTx::RelayWalletTransaction() +bool CWalletTx::RelayWalletTransaction() { if (!IsCoinBase()) { if (GetDepthInMainChain() == 0) { LogPrintf("Relaying wtx %s\n", GetHash().ToString()); RelayTransaction((CTransaction)*this); + return true; } } + return false; } set<uint256> CWalletTx::GetConflicts() const @@ -1255,7 +1326,31 @@ bool CWalletTx::IsTrusted() const return true; } -void CWallet::ResendWalletTransactions() +std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime) +{ + std::vector<uint256> result; + + LOCK(cs_wallet); + // Sort them in chronological order + multimap<unsigned int, CWalletTx*> mapSorted; + BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) + { + CWalletTx& wtx = item.second; + // Don't rebroadcast if newer than nTime: + if (wtx.nTimeReceived > nTime) + continue; + mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); + } + BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) + { + CWalletTx& wtx = *item.second; + if (wtx.RelayWalletTransaction()) + result.push_back(wtx.GetHash()); + } + return result; +} + +void CWallet::ResendWalletTransactions(int64_t nBestBlockTime) { // Do this infrequently and randomly to avoid giving away // that these are our transactions. @@ -1267,30 +1362,15 @@ void CWallet::ResendWalletTransactions() return; // Only do it if there's been a new block since last time - if (nTimeBestReceived < nLastResend) + if (nBestBlockTime < nLastResend) return; nLastResend = GetTime(); - // Rebroadcast any of our txes that aren't in a block yet - LogPrintf("ResendWalletTransactions()\n"); - { - LOCK(cs_wallet); - // Sort them in chronological order - multimap<unsigned int, CWalletTx*> mapSorted; - BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) - { - CWalletTx& wtx = item.second; - // Don't rebroadcast until it's had plenty of time that - // it should have gotten in already by now. - if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60) - mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx)); - } - BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted) - { - CWalletTx& wtx = *item.second; - wtx.RelayWalletTransaction(); - } - } + // Rebroadcast unconfirmed txes older than 5 minutes before the last + // block was found: + std::vector<uint256> relayed = ResendWalletTransactionsBefore(nBestBlockTime-5*60); + if (!relayed.empty()) + LogPrintf("%s: rebroadcast %u unconfirmed transactions\n", __func__, relayed.size()); } /** @} */ // end of mapWallet diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 1a9feff9f3..6ae1c87b1d 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -7,13 +7,15 @@ #define BITCOIN_WALLET_H #include "amount.h" -#include "primitives/block.h" -#include "primitives/transaction.h" -#include "crypter.h" #include "key.h" #include "keystore.h" -#include "main.h" +#include "primitives/block.h" +#include "primitives/transaction.h" +#include "tinyformat.h" #include "ui_interface.h" +#include "utilstrencodings.h" +#include "validationinterface.h" +#include "wallet/crypter.h" #include "wallet/wallet_ismine.h" #include "wallet/walletdb.h" @@ -48,10 +50,12 @@ static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWa static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000; class CAccountingEntry; +class CBlockIndex; class CCoinControl; class COutput; class CReserveKey; class CScript; +class CTxMemPool; class CWalletTx; /** (client) version numbers for particular wallet features */ @@ -377,7 +381,7 @@ public: int64_t GetTxTime() const; int GetRequestCount() const; - void RelayWalletTransaction(); + bool RelayWalletTransaction(); std::set<uint256> GetConflicts() const; }; @@ -610,7 +614,8 @@ public: void EraseFromWallet(const uint256 &hash); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); - void ResendWalletTransactions(); + void ResendWalletTransactions(int64_t nBestBlockTime); + std::vector<uint256> ResendWalletTransactionsBefore(int64_t nTime); CAmount GetBalance() const; CAmount GetUnconfirmedBalance() const; CAmount GetImmatureBalance() const; @@ -640,68 +645,16 @@ public: isminetype IsMine(const CTxIn& txin) const; CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; - isminetype IsMine(const CTxOut& txout) const - { - return ::IsMine(*this, txout.scriptPubKey); - } - 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); - } + isminetype IsMine(const CTxOut& txout) const; + CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const; bool IsChange(const CTxOut& txout) const; - CAmount GetChange(const CTxOut& txout) const - { - if (!MoneyRange(txout.nValue)) - throw std::runtime_error("CWallet::GetChange(): value out of range"); - return (IsChange(txout) ? txout.nValue : 0); - } - bool IsMine(const CTransaction& tx) const - { - BOOST_FOREACH(const CTxOut& txout, tx.vout) - if (IsMine(txout)) - return true; - return false; - } + CAmount GetChange(const CTxOut& txout) const; + bool IsMine(const CTransaction& tx) const; /** should probably be renamed to IsRelevantToMe */ - bool IsFromMe(const CTransaction& tx) const - { - return (GetDebit(tx, ISMINE_ALL) > 0); - } - CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const - { - CAmount nDebit = 0; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - nDebit += GetDebit(txin, filter); - if (!MoneyRange(nDebit)) - throw std::runtime_error("CWallet::GetDebit(): value out of range"); - } - return nDebit; - } - CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const - { - CAmount nCredit = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - nCredit += GetCredit(txout, filter); - if (!MoneyRange(nCredit)) - throw std::runtime_error("CWallet::GetCredit(): value out of range"); - } - return nCredit; - } - CAmount GetChange(const CTransaction& tx) const - { - CAmount nChange = 0; - BOOST_FOREACH(const CTxOut& txout, tx.vout) - { - nChange += GetChange(txout); - if (!MoneyRange(nChange)) - throw std::runtime_error("CWallet::GetChange(): value out of range"); - } - return nChange; - } + bool IsFromMe(const CTransaction& tx) const; + CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; + CAmount GetChange(const CTransaction& tx) const; void SetBestChain(const CBlockLocator& loc); DBErrors LoadWallet(bool& fFirstRunRet); @@ -747,7 +700,7 @@ public: void Flush(bool shutdown=false); //! Verify the wallet database and perform salvage if required - static bool Verify(const std::string walletFile, std::string& warningString, std::string& errorString); + static bool Verify(const std::string& walletFile, std::string& warningString, std::string& errorString); /** * Address book entry changed. diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 880026d187..de56a2d1af 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -6,6 +6,7 @@ #include "wallet/walletdb.h" #include "base58.h" +#include "main.h" #include "protocol.h" #include "serialize.h" #include "sync.h" @@ -891,7 +892,7 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) // // Try to (very carefully!) recover wallet.dat if there is a problem. // -bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) +bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys) { // Recovery procedure: // move wallet.dat to wallet.timestamp.bak @@ -968,7 +969,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys) return fSuccess; } -bool CWalletDB::Recover(CDBEnv& dbenv, std::string filename) +bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename) { return CWalletDB::Recover(dbenv, filename, false); } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 6aa0fa40df..a1c38b9d3d 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -127,8 +127,8 @@ public: DBErrors LoadWallet(CWallet* pwallet); DBErrors FindWalletTx(CWallet* pwallet, std::vector<uint256>& vTxHash, std::vector<CWalletTx>& vWtx); DBErrors ZapWalletTx(CWallet* pwallet, std::vector<CWalletTx>& vWtx); - static bool Recover(CDBEnv& dbenv, std::string filename, bool fOnlyKeys); - static bool Recover(CDBEnv& dbenv, std::string filename); + static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys); + static bool Recover(CDBEnv& dbenv, const std::string& filename); private: CWalletDB(const CWalletDB&); |