diff options
62 files changed, 596 insertions, 412 deletions
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index acb54dd354..28c1814998 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -4,6 +4,8 @@ This issue tracker is only for technical issues related to bitcoin-core. General bitcoin questions and/or support requests and are best directed to the [Bitcoin StackExchange](https://bitcoin.stackexchange.com). +For reporting security issues, please read instructions at [https://bitcoincore.org/en/contact/](https://bitcoincore.org/en/contact/). + ### Describe the issue ### Can you reliably reproduce the issue? diff --git a/configure.ac b/configure.ac index 705327e816..319e1afe27 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,6 @@ else CXXFLAGS_overridden=no fi AC_PROG_CXX -m4_ifdef([AC_PROG_OBJCXX],[AC_PROG_OBJCXX]) dnl By default, libtool for mingw refuses to link static libs into a dll for dnl fear of mixing pic/non-pic objects, and import/export complications. Since @@ -60,6 +59,15 @@ AX_CXX_COMPILE_STDCXX([11], [noext], [mandatory]) dnl Check if -latomic is required for <std::atomic> CHECK_ATOMIC +dnl Unless the user specified OBJCXX, force it to be the same as CXX. This ensures +dnl that we get the same -std flags for both. +m4_ifdef([AC_PROG_OBJCXX],[ +if test "x${OBJCXX+set}" = "x"; then + OBJCXX="${CXX}" +fi +AC_PROG_OBJCXX +]) + dnl Libtool init checks. LT_INIT([pic-only]) @@ -1126,3 +1134,28 @@ case ${OS} in mv qa/pull-tester/tests_config-2.py qa/pull-tester/tests_config.py ;; esac + +echo +echo "Options used to compile and link:" +echo " with wallet = $enable_wallet" +echo " with gui / qt = $bitcoin_enable_qt" +if test x$bitcoin_enable_qt != xno; then + echo " qt version = $bitcoin_qt_got_major_vers" + echo " with qr = $use_qr" +fi +echo " with zmq = $use_zmq" +echo " with test = $use_tests" +echo " with bench = $use_bench" +echo " with upnp = $use_upnp" +echo " debug enabled = $enable_debug" +echo +echo " target os = $TARGET_OS" +echo " build os = $BUILD_OS" +echo +echo " CC = $CC" +echo " CFLAGS = $CFLAGS" +echo " CPPFLAGS = $CPPFLAGS" +echo " CXX = $CXX" +echo " CXXFLAGS = $CXXFLAGS" +echo " LDFLAGS = $LDFLAGS" +echo diff --git a/doc/Doxyfile b/doc/Doxyfile index a0cbf7139a..ef55acdbc3 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = Bitcoin +PROJECT_NAME = "Bitcoin Core" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/doc/release-notes.md b/doc/release-notes.md index f511fee22e..fe7f69d1f8 100644 --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -53,11 +53,15 @@ Removal of Priority Estimation - Estimation of "priority" needed for a transaction to be included within a target number of blocks has been removed. The rpc calls are deprecated and will either - return -1 or 1e24 appropriately. The format for fee_estimates.dat has also + return -1 or 1e24 appropriately. The format for `fee_estimates.dat` has also changed to no longer save these priority estimates. It will automatically be converted to the new format which is not readable by prior versions of the software. +- The concept of "priority" transactions is planned to be removed in the next + major version. To prepare for this, the default for the rate limit of priority + transactions (`-limitfreerelay`) has been set to `0` kB/minute. + 0.14.0 Change log ================= diff --git a/qa/rpc-tests/p2p-compactblocks.py b/qa/rpc-tests/p2p-compactblocks.py index 1b4c8d90e7..ab4b809ded 100755 --- a/qa/rpc-tests/p2p-compactblocks.py +++ b/qa/rpc-tests/p2p-compactblocks.py @@ -27,6 +27,7 @@ class TestNode(SingleNodeConnCB): self.last_cmpctblock = None self.block_announced = False self.last_getdata = None + self.last_getheaders = None self.last_getblocktxn = None self.last_block = None self.last_blocktxn = None @@ -64,6 +65,9 @@ class TestNode(SingleNodeConnCB): def on_getdata(self, conn, message): self.last_getdata = message + def on_getheaders(self, conn, message): + self.last_getheaders = message + def on_getblocktxn(self, conn, message): self.last_getblocktxn = message @@ -186,12 +190,15 @@ class CompactBlocksTest(BitcoinTestFramework): def check_announcement_of_new_block(node, peer, predicate): peer.clear_block_announcement() - node.generate(1) - got_message = wait_until(lambda: peer.block_announced, timeout=30) + block_hash = int(node.generate(1)[0], 16) + peer.wait_for_block_announcement(block_hash, timeout=30) assert(peer.block_announced) assert(got_message) + with mininode_lock: - assert(predicate(peer)) + assert predicate(peer), ( + "block_hash={!r}, cmpctblock={!r}, inv={!r}".format( + block_hash, peer.last_cmpctblock, peer.last_inv)) # We shouldn't get any block announcements via cmpctblock yet. check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None) @@ -393,6 +400,9 @@ class CompactBlocksTest(BitcoinTestFramework): if announce == "inv": test_node.send_message(msg_inv([CInv(2, block.sha256)])) + success = wait_until(lambda: test_node.last_getheaders is not None, timeout=30) + assert(success) + test_node.send_header_for_blocks([block]) else: test_node.send_header_for_blocks([block]) success = wait_until(lambda: test_node.last_getdata is not None, timeout=30) diff --git a/qa/rpc-tests/p2p-segwit.py b/qa/rpc-tests/p2p-segwit.py index 09ab1b80fc..6ecd84c3f0 100755 --- a/qa/rpc-tests/p2p-segwit.py +++ b/qa/rpc-tests/p2p-segwit.py @@ -64,6 +64,9 @@ class TestNode(NodeConnCB): self.getdataset.add(inv.hash) self.last_getdata = message + def on_getheaders(self, conn, message): + self.last_getheaders = message + def on_pong(self, conn, message): self.last_pong = message @@ -97,6 +100,10 @@ class TestNode(NodeConnCB): test_function = lambda: self.last_getdata != None self.sync(test_function, timeout) + def wait_for_getheaders(self, timeout=60): + test_function = lambda: self.last_getheaders != None + self.sync(test_function, timeout) + def wait_for_inv(self, expected_inv, timeout=60): test_function = lambda: self.last_inv != expected_inv self.sync(test_function, timeout) @@ -111,12 +118,15 @@ class TestNode(NodeConnCB): def announce_block_and_wait_for_getdata(self, block, use_header, timeout=60): with mininode_lock: self.last_getdata = None + self.last_getheaders = None + msg = msg_headers() + msg.headers = [ CBlockHeader(block) ] if use_header: - msg = msg_headers() - msg.headers = [ CBlockHeader(block) ] self.send_message(msg) else: self.send_message(msg_inv(inv=[CInv(2, block.sha256)])) + self.wait_for_getheaders() + self.send_message(msg) self.wait_for_getdata() return diff --git a/qa/rpc-tests/proxy_test.py b/qa/rpc-tests/proxy_test.py index 27160cae07..9ccc0ffbb0 100755 --- a/qa/rpc-tests/proxy_test.py +++ b/qa/rpc-tests/proxy_test.py @@ -4,10 +4,16 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. import socket +import os from test_framework.socks5 import Socks5Configuration, Socks5Command, Socks5Server, AddressType from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import * +from test_framework.util import ( + PORT_MIN, + PORT_RANGE, + start_nodes, + assert_equal, +) from test_framework.netutil import test_ipv6_local ''' Test plan: @@ -33,6 +39,8 @@ addnode connect to onion addnode connect to generic DNS name ''' +RANGE_BEGIN = PORT_MIN + 2 * PORT_RANGE # Start after p2p and rpc ports + class ProxyTest(BitcoinTestFramework): def __init__(self): @@ -44,19 +52,19 @@ class ProxyTest(BitcoinTestFramework): # Create two proxies on different ports # ... one unauthenticated self.conf1 = Socks5Configuration() - self.conf1.addr = ('127.0.0.1', 13000 + (os.getpid() % 1000)) + self.conf1.addr = ('127.0.0.1', RANGE_BEGIN + (os.getpid() % 1000)) self.conf1.unauth = True self.conf1.auth = False # ... one supporting authenticated and unauthenticated (Tor) self.conf2 = Socks5Configuration() - self.conf2.addr = ('127.0.0.1', 14000 + (os.getpid() % 1000)) + self.conf2.addr = ('127.0.0.1', RANGE_BEGIN + 1000 + (os.getpid() % 1000)) self.conf2.unauth = True self.conf2.auth = True if self.have_ipv6: # ... one on IPv6 with similar configuration self.conf3 = Socks5Configuration() self.conf3.af = socket.AF_INET6 - self.conf3.addr = ('::1', 15000 + (os.getpid() % 1000)) + self.conf3.addr = ('::1', RANGE_BEGIN + 2000 + (os.getpid() % 1000)) self.conf3.unauth = True self.conf3.auth = True else: diff --git a/qa/rpc-tests/rawtransactions.py b/qa/rpc-tests/rawtransactions.py index ab6d2e8def..33a6f2b0cc 100755 --- a/qa/rpc-tests/rawtransactions.py +++ b/qa/rpc-tests/rawtransactions.py @@ -2,11 +2,15 @@ # Copyright (c) 2014-2016 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""rawtranscation RPCs QA test. -# -# Test re-org scenarios with a mempool that contains transactions -# that spend (directly or indirectly) coinbase transactions. -# +# Tests the following RPCs: +# - createrawtransaction +# - signrawtransaction +# - sendrawtransaction +# - decoderawtransaction +# - getrawtransaction +""" from test_framework.test_framework import BitcoinTestFramework from test_framework.util import * @@ -138,6 +142,33 @@ class RawTransactionsTest(BitcoinTestFramework): self.sync_all() assert_equal(self.nodes[0].getbalance(), bal+Decimal('50.00000000')+Decimal('2.19000000')) #block reward + tx + # getrawtransaction tests + # 1. valid parameters - only supply txid + txHash = rawTx["hash"] + assert_equal(self.nodes[0].getrawtransaction(txHash), rawTxSigned['hex']) + + # 2. valid parameters - supply txid and 0 for non-verbose + assert_equal(self.nodes[0].getrawtransaction(txHash, 0), rawTxSigned['hex']) + + # 3. valid parameters - supply txid and False for non-verbose + assert_equal(self.nodes[0].getrawtransaction(txHash, False), rawTxSigned['hex']) + + # 4. valid parameters - supply txid and 1 for verbose. + # We only check the "hex" field of the output so we don't need to update this test every time the output format changes. + assert_equal(self.nodes[0].getrawtransaction(txHash, 1)["hex"], rawTxSigned['hex']) + + # 5. valid parameters - supply txid and True for non-verbose + assert_equal(self.nodes[0].getrawtransaction(txHash, True)["hex"], rawTxSigned['hex']) + + # 6. invalid parameters - supply txid and string "Flase" + assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, "Flase") + + # 7. invalid parameters - supply txid and empty array + assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, []) + + # 8. invalid parameters - supply txid and empty dict + assert_raises(JSONRPCException, self.nodes[0].getrawtransaction, txHash, {}) + inputs = [ {'txid' : "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000", 'vout' : 1, 'sequence' : 1000}] outputs = { self.nodes[0].getnewaddress() : 1 } rawtx = self.nodes[0].createrawtransaction(inputs, outputs) diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py index 81b2442e6a..37b98c576e 100755 --- a/qa/rpc-tests/sendheaders.py +++ b/qa/rpc-tests/sendheaders.py @@ -348,14 +348,13 @@ class SendHeadersTest(BitcoinTestFramework): if j == 0: # Announce via inv test_node.send_block_inv(tip) - test_node.wait_for_getdata([tip], timeout=5) + test_node.wait_for_getheaders(timeout=5) + # Should have received a getheaders now + test_node.send_header_for_blocks(blocks) # Test that duplicate inv's won't result in duplicate # getdata requests, or duplicate headers announcements - inv_node.send_block_inv(tip) - # Should have received a getheaders as well! - test_node.send_header_for_blocks(blocks) - test_node.wait_for_getdata([x.sha256 for x in blocks[0:-1]], timeout=5) - [ inv_node.send_block_inv(x.sha256) for x in blocks[0:-1] ] + [ inv_node.send_block_inv(x.sha256) for x in blocks ] + test_node.wait_for_getdata([x.sha256 for x in blocks], timeout=5) inv_node.sync_with_ping() else: # Announce via headers diff --git a/qa/rpc-tests/test_framework/comptool.py b/qa/rpc-tests/test_framework/comptool.py index 7c92d3f828..17679fc7e1 100755 --- a/qa/rpc-tests/test_framework/comptool.py +++ b/qa/rpc-tests/test_framework/comptool.py @@ -111,6 +111,11 @@ class TestNode(NodeConnCB): m.locator = self.block_store.get_locator(self.bestblockhash) self.conn.send_message(m) + def send_header(self, header): + m = msg_headers() + m.headers.append(header) + self.conn.send_message(m) + # This assumes BIP31 def send_ping(self, nonce): self.pingMap[nonce] = True @@ -345,8 +350,16 @@ class TestManager(object): # Either send inv's to each node and sync, or add # to invqueue for later inv'ing. if (test_instance.sync_every_block): - [ c.cb.send_inv(block) for c in self.connections ] - self.sync_blocks(block.sha256, 1) + # if we expect success, send inv and sync every block + # if we expect failure, just push the block and see what happens. + if outcome == True: + [ c.cb.send_inv(block) for c in self.connections ] + self.sync_blocks(block.sha256, 1) + else: + [ c.send_message(msg_block(block)) for c in self.connections ] + [ c.cb.send_ping(self.ping_counter) for c in self.connections ] + self.wait_for_pings(self.ping_counter) + self.ping_counter += 1 if (not self.check_results(tip, outcome)): raise AssertionError("Test failed at test %d" % test_number) else: @@ -354,6 +367,8 @@ class TestManager(object): elif isinstance(b_or_t, CBlockHeader): block_header = b_or_t self.block_store.add_header(block_header) + [ c.cb.send_header(block_header) for c in self.connections ] + else: # Tx test runner assert(isinstance(b_or_t, CTransaction)) tx = b_or_t diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index b5ef0689b4..0b3585c6b2 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -123,19 +123,26 @@ def str_to_b64str(string): def sync_blocks(rpc_connections, *, wait=1, timeout=60): """ - Wait until everybody has the same tip + Wait until everybody has the same tip. + + sync_blocks needs to be called with an rpc_connections set that has least + one node already synced to the latest, stable tip, otherwise there's a + chance it might return before all nodes are stably synced. """ maxheight = 0 - while timeout > 0: + start_time = cur_time = time.time() + while cur_time <= start_time + timeout: tips = [r.waitforblockheight(maxheight, int(wait * 1000)) for r in rpc_connections] heights = [t["height"] for t in tips] - if tips == [tips[0]] * len(tips): + if all(t == tips[0] for t in tips): return - if heights == [heights[0]] * len(heights): - raise AssertionError("Block sync failed: (Hashes don't match)") - timeout -= wait + if all(h == heights[0] for h in heights): + raise AssertionError("Block sync failed, mismatched block hashes:{}".format( + "".join("\n {!r}".format(tip) for tip in tips))) maxheight = max(heights) - raise AssertionError("Block sync failed with heights: {}".format(heights)) + cur_time = time.time() + raise AssertionError("Block sync to height {} timed out:{}".format( + maxheight, "".join("\n {!r}".format(tip) for tip in tips))) def sync_chain(rpc_connections, *, wait=1, timeout=60): """ @@ -524,10 +531,14 @@ def assert_greater_than(thing1, thing2): raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) def assert_raises(exc, fun, *args, **kwds): + assert_raises_message(exc, None, fun, *args, **kwds) + +def assert_raises_message(exc, message, fun, *args, **kwds): try: fun(*args, **kwds) - except exc: - pass + except exc as e: + if message is not None and message not in e.error['message']: + raise AssertionError("Expected substring not found:"+e.error['message']) except Exception as e: raise AssertionError("Unexpected exception raised: "+type(e).__name__) else: diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index e43f6ea5d2..3c0dc0f4ea 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -71,7 +71,7 @@ class WalletTest (BitcoinTestFramework): unspent_0 = self.nodes[2].listunspent()[0] unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} self.nodes[2].lockunspent(False, [unspent_0]) - assert_raises(JSONRPCException, self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) + assert_raises_message(JSONRPCException, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) assert_equal([unspent_0], self.nodes[2].listlockunspent()) self.nodes[2].lockunspent(True, [unspent_0]) assert_equal(len(self.nodes[2].listlockunspent()), 0) diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include index 840d33c1b5..246797a1b2 100644 --- a/src/Makefile.bench.include +++ b/src/Makefile.bench.include @@ -67,7 +67,9 @@ bitcoin_bench_clean : FORCE %.raw.h: %.raw @$(MKDIR_P) $(@D) - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};" >> $@ + @{ \ + echo "static unsigned const char $(*F)[] = {" && \ + $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ + echo "};"; \ + } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/Makefile.test.include b/src/Makefile.test.include index fa610e300c..a14adc7876 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -149,16 +149,10 @@ endif %.json.h: %.json @$(MKDIR_P) $(@D) - @echo "namespace json_tests{" > $@ - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};};" >> $@ - @echo "Generated $@" - -%.raw.h: %.raw - @$(MKDIR_P) $(@D) - @echo "namespace alert_tests{" > $@ - @echo "static unsigned const char $(*F)[] = {" >> $@ - @$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> $@ - @echo "};};" >> $@ + @{ \ + echo "namespace json_tests{" && \ + echo "static unsigned const char $(*F)[] = {" && \ + $(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' && \ + echo "};};"; \ + } > "$@.new" && mv -f "$@.new" "$@" @echo "Generated $@" diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 227546a7a7..8942da8c74 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -64,8 +64,11 @@ bool State::KeepRunning() return true; } if (elapsed*16 < maxElapsed) { - countMask = ((countMask<<1)|1) & ((1LL<<60)-1); - countMaskInv = 1./(countMask+1); + uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1); + if ((count & newCountMask)==0) { + countMask = newCountMask; + countMaskInv = 1./(countMask+1); + } } } lastTime = now; diff --git a/src/bench/checkblock.cpp b/src/bench/checkblock.cpp index bb596ce7f9..4a564d3fc8 100644 --- a/src/bench/checkblock.cpp +++ b/src/bench/checkblock.cpp @@ -46,8 +46,8 @@ static void DeserializeAndCheckBlockTest(benchmark::State& state) stream >> block; assert(stream.Rewind(sizeof(block_bench::block413567))); - CValidationState state; - assert(CheckBlock(block, state, params)); + CValidationState validationState; + assert(CheckBlock(block, validationState, params)); } } diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 6c66efcc9c..6d17bc392f 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -638,7 +638,7 @@ static int CommandLineRawTx(int argc, char* argv[]) if (strHexTx == "-") // "-" implies standard input strHexTx = readStdin(); - if (!DecodeHexTx(txDecodeTmp, strHexTx)) + if (!DecodeHexTx(txDecodeTmp, strHexTx, true)) throw runtime_error("invalid transaction encoding"); startArg = 2; diff --git a/src/blockencodings.cpp b/src/blockencodings.cpp index dbed90583d..f14ae1c412 100644 --- a/src/blockencodings.cpp +++ b/src/blockencodings.cpp @@ -24,7 +24,7 @@ CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool f //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase prefilledtxn[0] = {0, block.vtx[0]}; for (size_t i = 1; i < block.vtx.size(); i++) { - const CTransaction& tx = block.vtx[i]; + const CTransaction& tx = *block.vtx[i]; shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash()); } } @@ -59,7 +59,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c int32_t lastprefilledindex = -1; for (size_t i = 0; i < cmpctblock.prefilledtxn.size(); i++) { - if (cmpctblock.prefilledtxn[i].tx.IsNull()) + if (cmpctblock.prefilledtxn[i].tx->IsNull()) return READ_STATUS_INVALID; lastprefilledindex += cmpctblock.prefilledtxn[i].index + 1; //index is a uint16_t, so cant overflow here @@ -71,7 +71,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c // have neither a prefilled txn or a shorttxid! return READ_STATUS_INVALID; } - txn_available[lastprefilledindex] = std::make_shared<CTransaction>(cmpctblock.prefilledtxn[i].tx); + txn_available[lastprefilledindex] = cmpctblock.prefilledtxn[i].tx; } prefilled_count = cmpctblock.prefilledtxn.size(); @@ -142,7 +142,7 @@ bool PartiallyDownloadedBlock::IsTxAvailable(size_t index) const { return txn_available[index] ? true : false; } -ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransaction>& vtx_missing) const { +ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) const { assert(!header.IsNull()); block = header; block.vtx.resize(txn_available.size()); @@ -154,7 +154,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< return READ_STATUS_INVALID; block.vtx[i] = vtx_missing[tx_missing_offset++]; } else - block.vtx[i] = *txn_available[i]; + block.vtx[i] = txn_available[i]; } if (vtx_missing.size() != tx_missing_offset) return READ_STATUS_INVALID; @@ -172,8 +172,8 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector< LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().ToString(), prefilled_count, mempool_count, vtx_missing.size()); if (vtx_missing.size() < 5) { - for(const CTransaction& tx : vtx_missing) - LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", header.GetHash().ToString(), tx.GetHash().ToString()); + for (const auto& tx : vtx_missing) + LogPrint("cmpctblock", "Reconstructed block %s required tx %s\n", header.GetHash().ToString(), tx->GetHash().ToString()); } return READ_STATUS_OK; diff --git a/src/blockencodings.h b/src/blockencodings.h index 1f9491867a..27baf1f8f8 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -14,9 +14,9 @@ class CTxMemPool; // Dumb helper to handle CTransaction compression at serialize-time struct TransactionCompressor { private: - CTransaction& tx; + CTransactionRef& tx; public: - TransactionCompressor(CTransaction& txIn) : tx(txIn) {} + TransactionCompressor(CTransactionRef& txIn) : tx(txIn) {} ADD_SERIALIZE_METHODS; @@ -72,7 +72,7 @@ class BlockTransactions { public: // A BlockTransactions message uint256 blockhash; - std::vector<CTransaction> txn; + std::vector<CTransactionRef> txn; BlockTransactions() {} BlockTransactions(const BlockTransactionsRequest& req) : @@ -104,7 +104,7 @@ struct PrefilledTransaction { // Used as an offset since last prefilled tx in CBlockHeaderAndShortTxIDs, // as a proper transaction-in-block-index in PartiallyDownloadedBlock uint16_t index; - CTransaction tx; + CTransactionRef tx; ADD_SERIALIZE_METHODS; @@ -193,7 +193,7 @@ public: class PartiallyDownloadedBlock { protected: - std::vector<std::shared_ptr<const CTransaction> > txn_available; + std::vector<CTransactionRef> txn_available; size_t prefilled_count = 0, mempool_count = 0; CTxMemPool* pool; public: @@ -202,7 +202,7 @@ public: ReadStatus InitData(const CBlockHeaderAndShortTxIDs& cmpctblock); bool IsTxAvailable(size_t index) const; - ReadStatus FillBlock(CBlock& block, const std::vector<CTransaction>& vtx_missing) const; + ReadStatus FillBlock(CBlock& block, const std::vector<CTransactionRef>& vtx_missing) const; }; #endif diff --git a/src/chainparams.cpp b/src/chainparams.cpp index a57ab632e4..3b3c0a5d3e 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -31,7 +31,7 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi genesis.nBits = nBits; genesis.nNonce = nNonce; genesis.nVersion = nVersion; - genesis.vtx.push_back(txNew); + genesis.vtx.push_back(MakeTransactionRef(std::move(txNew))); genesis.hashPrevBlock.SetNull(); genesis.hashMerkleRoot = BlockMerkleRoot(genesis); return genesis; diff --git a/src/consensus/merkle.cpp b/src/consensus/merkle.cpp index 35f7d2e05a..6fa96ddf45 100644 --- a/src/consensus/merkle.cpp +++ b/src/consensus/merkle.cpp @@ -160,7 +160,7 @@ uint256 BlockMerkleRoot(const CBlock& block, bool* mutated) std::vector<uint256> leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetHash(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleRoot(leaves, mutated); } @@ -171,7 +171,7 @@ uint256 BlockWitnessMerkleRoot(const CBlock& block, bool* mutated) leaves.resize(block.vtx.size()); leaves[0].SetNull(); // The witness hash of the coinbase is 0. for (size_t s = 1; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetWitnessHash(); + leaves[s] = block.vtx[s]->GetWitnessHash(); } return ComputeMerkleRoot(leaves, mutated); } @@ -181,7 +181,7 @@ std::vector<uint256> BlockMerkleBranch(const CBlock& block, uint32_t position) std::vector<uint256> leaves; leaves.resize(block.vtx.size()); for (size_t s = 0; s < block.vtx.size(); s++) { - leaves[s] = block.vtx[s].GetHash(); + leaves[s] = block.vtx[s]->GetHash(); } return ComputeMerkleBranch(leaves, position); } diff --git a/src/core_memusage.h b/src/core_memusage.h index b8e0f08bbf..0dcc24c40c 100644 --- a/src/core_memusage.h +++ b/src/core_memusage.h @@ -69,8 +69,8 @@ static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) { static inline size_t RecursiveDynamicUsage(const CBlock& block) { size_t mem = memusage::DynamicUsage(block.vtx); - for (std::vector<CTransaction>::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) { - mem += RecursiveDynamicUsage(*it); + for (const auto& tx : block.vtx) { + mem += memusage::DynamicUsage(tx) + RecursiveDynamicUsage(*tx); } return mem; } diff --git a/src/init.cpp b/src/init.cpp index 8c93d34268..ca5437fb91 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -601,6 +601,8 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) { const CChainParams& chainparams = Params(); RenameThread("bitcoin-loadblk"); + + { CImportingNow imp; // -reindex @@ -660,7 +662,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles) LogPrintf("Stopping after block import\n"); StartShutdown(); } - + } // End scope of CImportingNow LoadMempool(); } diff --git a/src/main.cpp b/src/main.cpp index e868e3c5f9..4293a6bebf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -233,7 +233,7 @@ namespace { int nPeersWithValidatedDownloads = 0; /** Relay map, protected by cs_main. */ - typedef std::map<uint256, std::shared_ptr<const CTransaction>> MapRelay; + typedef std::map<uint256, CTransactionRef> MapRelay; MapRelay mapRelay; /** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */ std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration; @@ -1639,7 +1639,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P LOCK(cs_main); - std::shared_ptr<const CTransaction> ptx = mempool.get(hash); + CTransactionRef ptx = mempool.get(hash); if (ptx) { txOut = *ptx; @@ -1682,9 +1682,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P if (pindexSlow) { CBlock block; if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) { - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - if (tx.GetHash() == hash) { - txOut = tx; + for (const auto& tx : block.vtx) { + if (tx->GetHash() == hash) { + txOut = *tx; hashBlock = pindexSlow->GetBlockHash(); return true; } @@ -2223,7 +2223,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI // undo transactions in reverse order for (int i = block.vtx.size() - 1; i >= 0; i--) { - const CTransaction &tx = block.vtx[i]; + const CTransaction &tx = *(block.vtx[i]); uint256 hash = tx.GetHash(); // Check that all outputs are available and match the outputs in the block itself @@ -2417,8 +2417,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash)); if (fEnforceBIP30) { - BOOST_FOREACH(const CTransaction& tx, block.vtx) { - const CCoins* coins = view.AccessCoins(tx.GetHash()); + for (const auto& tx : block.vtx) { + const CCoins* coins = view.AccessCoins(tx->GetHash()); if (coins && !coins->IsPruned()) return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30"); @@ -2474,7 +2474,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated for (unsigned int i = 0; i < block.vtx.size(); i++) { - const CTransaction &tx = block.vtx[i]; + const CTransaction &tx = *(block.vtx[i]); nInputs += tx.vin.size(); @@ -2544,10 +2544,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); - if (block.vtx[0].GetValueOut() > blockReward) + if (block.vtx[0]->GetValueOut() > blockReward) return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", - block.vtx[0].GetValueOut(), blockReward), + block.vtx[0]->GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); if (!control.Wait()) @@ -2590,7 +2590,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Watch for changes to the previous coinbase transaction. static uint256 hashPrevBestCoinBase; GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase); - hashPrevBestCoinBase = block.vtx[0].GetHash(); + hashPrevBestCoinBase = block.vtx[0]->GetHash(); // Erase orphan transactions include or precluded by this block if (vOrphanErase.size()) { @@ -2807,7 +2807,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara if (!fBare) { // Resurrect mempool transactions from the disconnected block. std::vector<uint256> vHashUpdate; - BOOST_FOREACH(const CTransaction &tx, block.vtx) { + for (const auto& it : block.vtx) { + const CTransaction& tx = *it; // ignore validation errors in resurrected transactions CValidationState stateDummy; if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) { @@ -2828,8 +2829,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara UpdateTip(pindexDelete->pprev, chainparams); // Let wallets know transactions went from 1-confirmed to // 0-confirmed or conflicted: - BOOST_FOREACH(const CTransaction &tx, block.vtx) { - GetMainSignals().SyncTransaction(tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); + for (const auto& tx : block.vtx) { + GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); } return true; } @@ -2844,7 +2845,7 @@ static int64_t nTimePostConnect = 0; * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. */ -bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<std::shared_ptr<const CTransaction>> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>> &txChanged) +bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<CTransactionRef> &txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>> &txChanged) { assert(pindexNew->pprev == chainActive.Tip()); // Read block from disk. @@ -2884,7 +2885,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, // Update chainActive & related variables. UpdateTip(pindexNew, chainparams); - for(unsigned int i=0; i < pblock->vtx.size(); i++) + for (unsigned int i=0; i < pblock->vtx.size(); i++) txChanged.emplace_back(pblock->vtx[i], pindexNew, i); int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1; @@ -2967,7 +2968,7 @@ static void PruneBlockIndexCandidates() { * Try to make some progress towards making pindexMostWork the active block. * pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork. */ -static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<std::shared_ptr<const CTransaction>>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>>& txChanged) +static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<CTransactionRef>& txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>>& txChanged) { AssertLockHeld(cs_main); const CBlockIndex *pindexOldTip = chainActive.Tip(); @@ -3068,7 +3069,7 @@ static void NotifyHeaderTip() { bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) { CBlockIndex *pindexMostWork = NULL; CBlockIndex *pindexNewTip = NULL; - std::vector<std::tuple<CTransaction,CBlockIndex*,int>> txChanged; + std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>> txChanged; if (pblock) txChanged.reserve(pblock->vtx.size()); do { @@ -3078,7 +3079,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, break; const CBlockIndex *pindexFork; - std::vector<std::shared_ptr<const CTransaction>> txConflicted; + std::vector<CTransactionRef> txConflicted; bool fInitialDownload; { LOCK(cs_main); @@ -3109,13 +3110,13 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, // throw all transactions though the signal-interface // while _not_ holding the cs_main lock - for(std::shared_ptr<const CTransaction> tx : txConflicted) + for (const auto& tx : txConflicted) { GetMainSignals().SyncTransaction(*tx, pindexNewTip, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK); } // ... and about transactions that got confirmed: - for(unsigned int i = 0; i < txChanged.size(); i++) - GetMainSignals().SyncTransaction(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i])); + for (unsigned int i = 0; i < txChanged.size(); i++) + GetMainSignals().SyncTransaction(*std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i])); // Notify external listeners about the new tip. GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload); @@ -3454,22 +3455,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); // First transaction must be coinbase, the rest must not be - if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) + if (block.vtx.empty() || !block.vtx[0]->IsCoinBase()) return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase"); for (unsigned int i = 1; i < block.vtx.size(); i++) - if (block.vtx[i].IsCoinBase()) + if (block.vtx[i]->IsCoinBase()) return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase"); // Check transactions for (const auto& tx : block.vtx) - if (!CheckTransaction(tx, state, false)) + if (!CheckTransaction(*tx, state, false)) return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), - strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage())); + strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage())); unsigned int nSigOps = 0; for (const auto& tx : block.vtx) { - nSigOps += GetLegacySigOpCount(tx); + nSigOps += GetLegacySigOpCount(*tx); } if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST) return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount"); @@ -3505,8 +3506,8 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa static int GetWitnessCommitmentIndex(const CBlock& block) { int commitpos = -1; - for (size_t o = 0; o < block.vtx[0].vout.size(); o++) { - if (block.vtx[0].vout[o].scriptPubKey.size() >= 38 && block.vtx[0].vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0].vout[o].scriptPubKey[1] == 0x24 && block.vtx[0].vout[o].scriptPubKey[2] == 0xaa && block.vtx[0].vout[o].scriptPubKey[3] == 0x21 && block.vtx[0].vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0].vout[o].scriptPubKey[5] == 0xed) { + for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) { + if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa && block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0]->vout[o].scriptPubKey[5] == 0xed) { commitpos = o; } } @@ -3517,10 +3518,12 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr { int commitpos = GetWitnessCommitmentIndex(block); static const std::vector<unsigned char> nonce(32, 0x00); - if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0].wit.IsEmpty()) { - block.vtx[0].wit.vtxinwit.resize(1); - block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.resize(1); - block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0] = nonce; + if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0]->wit.IsEmpty()) { + CMutableTransaction tx(*block.vtx[0]); + tx.wit.vtxinwit.resize(1); + tx.wit.vtxinwit[0].scriptWitness.stack.resize(1); + tx.wit.vtxinwit[0].scriptWitness.stack[0] = nonce; + block.vtx[0] = MakeTransactionRef(std::move(tx)); } } @@ -3530,7 +3533,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc int commitpos = GetWitnessCommitmentIndex(block); bool fHaveWitness = false; for (size_t t = 1; t < block.vtx.size(); t++) { - if (!block.vtx[t].wit.IsNull()) { + if (!block.vtx[t]->wit.IsNull()) { fHaveWitness = true; break; } @@ -3551,8 +3554,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc out.scriptPubKey[5] = 0xed; memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32); commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end()); - const_cast<std::vector<CTxOut>*>(&block.vtx[0].vout)->push_back(out); - block.vtx[0].UpdateHash(); + const_cast<std::vector<CTxOut>*>(&block.vtx[0]->vout)->push_back(out); + block.vtx[0]->UpdateHash(); } } UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams); @@ -3601,7 +3604,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co // Check that all transactions are finalized for (const auto& tx : block.vtx) { - if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { + if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) { return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction"); } } @@ -3610,8 +3613,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co if (nHeight >= consensusParams.BIP34Height) { CScript expect = CScript() << nHeight; - if (block.vtx[0].vin[0].scriptSig.size() < expect.size() || - !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) { + if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || + !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) { return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase"); } } @@ -3633,11 +3636,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co // The malleation check is ignored; as the transaction tree itself // already does not permit it, it is impossible to trigger in the // witness tree. - if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) { + if (block.vtx[0]->wit.vtxinwit.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) { return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__)); } - CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); - if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) { + CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin()); + if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) { return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__)); } fHaveWitness = true; @@ -3647,7 +3650,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co // No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam if (!fHaveWitness) { for (size_t i = 0; i < block.vtx.size(); i++) { - if (!block.vtx[i].wit.IsNull()) { + if (!block.vtx[i]->wit.IsNull()) { return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__)); } } @@ -3788,26 +3791,26 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha return true; } -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid) +bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool *fNewBlock) { { LOCK(cs_main); // Store to disk CBlockIndex *pindex = NULL; - bool fNewBlock = false; - bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock); - if (pindex && pfrom) { - mapBlockSource[pindex->GetBlockHash()] = std::make_pair(pfrom->GetId(), fMayBanPeerIfInvalid); - if (fNewBlock) pfrom->nLastBlockTime = GetTime(); - } + if (fNewBlock) *fNewBlock = false; + CValidationState state; + bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, fNewBlock); CheckBlockIndex(chainparams.GetConsensus()); - if (!ret) + if (!ret) { + GetMainSignals().BlockChecked(*pblock, state); return error("%s: AcceptBlock FAILED", __func__); + } } NotifyHeaderTip(); + CValidationState state; // Only used to report errors, not invalidity - ignore it if (!ActivateBestChain(state, chainparams, pblock)) return error("%s: ActivateBestChain failed", __func__); @@ -4953,7 +4956,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam // however we MUST always provide at least what the remote peer needs typedef std::pair<unsigned int, uint256> PairType; BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn) - connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]); + connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]); } // else // no response @@ -5367,28 +5370,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, if (inv.type == MSG_BLOCK) { UpdateBlockAvailability(pfrom->GetId(), inv.hash); if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) { - // First request the headers preceding the announced block. In the normal fully-synced - // case where a new block is announced that succeeds the current tip (no reorganization), - // there are no such headers. - // Secondly, and only when we are close to being synced, we request the announced block directly, - // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the - // time the block arrives, the header chain leading up to it is already validated. Not - // doing this will result in the received block being rejected as an orphan in case it is - // not a direct successor. + // We used to request the full block here, but since headers-announcements are now the + // primary method of announcement on the network, and since, in the case that a node + // fell back to inv we probably have a reorg which we should get the headers for first, + // we now only provide a getheaders response here. When we receive the headers, we will + // then ask for the blocks we need. connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash); - CNodeState *nodestate = State(pfrom->GetId()); - if (CanDirectFetch(chainparams.GetConsensus()) && - nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER && - (!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) { - inv.type |= nFetchFlags; - if (nodestate->fSupportsDesiredCmpctVersion) - vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash)); - else - vToFetch.push_back(inv); - // Mark block as in flight already, even though the actual "getdata" message only goes out - // later (within the same cs_main lock, though). - MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus()); - } LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id); } } @@ -5503,10 +5490,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // expensive disk reads, because it will require the peer to // actually receive all the data read from disk over the network. LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH); - CInv vInv; - vInv.type = State(pfrom->GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK; - vInv.hash = req.blockhash; - pfrom->vRecvGetData.push_back(vInv); + CInv inv; + inv.type = State(pfrom->GetId())->fWantsCmpctWitness ? MSG_WITNESS_BLOCK : MSG_BLOCK; + inv.hash = req.blockhash; + pfrom->vRecvGetData.push_back(inv); ProcessGetData(pfrom, chainparams.GetConsensus(), connman); return true; } @@ -5927,22 +5914,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // updated, reject messages go out, etc. MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer fBlockRead = true; + // mapBlockSource is only used for sending reject messages and DoS scores, + // so the race between here and cs_main in ProcessNewBlock is fine. + // BIP 152 permits peers to relay compact blocks after validating + // the header only; we should not punish peers if the block turns + // out to be invalid. + mapBlockSource.emplace(resp.blockhash, std::make_pair(pfrom->GetId(), false)); } } // Don't hold cs_main when we call into ProcessNewBlock if (fBlockRead) { - CValidationState state; + bool fNewBlock = false; // Since we requested this block (it was in mapBlocksInFlight), force it to be processed, // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc) - // BIP 152 permits peers to relay compact blocks after validating - // the header only; we should not punish peers if the block turns - // out to be invalid. - ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL, false); - int nDoS; - if (state.IsInvalid(nDoS)) { - assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash()); - } + ProcessNewBlock(chainparams, &block, true, NULL, &fNewBlock); + if (fNewBlock) + pfrom->nLastBlockTime = GetTime(); } } @@ -6100,30 +6086,25 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, LogPrint("net", "received block %s peer=%d\n", block.GetHash().ToString(), pfrom->id); - CValidationState state; // Process all blocks from whitelisted peers, even if not requested, // unless we're still syncing with the network. // Such an unrequested block may still be processed, subject to the // conditions in AcceptBlock(). bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload(); + const uint256 hash(block.GetHash()); { LOCK(cs_main); // Also always process if we requested the block explicitly, as we may // need it even though it is not a candidate for a new best tip. - forceProcessing |= MarkBlockAsReceived(block.GetHash()); - } - ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, true); - int nDoS; - if (state.IsInvalid(nDoS)) { - assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes - connman.PushMessage(pfrom, NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), - state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash()); - if (nDoS > 0) { - LOCK(cs_main); - Misbehaving(pfrom->GetId(), nDoS); - } + forceProcessing |= MarkBlockAsReceived(hash); + // mapBlockSource is only used for sending reject messages and DoS scores, + // so the race between here and cs_main in ProcessNewBlock is fine. + mapBlockSource.emplace(hash, std::make_pair(pfrom->GetId(), true)); } - + bool fNewBlock = false; + ProcessNewBlock(chainparams, &block, forceProcessing, NULL, &fNewBlock); + if (fNewBlock) + pfrom->nLastBlockTime = GetTime(); } @@ -6970,7 +6951,7 @@ bool SendMessages(CNode* pto, CConnman& connman) // Message: feefilter // // We don't want white listed peers to filter txs to us if we have -whitelistforcerelay - if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && + if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) && !(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) { CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK(); int64_t timeNow = GetTimeMicros(); diff --git a/src/main.h b/src/main.h index 21829b6c25..48fc3306f9 100644 --- a/src/main.h +++ b/src/main.h @@ -125,7 +125,7 @@ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000; /** Additional block download timeout per parallel downloading peer (i.e. 5 min) */ static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000; -static const unsigned int DEFAULT_LIMITFREERELAY = 15; +static const unsigned int DEFAULT_LIMITFREERELAY = 0; static const bool DEFAULT_RELAYPRIORITY = true; static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60; @@ -215,15 +215,21 @@ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; * 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! + * + * If you want to *possibly* get feedback on whether pblock is valid, you must + * install a CValidationInterface (see validationinterface.h) - this will have + * its BlockChecked method called whenever *any* block completes validation. + * + * Note that we guarantee that either the proof-of-work is valid on pblock, or + * (and possibly also) BlockChecked will have been called. * - * @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 reorganization; 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[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers. * @param[out] dbp The already known disk position of pblock, or NULL if not yet stored. + * @param[out] fNewBlock A boolean which is set to indicate if the block was first received via this call * @return True if state.IsValid() */ -bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid); +bool ProcessNewBlock(const CChainParams& chainparams, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool* fNewBlock); /** Check whether enough disk space is available for an incoming block */ bool CheckDiskSpace(uint64_t nAdditionalBytes = 0); /** Open a block file (blk?????.dat) */ diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp index 31332526a9..882717ac56 100644 --- a/src/merkleblock.cpp +++ b/src/merkleblock.cpp @@ -23,8 +23,8 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, CBloomFilter& filter) for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256& hash = block.vtx[i].GetHash(); - if (filter.IsRelevantAndUpdate(block.vtx[i])) + const uint256& hash = block.vtx[i]->GetHash(); + if (filter.IsRelevantAndUpdate(*block.vtx[i])) { vMatch.push_back(true); vMatchedTxn.push_back(make_pair(i, hash)); @@ -49,7 +49,7 @@ CMerkleBlock::CMerkleBlock(const CBlock& block, const std::set<uint256>& txids) for (unsigned int i = 0; i < block.vtx.size(); i++) { - const uint256& hash = block.vtx[i].GetHash(); + const uint256& hash = block.vtx[i]->GetHash(); if (txids.count(hash)) vMatch.push_back(true); else diff --git a/src/miner.cpp b/src/miner.cpp index ebf2f21ffd..c40b12cd8e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -134,7 +134,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc pblock = &pblocktemplate->block; // pointer for convenience // Add dummy coinbase tx as first transaction - pblock->vtx.push_back(CTransaction()); + pblock->vtx.emplace_back(); pblocktemplate->vTxFees.push_back(-1); // updated at end pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end @@ -169,7 +169,6 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; nLastBlockWeight = nBlockWeight; - LogPrintf("CreateNewBlock(): total size %u txs: %u fees: %ld sigops %d\n", nBlockSize, nBlockTx, nFees, nBlockSigOpsCost); // Create coinbase transaction. CMutableTransaction coinbaseTx; @@ -179,16 +178,19 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; - pblock->vtx[0] = coinbaseTx; + pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus()); pblocktemplate->vTxFees[0] = -nFees; + uint64_t nSerializeSize = GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION); + LogPrintf("CreateNewBlock(): total size: %u block weight: %u txs: %u fees: %ld sigops %d\n", nSerializeSize, GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost); + // Fill in header pblock->hashPrevBlock = pindexPrev->GetBlockHash(); UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus()); pblock->nNonce = 0; - pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(pblock->vtx[0]); + pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); CValidationState state; if (!TestBlockValidity(state, chainparams, *pblock, pindexPrev, false, false)) { @@ -310,7 +312,7 @@ bool BlockAssembler::TestForBlock(CTxMemPool::txiter iter) void BlockAssembler::AddToBlock(CTxMemPool::txiter iter) { - pblock->vtx.push_back(iter->GetTx()); + pblock->vtx.emplace_back(iter->GetSharedTx()); pblocktemplate->vTxFees.push_back(iter->GetFee()); pblocktemplate->vTxSigOpsCost.push_back(iter->GetSigOpCost()); if (fNeedSizeAccounting) { @@ -599,10 +601,10 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned } ++nExtraNonce; unsigned int nHeight = pindexPrev->nHeight+1; // Height first in coinbase required for block.version=2 - CMutableTransaction txCoinbase(pblock->vtx[0]); + CMutableTransaction txCoinbase(*pblock->vtx[0]); txCoinbase.vin[0].scriptSig = (CScript() << nHeight << CScriptNum(nExtraNonce)) + COINBASE_FLAGS; assert(txCoinbase.vin[0].scriptSig.size() <= 100); - pblock->vtx[0] = txCoinbase; + pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); } @@ -403,7 +403,7 @@ private: unsigned int nReceiveFloodSize; std::vector<ListenSocket> vhListenSocket; - bool fNetworkActive; + std::atomic<bool> fNetworkActive; banmap_t setBanned; CCriticalSection cs_setBanned; bool setBannedIsDirty; diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index a3eee474ab..3ad1ff7bae 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -66,7 +66,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions - // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. + // to MAX_STANDARD_TX_WEIGHT mitigates CPU exhaustion attacks. unsigned int sz = GetTransactionWeight(tx); if (sz >= MAX_STANDARD_TX_WEIGHT) { reason = "tx-size"; diff --git a/src/primitives/block.cpp b/src/primitives/block.cpp index 0e6ab4dd71..95bd2211f9 100644 --- a/src/primitives/block.cpp +++ b/src/primitives/block.cpp @@ -27,7 +27,7 @@ std::string CBlock::ToString() const vtx.size()); for (unsigned int i = 0; i < vtx.size(); i++) { - s << " " << vtx[i].ToString() << "\n"; + s << " " << vtx[i]->ToString() << "\n"; } return s.str(); } diff --git a/src/primitives/block.h b/src/primitives/block.h index d148aec1e0..b037fc839c 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -73,7 +73,7 @@ class CBlock : public CBlockHeader { public: // network and disk - std::vector<CTransaction> vtx; + std::vector<CTransactionRef> vtx; // memory only mutable bool fChecked; diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 7acdac17f2..91f4d29488 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -78,6 +78,10 @@ CTransaction::CTransaction(const CMutableTransaction &tx) : nVersion(tx.nVersion UpdateHash(); } +CTransaction::CTransaction(CMutableTransaction &&tx) : nVersion(tx.nVersion), vin(std::move(tx.vin)), vout(std::move(tx.vout)), wit(std::move(tx.wit)), nLockTime(tx.nLockTime) { + UpdateHash(); +} + CTransaction& CTransaction::operator=(const CTransaction &tx) { *const_cast<int*>(&nVersion) = tx.nVersion; *const_cast<std::vector<CTxIn>*>(&vin) = tx.vin; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 1d176e5d8c..0fa85a1519 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -379,6 +379,7 @@ public: /** Convert a CMutableTransaction into a CTransaction. */ CTransaction(const CMutableTransaction &tx); + CTransaction(CMutableTransaction &&tx); CTransaction& operator=(const CTransaction& tx); @@ -392,6 +393,9 @@ public: } } + template <typename Stream> + CTransaction(deserialize_type, Stream& s) : CTransaction(CMutableTransaction(deserialize, s)) {} + bool IsNull() const { return vin.empty() && vout.empty(); } @@ -460,12 +464,23 @@ struct CMutableTransaction SerializeTransaction(*this, s, ser_action); } + template <typename Stream> + CMutableTransaction(deserialize_type, Stream& s) { + Unserialize(s); + } + /** Compute the hash of this CMutableTransaction. This is computed on the * fly, as opposed to GetHash() in CTransaction, which uses a cached result. */ uint256 GetHash() const; }; +typedef std::shared_ptr<const CTransaction> CTransactionRef; +static inline CTransactionRef MakeTransactionRef() { return std::make_shared<const CTransaction>(); } +template <typename Tx> static inline CTransactionRef MakeTransactionRef(Tx&& txIn) { return std::make_shared<const CTransaction>(std::forward<Tx>(txIn)); } +static inline CTransactionRef MakeTransactionRef(const CTransactionRef& txIn) { return txIn; } +static inline CTransactionRef MakeTransactionRef(CTransactionRef&& txIn) { return std::move(txIn); } + /** Compute the weight of a transaction, as defined by BIP 141 */ int64_t GetTransactionWeight(const CTransaction &tx); diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index b2c9a704ed..b7302e3969 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -713,13 +713,19 @@ void BitcoinGUI::updateNetworkState() default: icon = ":/icons/connect_4"; break; } + QString tooltip; + if (clientModel->getNetworkActive()) { - connectionsControl->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count)); + tooltip = tr("%n active connection(s) to Bitcoin network", "", count) + QString(".<br>") + tr("Click to disable network activity."); } else { - connectionsControl->setToolTip(tr("Network activity disabled")); + tooltip = tr("Network activity disabled.") + QString("<br>") + tr("Click to enable network activity again."); icon = ":/icons/network_disabled"; } + // Don't word-wrap this (fixed-width) tooltip + tooltip = QString("<nobr>") + tooltip + QString("</nobr>"); + connectionsControl->setToolTip(tooltip); + connectionsControl->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE)); } diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 1a1671f0ee..1010a62fc4 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -35,6 +35,13 @@ QList<CAmount> CoinControlDialog::payAmounts; CCoinControl* CoinControlDialog::coinControl = new CCoinControl(); bool CoinControlDialog::fSubtractFeeFromAmount = false; +bool CCoinControlWidgetItem::operator<(const QTreeWidgetItem &other) const { + int column = treeWidget()->sortColumn(); + if (column == CoinControlDialog::COLUMN_AMOUNT || column == CoinControlDialog::COLUMN_DATE || column == CoinControlDialog::COLUMN_CONFIRMATIONS) + return data(column, Qt::UserRole).toLongLong() < other.data(column, Qt::UserRole).toLongLong(); + return QTreeWidgetItem::operator<(other); +} + CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidget *parent) : QDialog(parent), ui(new Ui::CoinControlDialog), @@ -128,11 +135,9 @@ CoinControlDialog::CoinControlDialog(const PlatformStyle *_platformStyle, QWidge ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 110); ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transaction hash in this column, but don't show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_AMOUNT_INT64, true); // store amount int64 in this column, but don't show it - ui->treeWidget->setColumnHidden(COLUMN_DATE_INT64, true); // store date int64 in this column, but don't show it // default view is sorted by amount desc - sortView(COLUMN_AMOUNT_INT64, Qt::DescendingOrder); + sortView(COLUMN_AMOUNT, Qt::DescendingOrder); // restore list mode and sortorder as a convenience feature QSettings settings; @@ -164,15 +169,6 @@ void CoinControlDialog::setModel(WalletModel *_model) } } -// helper function str_pad -QString CoinControlDialog::strPad(QString s, int nPadLength, QString sPadding) -{ - while (s.length() < nPadLength) - s = sPadding + s; - - return s; -} - // ok button void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) { @@ -338,7 +334,7 @@ void CoinControlDialog::sortView(int column, Qt::SortOrder order) sortColumn = column; sortOrder = order; ui->treeWidget->sortItems(column, order); - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } // treeview: clicked on header @@ -346,12 +342,10 @@ void CoinControlDialog::headerSectionClicked(int logicalIndex) { if (logicalIndex == COLUMN_CHECKBOX) // click on most left column -> do nothing { - ui->treeWidget->header()->setSortIndicator(getMappedColumn(sortColumn), sortOrder); + ui->treeWidget->header()->setSortIndicator(sortColumn, sortOrder); } else { - logicalIndex = getMappedColumn(logicalIndex, false); - if (sortColumn == logicalIndex) sortOrder = ((sortOrder == Qt::AscendingOrder) ? Qt::DescendingOrder : Qt::AscendingOrder); else @@ -658,7 +652,7 @@ void CoinControlDialog::updateView() model->listCoins(mapCoins); BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) { - QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem(); + CCoinControlWidgetItem *itemWalletAddress = new CCoinControlWidgetItem(); itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); QString sWalletAddress = coins.first; QString sWalletLabel = model->getAddressTableModel()->labelForAddress(sWalletAddress); @@ -686,9 +680,9 @@ void CoinControlDialog::updateView() nSum += out.tx->vout[out.i].nValue; nChildren++; - QTreeWidgetItem *itemOutput; - if (treeMode) itemOutput = new QTreeWidgetItem(itemWalletAddress); - else itemOutput = new QTreeWidgetItem(ui->treeWidget); + CCoinControlWidgetItem *itemOutput; + if (treeMode) itemOutput = new CCoinControlWidgetItem(itemWalletAddress); + else itemOutput = new CCoinControlWidgetItem(ui->treeWidget); itemOutput->setFlags(flgCheckbox); itemOutput->setCheckState(COLUMN_CHECKBOX,Qt::Unchecked); @@ -721,14 +715,15 @@ void CoinControlDialog::updateView() // amount itemOutput->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, out.tx->vout[out.i].nValue)); - itemOutput->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(out.tx->vout[out.i].nValue), 15, " ")); // padding so that sorting works correctly + itemOutput->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)out.tx->vout[out.i].nValue)); // padding so that sorting works correctly // date itemOutput->setText(COLUMN_DATE, GUIUtil::dateTimeStr(out.tx->GetTxTime())); - itemOutput->setText(COLUMN_DATE_INT64, strPad(QString::number(out.tx->GetTxTime()), 20, " ")); + itemOutput->setData(COLUMN_DATE, Qt::UserRole, QVariant((qlonglong)out.tx->GetTxTime())); // confirmations - itemOutput->setText(COLUMN_CONFIRMATIONS, strPad(QString::number(out.nDepth), 8, " ")); + itemOutput->setText(COLUMN_CONFIRMATIONS, QString::number(out.nDepth)); + itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong)out.nDepth)); // transaction hash uint256 txhash = out.tx->GetHash(); @@ -756,7 +751,7 @@ void CoinControlDialog::updateView() { itemWalletAddress->setText(COLUMN_CHECKBOX, "(" + QString::number(nChildren) + ")"); itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); - itemWalletAddress->setText(COLUMN_AMOUNT_INT64, strPad(QString::number(nSum), 15, " ")); + itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong)nSum)); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 7d73421e3a..7c2269b1eb 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -28,6 +28,17 @@ namespace Ui { #define ASYMP_UTF8 "\xE2\x89\x88" +class CCoinControlWidgetItem : public QTreeWidgetItem +{ +public: + CCoinControlWidgetItem(QTreeWidget *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + CCoinControlWidgetItem(int type = Type) : QTreeWidgetItem(type) {} + CCoinControlWidgetItem(QTreeWidgetItem *parent, int type = Type) : QTreeWidgetItem(parent, type) {} + + bool operator<(const QTreeWidgetItem &other) const; +}; + + class CoinControlDialog : public QDialog { Q_OBJECT @@ -59,13 +70,12 @@ private: const PlatformStyle *platformStyle; - QString strPad(QString, int, QString); void sortView(int, Qt::SortOrder); void updateView(); enum { - COLUMN_CHECKBOX, + COLUMN_CHECKBOX = 0, COLUMN_AMOUNT, COLUMN_LABEL, COLUMN_ADDRESS, @@ -73,30 +83,8 @@ private: COLUMN_CONFIRMATIONS, COLUMN_TXHASH, COLUMN_VOUT_INDEX, - COLUMN_AMOUNT_INT64, - COLUMN_DATE_INT64 }; - - // some columns have a hidden column containing the value used for sorting - int getMappedColumn(int column, bool fVisibleColumn = true) - { - if (fVisibleColumn) - { - if (column == COLUMN_AMOUNT_INT64) - return COLUMN_AMOUNT; - else if (column == COLUMN_DATE_INT64) - return COLUMN_DATE; - } - else - { - if (column == COLUMN_AMOUNT) - return COLUMN_AMOUNT_INT64; - else if (column == COLUMN_DATE) - return COLUMN_DATE_INT64; - } - - return column; - } + friend class CCoinControlWidgetItem; private Q_SLOTS: void showMenu(const QPoint &); diff --git a/src/qt/res/icons/network_disabled.png b/src/qt/res/icons/network_disabled.png Binary files differindex 49f728693d..269c3cfab8 100644 --- a/src/qt/res/icons/network_disabled.png +++ b/src/qt/res/icons/network_disabled.png diff --git a/src/qt/res/src/connect-0.svg b/src/qt/res/src/connect-0.svg index 7d2afac622..0920555b96 100644 --- a/src/qt/res/src/connect-0.svg +++ b/src/qt/res/src/connect-0.svg @@ -7,8 +7,8 @@ xmlns="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 24 24" - height="24" - width="24" + height="92" + width="92" version="1.2"> <metadata id="metadata10"> diff --git a/src/qt/res/src/connect-1.svg b/src/qt/res/src/connect-1.svg index d17928c97d..25dea4cd3a 100644 --- a/src/qt/res/src/connect-1.svg +++ b/src/qt/res/src/connect-1.svg @@ -6,8 +6,8 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" - width="24" - height="24" + width="92" + height="92" viewBox="0 0 24 24" id="svg2"> <metadata diff --git a/src/qt/res/src/connect-2.svg b/src/qt/res/src/connect-2.svg index 841ca6071d..bb98333d23 100644 --- a/src/qt/res/src/connect-2.svg +++ b/src/qt/res/src/connect-2.svg @@ -6,8 +6,8 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" - width="24" - height="24" + width="92" + height="92" viewBox="0 0 24 24" id="svg2"> <metadata diff --git a/src/qt/res/src/connect-3.svg b/src/qt/res/src/connect-3.svg index b06e67daf8..a54a55ef61 100644 --- a/src/qt/res/src/connect-3.svg +++ b/src/qt/res/src/connect-3.svg @@ -7,8 +7,8 @@ xmlns="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 24 24" - height="24" - width="24" + height="92" + width="92" version="1.2"> <metadata id="metadata10"> diff --git a/src/qt/res/src/connect-4.svg b/src/qt/res/src/connect-4.svg index 0abc7955fd..b83b9f9d03 100644 --- a/src/qt/res/src/connect-4.svg +++ b/src/qt/res/src/connect-4.svg @@ -6,8 +6,8 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" - width="24" - height="24" + width="92" + height="92" viewBox="0 0 24 24" id="svg2"> <metadata diff --git a/src/qt/res/src/network_disabled.svg b/src/qt/res/src/network_disabled.svg index e95a5eb5bb..a041d77439 100644 --- a/src/qt/res/src/network_disabled.svg +++ b/src/qt/res/src/network_disabled.svg @@ -7,8 +7,8 @@ xmlns="http://www.w3.org/2000/svg" id="svg2" viewBox="0 0 24 24" - height="24" - width="24" + width="92" + height="92" version="1.2"> <metadata id="metadata10"> @@ -37,31 +37,12 @@ id="g4291"> <path id="path4293" - d="m -65.35,116.3 0,3 0.5,0 c 0.54,0 1,0.5 1,1 l 0,2.6 c -1.15,0.5 -2,1.6 -2,3 0,2 1.59,3.5 3.5,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-2.3 -1.81,-4 -4,-4 z m 1,1.2 c 1.39,0.3 2.5,1.3 2.5,2.8 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.5,-1.1 -2.5,-2.5 0,-1.1 0.69,-2 1.66,-2.3 l 0.34,-0.1 0,-3.2 c 0,-0.9 -0.67,-1.5 -1.5,-1.8 z" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> - <g - style="fill:#969696;fill-opacity:1" - id="g4295"> - <path - id="path4297" - d="m -67.35,106.1 c -1.94,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,2.2 1.79,4 4,4 l 0.5,0 0,-0.5 0,-2.5 -0.5,0 c -0.55,0 -1,-0.5 -1,-1 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.57,-3.5 -3.5,-3.5 z m 0,1 c 1.37,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,0.9 0.67,1.5 1.5,1.8 l 0,1 c -1.38,-0.3 -2.5,-1.4 -2.5,-2.8 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.12,-2.5 2.5,-2.5 z" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> - <path - id="path4299" - d="m -57.35,106.1 c -1.93,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,0.5 -0.45,1 -1,1 l -4.85,0 3.17,3 1.68,0 c 2.21,0 4,-1.8 4,-4 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.56,-3.5 -3.5,-3.5 z m 0,1 c 1.38,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,1.6 -1.35,3 -3,3 l -1.81,0 -2.04,-1 3.85,0 c 1.11,0 2,-0.9 2,-2 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.13,-2.5 2.5,-2.5 z" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> - </g> - <path - id="path4301" - d="m -69.84,116.3 c -2.19,0 -4,1.7 -4,4 l 0,2.6 c -1.14,0.6 -1.99,1.6 -1.99,3 0,2 1.6,3.5 3.51,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-0.5 0.45,-1 1,-1 l 5.01,0 -3.36,-3 z m 0,1 1.84,0 2.19,1 -4.01,0 c -1.11,0 -2,0.9 -2,2 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.51,-1.1 -2.51,-2.5 0,-1.1 0.7,-2 1.66,-2.3 l 0.33,-0.1 0,-0.4 0,-2.8 c 0,-1.7 1.33,-3 3,-3 z" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> + transform="matrix(0,-1,-1,0,-52.84,129.7464)" + d="M 20.146484 1.0097656 C 18.746484 1.0097656 17.646484 1.8597656 17.146484 3.0097656 L 14.447266 3.0097656 C 12.247266 3.0097656 10.447266 4.7997656 10.447266 7.0097656 L 10.447266 8.1425781 C 10.128283 8.0634395 9.7980674 8.0097656 9.4472656 8.0097656 L 6.8457031 8.0097656 C 6.3457031 6.8597656 5.2457031 6.0097656 3.8457031 6.0097656 C 1.8457031 6.0097656 0.34570312 7.5997656 0.34570312 9.5097656 C 0.34570312 11.419766 1.8457031 13.009766 3.8457031 13.009766 C 5.2457031 13.009766 6.3457031 12.159766 6.8457031 11.009766 L 8.9746094 11.009766 C 8.8693536 11.330059 8.8007812 11.663345 8.8007812 12.001953 C 8.8007813 12.841953 9.1402344 13.671625 9.7402344 14.265625 C 9.9479364 14.475439 10.191281 14.640988 10.447266 14.783203 L 10.447266 16.980469 C 10.447266 17.530469 9.9472656 17.980469 9.4472656 17.980469 L 6.8457031 17.980469 C 6.3457031 16.830469 5.2457031 15.980469 3.8457031 15.980469 C 1.8457031 15.980469 0.34570312 17.570469 0.34570312 19.480469 C 0.34570312 21.390469 1.8457031 22.990234 3.8457031 22.990234 C 5.2457031 22.990234 6.2457031 22.14 6.8457031 21 L 9.4472656 21 C 11.747266 21 13.447266 19.19 13.447266 17 L 13.447266 15.869141 C 13.768504 15.952624 14.100702 16.009766 14.447266 16.009766 L 17.146484 16.009766 C 17.646484 17.159766 18.746484 18.009766 20.146484 18.009766 C 22.046484 18.009766 23.646484 16.449766 23.646484 14.509766 C 23.646484 12.579766 22.046484 11.009766 20.146484 11.009766 C 18.746484 11.009766 17.646484 11.859766 17.146484 13.009766 L 15.009766 13.009766 C 15.119625 12.684735 15.189453 12.346256 15.189453 12 C 15.189453 11.16 14.849906 10.339953 14.253906 9.7519531 C 14.0189 9.51021 13.74069 9.3244522 13.447266 9.171875 L 13.447266 7.0097656 C 13.447266 6.4597656 13.947266 6.0097656 14.447266 6.0097656 L 17.146484 6.0097656 C 17.646484 7.1597656 18.746484 8.0097656 20.146484 8.0097656 C 22.046484 8.0097656 23.646484 6.4397656 23.646484 4.5097656 C 23.646484 2.5697656 22.046484 1.0097656 20.146484 1.0097656 z M 20.146484 2.0097656 C 21.446484 2.0097656 22.646484 3.1297656 22.646484 4.5097656 C 22.646484 5.8797656 21.446484 7.0097656 20.146484 7.0097656 C 19.046484 7.0097656 18.145703 6.3096094 17.845703 5.3496094 L 17.746094 5.0097656 L 14.447266 5.0097656 C 13.347266 5.0097656 12.447266 5.8997656 12.447266 7.0097656 L 12.447266 8.8476562 C 12.298996 8.8261586 12.150754 8.8027344 12 8.8027344 C 11.954455 8.8027344 11.910576 8.8144662 11.865234 8.8164062 C 11.733157 8.716719 11.592447 8.6297054 11.447266 8.546875 L 11.447266 7.0097656 C 11.447266 5.3597656 12.847266 4.0097656 14.447266 4.0097656 L 17.746094 4.0097656 L 17.845703 3.6699219 C 18.145703 2.7099219 19.046484 2.0097656 20.146484 2.0097656 z M 3.8457031 7.0097656 C 4.9457031 7.0097656 5.8464844 7.7099219 6.1464844 8.6699219 L 6.2460938 9.0097656 L 9.4472656 9.0097656 C 9.8222656 9.0097656 10.165234 9.0792969 10.474609 9.2050781 C 10.207952 9.3508551 9.9554097 9.5233651 9.7402344 9.7421875 C 9.6554755 9.8255337 9.5878282 9.9233484 9.5136719 10.015625 C 9.4909069 10.014746 9.470428 10.009766 9.4472656 10.009766 L 6.2460938 10.009766 L 6.1464844 10.349609 C 5.8464844 11.319609 4.9457031 12.009766 3.8457031 12.009766 C 2.4457031 12.009766 1.3457031 10.899766 1.3457031 9.5097656 C 1.3457031 8.1197656 2.4457031 7.0097656 3.8457031 7.0097656 z M 20.146484 12.009766 C 21.446484 12.009766 22.646484 13.139766 22.646484 14.509766 C 22.646484 15.889766 21.446484 17.009766 20.146484 17.009766 C 19.046484 17.009766 18.145703 16.309609 17.845703 15.349609 L 17.746094 15.009766 L 14.447266 15.009766 C 14.100959 15.009766 13.772729 14.94045 13.470703 14.816406 C 13.754756 14.666178 14.02454 14.485593 14.253906 14.253906 C 14.328913 14.179151 14.386367 14.091269 14.453125 14.009766 L 17.746094 14.009766 L 17.845703 13.669922 C 18.145703 12.709922 19.046484 12.009766 20.146484 12.009766 z M 11.447266 15.144531 C 11.629002 15.17624 11.813246 15.199219 12 15.199219 C 12.018544 15.199153 12.036184 15.193748 12.054688 15.193359 C 12.180437 15.288088 12.3107 15.373496 12.447266 15.453125 L 12.447266 17 C 12.447266 18.67 11.147266 20 9.4472656 20 L 6.6464844 20 L 6.2460938 20 L 6.1464844 20.330078 C 5.8464844 21.290078 4.9457031 21.990234 3.8457031 21.990234 C 2.4457031 21.990234 1.3457031 20.870469 1.3457031 19.480469 C 1.3457031 18.090469 2.4457031 16.980469 3.8457031 16.980469 C 4.9457031 16.980469 5.8464844 17.680625 6.1464844 18.640625 L 6.2460938 18.980469 L 9.4472656 18.980469 C 10.547266 18.980469 11.447266 18.090469 11.447266 16.980469 L 11.447266 15.144531 z " + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.5;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> </g> </g> </g> - <path - id="path4165" - d="m 12,8.77 c -0.84,0 -1.66,0.341 -2.254,0.937 -0.599,0.593 -0.942,1.403 -0.945,2.253 0,0.85 0.337,1.67 0.933,2.26 a 0.6001,0.6001 0 0 0 0,0 c 0.594,0.6 1.424,0.94 2.264,0.94 0.84,0 1.67,-0.34 2.26,-0.94 0.6,-0.59 0.94,-1.41 0.94,-2.26 0,-0.84 -0.34,-1.66 -0.95,-2.253 C 13.66,9.111 12.84,8.77 12,8.77 Z" - style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> </g> <path d="M 3,3 l 18,18" style="stroke-width: 3; stroke: #000000; stroke-linecap: round;" /> <path d="M 21,3 l -18,18" style="stroke-width: 3; stroke: #000000; stroke-linecap: round;" /> diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 8caea14adb..154107c0dc 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -119,16 +119,16 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool tx result.push_back(Pair("versionHex", strprintf("%08x", block.nVersion))); result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); UniValue txs(UniValue::VARR); - BOOST_FOREACH(const CTransaction&tx, block.vtx) + for(const auto& tx : block.vtx) { if(txDetails) { UniValue objTx(UniValue::VOBJ); - TxToJSON(tx, uint256(), objTx); + TxToJSON(*tx, uint256(), objTx); txs.push_back(objTx); } else - txs.push_back(tx.GetHash().GetHex()); + txs.push_back(tx->GetHash().GetHex()); } result.push_back(Pair("tx", txs)); result.push_back(Pair("time", block.GetBlockTime())); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 8824898feb..6b0e52a309 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -131,9 +131,8 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG if (pblock->nNonce == nInnerLoopCount) { continue; } - CValidationState state; - if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, false)) - throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("ProcessNewBlock: block not accepted: %s", FormatStateMessage(state))); + if (!ProcessNewBlock(Params(), pblock, true, NULL, NULL)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted"); ++nHeight; blockHashes.push_back(pblock->GetHash().GetHex()); @@ -558,7 +557,8 @@ UniValue getblocktemplate(const JSONRPCRequest& request) UniValue transactions(UniValue::VARR); map<uint256, int64_t> setTxIndex; int i = 0; - BOOST_FOREACH (CTransaction& tx, pblock->vtx) { + for (const auto& it : pblock->vtx) { + const CTransaction& tx = *it; uint256 txHash = tx.GetHash(); setTxIndex[txHash] = i++; @@ -663,7 +663,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex())); result.push_back(Pair("transactions", transactions)); result.push_back(Pair("coinbaseaux", aux)); - result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].vout[0].nValue)); + result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0]->vout[0].nValue)); result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast))); result.push_back(Pair("target", hashTarget.GetHex())); result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast()+1)); @@ -754,10 +754,9 @@ UniValue submitblock(const JSONRPCRequest& request) } } - CValidationState state; submitblock_StateCatcher sc(block.GetHash()); RegisterValidationInterface(&sc); - bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, false); + bool fAccepted = ProcessNewBlock(Params(), &block, true, NULL, NULL); UnregisterValidationInterface(&sc); if (fBlockPresent) { @@ -765,13 +764,9 @@ UniValue submitblock(const JSONRPCRequest& request) return "duplicate-inconclusive"; return "duplicate"; } - if (fAccepted) - { - if (!sc.found) - return "inconclusive"; - state = sc.state; - } - return BIP22ValidationResult(state); + if (!sc.found) + return "inconclusive"; + return BIP22ValidationResult(sc.state); } UniValue estimatefee(const JSONRPCRequest& request) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 0656a61755..370c021ea6 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -135,17 +135,17 @@ UniValue getrawtransaction(const JSONRPCRequest& request) "or there is an unspent output in the utxo for this transaction. To make it always work,\n" "you need to maintain a transaction index, using the -txindex command line option.\n" "\nReturn the raw transaction data.\n" - "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n" - "If verbose is non-zero, returns an Object with information about 'txid'.\n" + "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" + "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" - "2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n" + "2. verbose (bool, optional, default=false) If true, return a string, other return a json object\n" - "\nResult (if verbose is not set or set to 0):\n" + "\nResult (if verbose is not set or set to false):\n" "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" - "\nResult (if verbose > 0):\n" + "\nResult (if verbose is set to true):\n" "{\n" " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" @@ -192,17 +192,31 @@ UniValue getrawtransaction(const JSONRPCRequest& request) "\nExamples:\n" + HelpExampleCli("getrawtransaction", "\"mytxid\"") - + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") - + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") + + HelpExampleCli("getrawtransaction", "\"mytxid\" true") + + HelpExampleRpc("getrawtransaction", "\"mytxid\", true") ); LOCK(cs_main); uint256 hash = ParseHashV(request.params[0], "parameter 1"); + // Accept either a bool (true) or a num (>=1) to indicate verbose output. bool fVerbose = false; - if (request.params.size() > 1) - fVerbose = (request.params[1].get_int() != 0); + if (request.params.size() > 1) { + if (request.params[1].isNum()) { + if (request.params[1].get_int() != 0) { + fVerbose = true; + } + } + else if(request.params[1].isBool()) { + if(request.params[1].isTrue()) { + fVerbose = true; + } + } + else { + throw JSONRPCError(RPC_TYPE_ERROR, "Invalid type provided. Verbose parameter must be a boolean."); + } + } CTransaction tx; uint256 hashBlock; @@ -288,8 +302,8 @@ UniValue gettxoutproof(const JSONRPCRequest& request) throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); unsigned int ntxFound = 0; - BOOST_FOREACH(const CTransaction&tx, block.vtx) - if (setTxids.count(tx.GetHash())) + for (const auto& tx : block.vtx) + if (setTxids.count(tx->GetHash())) ntxFound++; if (ntxFound != setTxids.size()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block"); diff --git a/src/scheduler.cpp b/src/scheduler.cpp index 52777b61f9..27c03f154c 100644 --- a/src/scheduler.cpp +++ b/src/scheduler.cpp @@ -54,9 +54,10 @@ void CScheduler::serviceQueue() #else // Some boost versions have a conflicting overload of wait_until that returns void. // Explicitly use a template here to avoid hitting that overload. - while (!shouldStop() && !taskQueue.empty() && - newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) { - // Keep waiting until timeout + while (!shouldStop() && !taskQueue.empty()) { + boost::chrono::system_clock::time_point timeToWaitFor = taskQueue.begin()->first; + if (newTaskScheduled.wait_until<>(lock, timeToWaitFor) == boost::cv_status::timeout) + break; // Exit loop after timeout, it means we reached the time of the event } #endif // If there are multiple threads, the queue can empty while we're waiting (another diff --git a/src/serialize.h b/src/serialize.h index 91864e1b64..e28ca548c0 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -13,6 +13,7 @@ #include <ios> #include <limits> #include <map> +#include <memory> #include <set> #include <stdint.h> #include <string> @@ -25,6 +26,20 @@ static const unsigned int MAX_SIZE = 0x02000000; /** + * Dummy data type to identify deserializing constructors. + * + * By convention, a constructor of a type T with signature + * + * template <typename Stream> T::T(deserialize_type, Stream& s) + * + * is a deserializing constructor, which builds the type by + * deserializing it from s. If T contains const fields, this + * is likely the only way to do so. + */ +struct deserialize_type {}; +constexpr deserialize_type deserialize {}; + +/** * Used to bypass the rule against non-const reference to temporary * where it makes sense with wrappers such as CFlatData or CTxDB */ @@ -521,7 +536,17 @@ template<typename Stream, typename K, typename T, typename Pred, typename A> voi template<typename Stream, typename K, typename Pred, typename A> void Serialize(Stream& os, const std::set<K, Pred, A>& m); template<typename Stream, typename K, typename Pred, typename A> void Unserialize(Stream& is, std::set<K, Pred, A>& m); +/** + * shared_ptr + */ +template<typename Stream, typename T> void Serialize(Stream& os, const std::shared_ptr<const T>& p); +template<typename Stream, typename T> void Unserialize(Stream& os, std::shared_ptr<const T>& p); +/** + * unique_ptr + */ +template<typename Stream, typename T> void Serialize(Stream& os, const std::unique_ptr<const T>& p); +template<typename Stream, typename T> void Unserialize(Stream& os, std::unique_ptr<const T>& p); @@ -776,6 +801,40 @@ void Unserialize(Stream& is, std::set<K, Pred, A>& m) /** + * unique_ptr + */ +template<typename Stream, typename T> void +Serialize(Stream& os, const std::unique_ptr<const T>& p) +{ + Serialize(os, *p); +} + +template<typename Stream, typename T> +void Unserialize(Stream& is, std::unique_ptr<const T>& p) +{ + p.reset(new T(deserialize, is)); +} + + + +/** + * shared_ptr + */ +template<typename Stream, typename T> void +Serialize(Stream& os, const std::shared_ptr<const T>& p) +{ + Serialize(os, *p); +} + +template<typename Stream, typename T> +void Unserialize(Stream& is, std::shared_ptr<const T>& p) +{ + p = std::make_shared<const T>(deserialize, is); +} + + + +/** * Support for ADD_SERIALIZE_METHODS and READWRITE macro */ struct CSerActionSerialize diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 0ed5d62ef6..b013cda6d7 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -26,21 +26,21 @@ static CBlock BuildBlockTestCase() { tx.vout[0].nValue = 42; block.vtx.resize(3); - block.vtx[0] = tx; + block.vtx[0] = MakeTransactionRef(tx); block.nVersion = 42; block.hashPrevBlock = GetRandHash(); block.nBits = 0x207fffff; tx.vin[0].prevout.hash = GetRandHash(); tx.vin[0].prevout.n = 0; - block.vtx[1] = tx; + block.vtx[1] = MakeTransactionRef(tx); tx.vin.resize(10); for (size_t i = 0; i < tx.vin.size(); i++) { tx.vin[i].prevout.hash = GetRandHash(); tx.vin[i].prevout.n = 0; } - block.vtx[2] = tx; + block.vtx[2] = MakeTransactionRef(tx); bool mutated; block.hashMerkleRoot = BlockMerkleRoot(block, &mutated); @@ -59,8 +59,8 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2])); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); // Do a simple ShortTxIDs RT { @@ -78,14 +78,14 @@ BOOST_AUTO_TEST_CASE(SimpleRoundTripTest) BOOST_CHECK(!partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); - std::vector<std::shared_ptr<const CTransaction>> removed; - pool.removeRecursive(block.vtx[2], &removed); + std::vector<CTransactionRef> removed; + pool.removeRecursive(*block.vtx[2], &removed); BOOST_CHECK_EQUAL(removed.size(), 1); CBlock block2; - std::vector<CTransaction> vtx_missing; + std::vector<CTransactionRef> vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions vtx_missing.push_back(block.vtx[2]); // Wrong transaction @@ -152,8 +152,10 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[2].GetHash(), entry.FromTx(block.vtx[2])); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + pool.addUnchecked(block.vtx[2]->GetHash(), entry.FromTx(*block.vtx[2])); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + + uint256 txhash; // Test with pre-forwarding tx 1, but not coinbase { @@ -161,8 +163,8 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) shortIDs.prefilledtxn.resize(1); shortIDs.prefilledtxn[0] = {1, block.vtx[1]}; shortIDs.shorttxids.resize(2); - shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0].GetHash()); - shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2].GetHash()); + shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[0]->GetHash()); + shortIDs.shorttxids[1] = shortIDs.GetShortID(block.vtx[2]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; @@ -176,10 +178,10 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) BOOST_CHECK( partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; - std::vector<CTransaction> vtx_missing; + std::vector<CTransactionRef> vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_INVALID); // No transactions vtx_missing.push_back(block.vtx[1]); // Wrong transaction @@ -194,9 +196,13 @@ BOOST_AUTO_TEST_CASE(NonCoinbasePreforwardRTTest) BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block3, &mutated).ToString()); BOOST_CHECK(!mutated); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); + txhash = block.vtx[2]->GetHash(); + block.vtx.clear(); + block2.vtx.clear(); + block3.vtx.clear(); + BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); } - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[2].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); } BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) @@ -205,8 +211,10 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) TestMemPoolEntryHelper entry; CBlock block(BuildBlockTestCase()); - pool.addUnchecked(block.vtx[1].GetHash(), entry.FromTx(block.vtx[1])); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + pool.addUnchecked(block.vtx[1]->GetHash(), entry.FromTx(*block.vtx[1])); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + + uint256 txhash; // Test with pre-forwarding coinbase + tx 2 with tx 1 in mempool { @@ -215,7 +223,7 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) shortIDs.prefilledtxn[0] = {0, block.vtx[0]}; shortIDs.prefilledtxn[1] = {1, block.vtx[2]}; // id == 1 as it is 1 after index 1 shortIDs.shorttxids.resize(1); - shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1].GetHash()); + shortIDs.shorttxids[0] = shortIDs.GetShortID(block.vtx[1]->GetHash()); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); stream << shortIDs; @@ -229,19 +237,22 @@ BOOST_AUTO_TEST_CASE(SufficientPreforwardRTTest) BOOST_CHECK( partialBlock.IsTxAvailable(1)); BOOST_CHECK( partialBlock.IsTxAvailable(2)); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); + BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1]->GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); CBlock block2; - std::vector<CTransaction> vtx_missing; + std::vector<CTransactionRef> vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); bool mutated; BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); BOOST_CHECK(!mutated); - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); + txhash = block.vtx[1]->GetHash(); + block.vtx.clear(); + block2.vtx.clear(); + BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 1); } - BOOST_CHECK_EQUAL(pool.mapTx.find(block.vtx[1].GetHash())->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); + BOOST_CHECK_EQUAL(pool.mapTx.find(txhash)->GetSharedTx().use_count(), SHARED_TX_OFFSET + 0); } BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) @@ -255,7 +266,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) CBlock block; block.vtx.resize(1); - block.vtx[0] = coinbase; + block.vtx[0] = MakeTransactionRef(std::move(coinbase)); block.nVersion = 42; block.hashPrevBlock = GetRandHash(); block.nBits = 0x207fffff; @@ -280,7 +291,7 @@ BOOST_AUTO_TEST_CASE(EmptyBlockRoundTripTest) BOOST_CHECK(partialBlock.IsTxAvailable(0)); CBlock block2; - std::vector<CTransaction> vtx_missing; + std::vector<CTransactionRef> vtx_missing; BOOST_CHECK(partialBlock.FillBlock(block2, vtx_missing) == READ_STATUS_OK); BOOST_CHECK_EQUAL(block.GetHash().ToString(), block2.GetHash().ToString()); BOOST_CHECK_EQUAL(block.hashMerkleRoot.ToString(), BlockMerkleRoot(block2, &mutated).ToString()); diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json index de95044597..98be75919b 100644 --- a/src/test/data/bitcoin-util-test.json +++ b/src/test/data/bitcoin-util-test.json @@ -103,6 +103,16 @@ "description": "Creates a new transaction with a single empty output script (output in json)" }, { "exec": "./bitcoin-tx", + "args": ["01000000000100000000000000000000000000"], + "output_cmp": "txcreate2.hex", + "description": "Parses a transation with no inputs and a single output script" + }, + { "exec": "./bitcoin-tx", + "args": ["-json", "01000000000100000000000000000000000000"], + "output_cmp": "txcreate2.json", + "description": "Parses a transation with no inputs and a single output script (output in json)" + }, + { "exec": "./bitcoin-tx", "args": ["-create", "in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0", diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp index a73dbe725c..1faf8b6aeb 100644 --- a/src/test/mempool_tests.cpp +++ b/src/test/mempool_tests.cpp @@ -55,7 +55,7 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest) CTxMemPool testPool(CFeeRate(0)); - std::vector<std::shared_ptr<const CTransaction>> removed; + std::vector<CTransactionRef> removed; // Nothing in pool, remove should do nothing: testPool.removeRecursive(txParent, &removed); @@ -410,8 +410,8 @@ BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest) CheckSort<ancestor_score>(pool, sortedOrder); /* after tx6 is mined, tx7 should move up in the sort */ - std::vector<CTransaction> vtx; - vtx.push_back(tx6); + std::vector<CTransactionRef> vtx; + vtx.push_back(MakeTransactionRef(tx6)); pool.removeForBlock(vtx, 1, NULL, false); sortedOrder.erase(sortedOrder.begin()+1); @@ -546,7 +546,7 @@ BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest) pool.addUnchecked(tx5.GetHash(), entry.Fee(1000LL).FromTx(tx5, &pool)); pool.addUnchecked(tx7.GetHash(), entry.Fee(9000LL).FromTx(tx7, &pool)); - std::vector<CTransaction> vtx; + std::vector<CTransactionRef> vtx; SetMockTime(42); SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE); BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000); diff --git a/src/test/merkle_tests.cpp b/src/test/merkle_tests.cpp index 706d30f489..55e6852a15 100644 --- a/src/test/merkle_tests.cpp +++ b/src/test/merkle_tests.cpp @@ -15,8 +15,8 @@ static uint256 BlockBuildMerkleTree(const CBlock& block, bool* fMutated, std::ve { vMerkleTree.clear(); vMerkleTree.reserve(block.vtx.size() * 2 + 16); // Safe upper bound for the number of total nodes. - for (std::vector<CTransaction>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) - vMerkleTree.push_back(it->GetHash()); + for (std::vector<CTransactionRef>::const_iterator it(block.vtx.begin()); it != block.vtx.end(); ++it) + vMerkleTree.push_back((*it)->GetHash()); int j = 0; bool mutated = false; for (int nSize = block.vtx.size(); nSize > 1; nSize = (nSize + 1) / 2) @@ -86,7 +86,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) for (int j = 0; j < ntx; j++) { CMutableTransaction mtx; mtx.nLockTime = j; - block.vtx[j] = mtx; + block.vtx[j] = MakeTransactionRef(std::move(mtx)); } // Compute the root of the block before mutating it. bool unmutatedMutated = false; @@ -126,7 +126,7 @@ BOOST_AUTO_TEST_CASE(merkle_test) std::vector<uint256> newBranch = BlockMerkleBranch(block, mtx); std::vector<uint256> oldBranch = BlockGetMerkleBranch(block, merkleTree, mtx); BOOST_CHECK(oldBranch == newBranch); - BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx].GetHash(), newBranch, mtx) == oldRoot); + BOOST_CHECK(ComputeMerkleRootFromBranch(block.vtx[mtx]->GetHash(), newBranch, mtx) == oldRoot); } } } diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp index 2762cafa38..aea8920936 100644 --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -77,7 +77,7 @@ bool TestSequenceLocks(const CTransaction &tx, int flags) // Implemented as an additional function, rather than a separate test case, // to allow reusing the blockchain created in CreateNewBlock_validity. // Note that this test assumes blockprioritysize is 0. -void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransaction *>& txFirst) +void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, std::vector<CTransactionRef>& txFirst) { // Test the ancestor feerate transaction selection. TestMemPoolEntryHelper entry; @@ -108,9 +108,9 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, mempool.addUnchecked(hashHighFeeTx, entry.Fee(50000).Time(GetTime()).SpendsCoinbase(false).FromTx(tx)); std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[1].GetHash() == hashParentTx); - BOOST_CHECK(pblocktemplate->block.vtx[2].GetHash() == hashHighFeeTx); - BOOST_CHECK(pblocktemplate->block.vtx[3].GetHash() == hashMediumFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[1]->GetHash() == hashParentTx); + BOOST_CHECK(pblocktemplate->block.vtx[2]->GetHash() == hashHighFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[3]->GetHash() == hashMediumFeeTx); // Test that a package below the min relay fee doesn't get included tx.vin[0].prevout.hash = hashHighFeeTx; @@ -130,8 +130,8 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); // Verify that the free tx and the low fee tx didn't get selected for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { - BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashFreeTx); - BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx); } // Test that packages above the min relay fee do get included, even if one @@ -142,8 +142,8 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, hashLowFeeTx = tx.GetHash(); mempool.addUnchecked(hashLowFeeTx, entry.Fee(feeToUse+2).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[4].GetHash() == hashFreeTx); - BOOST_CHECK(pblocktemplate->block.vtx[5].GetHash() == hashLowFeeTx); + BOOST_CHECK(pblocktemplate->block.vtx[4]->GetHash() == hashFreeTx); + BOOST_CHECK(pblocktemplate->block.vtx[5]->GetHash() == hashLowFeeTx); // Test that transaction selection properly updates ancestor fee // calculations as ancestor transactions get included in a block. @@ -166,8 +166,8 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, // Verify that this tx isn't selected. for (size_t i=0; i<pblocktemplate->block.vtx.size(); ++i) { - BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashFreeTx2); - BOOST_CHECK(pblocktemplate->block.vtx[i].GetHash() != hashLowFeeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashFreeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[i]->GetHash() != hashLowFeeTx2); } // This tx will be mineable, and should cause hashLowFeeTx2 to be selected @@ -176,7 +176,7 @@ void TestPackageSelection(const CChainParams& chainparams, CScript scriptPubKey, tx.vout[0].nValue = 100000000 - 10000; // 10k satoshi fee mempool.addUnchecked(tx.GetHash(), entry.Fee(10000).FromTx(tx)); pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKey); - BOOST_CHECK(pblocktemplate->block.vtx[8].GetHash() == hashLowFeeTx2); + BOOST_CHECK(pblocktemplate->block.vtx[8]->GetHash() == hashLowFeeTx2); } // NOTE: These tests rely on CreateNewBlock doing its own self-validation! @@ -203,28 +203,26 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) // We can't make transactions until we have inputs // Therefore, load 100 blocks :) int baseheight = 0; - std::vector<CTransaction*>txFirst; + std::vector<CTransactionRef> txFirst; for (unsigned int i = 0; i < sizeof(blockinfo)/sizeof(*blockinfo); ++i) { CBlock *pblock = &pblocktemplate->block; // pointer for convenience pblock->nVersion = 1; pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1; - CMutableTransaction txCoinbase(pblock->vtx[0]); + CMutableTransaction txCoinbase(*pblock->vtx[0]); txCoinbase.nVersion = 1; txCoinbase.vin[0].scriptSig = CScript(); txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce); txCoinbase.vin[0].scriptSig.push_back(chainActive.Height()); txCoinbase.vout[0].scriptPubKey = CScript(); - pblock->vtx[0] = CTransaction(txCoinbase); + pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase)); if (txFirst.size() == 0) baseheight = chainActive.Height(); if (txFirst.size() < 4) - txFirst.push_back(new CTransaction(pblock->vtx[0])); + txFirst.push_back(pblock->vtx[0]); pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); pblock->nNonce = blockinfo[i].nonce; - CValidationState state; - BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false)); - BOOST_CHECK(state.IsValid()); + BOOST_CHECK(ProcessNewBlock(chainparams, pblock, true, NULL, NULL)); pblock->hashPrevBlock = pblock->GetHash(); } @@ -487,9 +485,6 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity) TestPackageSelection(chainparams, scriptPubKey, txFirst); - BOOST_FOREACH(CTransaction *_tx, txFirst) - delete _tx; - fCheckpointsEnabled = true; } diff --git a/src/test/pmt_tests.cpp b/src/test/pmt_tests.cpp index c773129640..e6b689bc6c 100644 --- a/src/test/pmt_tests.cpp +++ b/src/test/pmt_tests.cpp @@ -45,14 +45,14 @@ BOOST_AUTO_TEST_CASE(pmt_test1) for (unsigned int j=0; j<nTx; j++) { CMutableTransaction tx; tx.nLockTime = j; // actual transaction data doesn't matter; just make the nLockTime's unique - block.vtx.push_back(CTransaction(tx)); + block.vtx.push_back(MakeTransactionRef(std::move(tx))); } // calculate actual merkle root and height uint256 merkleRoot1 = BlockMerkleRoot(block); std::vector<uint256> vTxid(nTx, uint256()); for (unsigned int j=0; j<nTx; j++) - vTxid[j] = block.vtx[j].GetHash(); + vTxid[j] = block.vtx[j]->GetHash(); int nHeight = 1, nTx_ = nTx; while (nTx_ > 1) { nTx_ = (nTx_+1)/2; diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp index 38aaaba267..7dc8f226c9 100644 --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) CFeeRate baseRate(basefee, GetVirtualTransactionSize(tx)); // Create a fake block - std::vector<CTransaction> block; + std::vector<CTransactionRef> block; int blocknum = 0; // Loop through 200 blocks @@ -66,9 +66,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // 9/10 blocks add 2nd highest and so on until ... // 1/10 blocks add lowest fee transactions while (txHashes[9-h].size()) { - std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[9-h].back()); + CTransactionRef ptx = mpool.get(txHashes[9-h].back()); if (ptx) - block.push_back(*ptx); + block.push_back(ptx); txHashes[9-h].pop_back(); } } @@ -143,9 +143,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) // Estimates should still not be below original for (int j = 0; j < 10; j++) { while(txHashes[j].size()) { - std::shared_ptr<const CTransaction> ptx = mpool.get(txHashes[j].back()); + CTransactionRef ptx = mpool.get(txHashes[j].back()); if (ptx) - block.push_back(*ptx); + block.push_back(ptx); txHashes[j].pop_back(); } } @@ -163,9 +163,9 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) tx.vin[0].prevout.n = 10000*blocknum+100*j+k; uint256 hash = tx.GetHash(); mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(tx, &mpool)); - std::shared_ptr<const CTransaction> ptx = mpool.get(hash); + CTransactionRef ptx = mpool.get(hash); if (ptx) - block.push_back(*ptx); + block.push_back(ptx); } } diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 3da0be8ca4..6cbe314a76 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -101,7 +101,7 @@ TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST) { std::vector<CMutableTransaction> noTxns; CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); - coinbaseTxns.push_back(b.vtx[0]); + coinbaseTxns.push_back(*b.vtx[0]); } } @@ -119,15 +119,14 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& // Replace mempool-selected txns with just coinbase plus passed-in txns: block.vtx.resize(1); BOOST_FOREACH(const CMutableTransaction& tx, txns) - block.vtx.push_back(tx); + block.vtx.push_back(MakeTransactionRef(tx)); // IncrementExtraNonce creates a valid coinbase and merkleRoot unsigned int extraNonce = 0; IncrementExtraNonce(&block, chainActive.Tip(), extraNonce); while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; - CValidationState state; - ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false); + ProcessNewBlock(chainparams, &block, true, NULL, NULL); CBlock result = block; return result; @@ -138,12 +137,12 @@ TestChain100Setup::~TestChain100Setup() } -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) { +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx, CTxMemPool *pool) { CTransaction txn(tx); return FromTx(txn, pool); } -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CTransaction &txn, CTxMemPool *pool) { +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CTransaction &txn, CTxMemPool *pool) { bool hasNoDependencies = pool ? pool->HasNoInputsOf(txn) : hadNoDependencies; // Hack to assume either its completely dependent on other mempool txs or not at all CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0; diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h index 9819a7097d..3dea20445d 100644 --- a/src/test/test_bitcoin.h +++ b/src/test/test_bitcoin.h @@ -79,8 +79,8 @@ struct TestMemPoolEntryHelper nFee(0), nTime(0), dPriority(0.0), nHeight(1), hadNoDependencies(false), spendsCoinbase(false), sigOpCost(4) { } - CTxMemPoolEntry FromTx(CMutableTransaction &tx, CTxMemPool *pool = NULL); - CTxMemPoolEntry FromTx(CTransaction &tx, CTxMemPool *pool = NULL); + CTxMemPoolEntry FromTx(const CMutableTransaction &tx, CTxMemPool *pool = NULL); + CTxMemPoolEntry FromTx(const CTransaction &tx, CTxMemPool *pool = NULL); // Change the default value TestMemPoolEntryHelper &Fee(CAmount _fee) { nFee = _fee; return *this; } diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 45135a5f73..417a88cbef 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -24,7 +24,7 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee, int64_t _nTime, double _entryPriority, unsigned int _entryHeight, bool poolHasNoInputsOf, CAmount _inChainInputValue, bool _spendsCoinbase, int64_t _sigOpsCost, LockPoints lp): - tx(std::make_shared<CTransaction>(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), + tx(MakeTransactionRef(_tx)), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight), hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue), spendsCoinbase(_spendsCoinbase), sigOpCost(_sigOpsCost), lockPoints(lp) { @@ -503,7 +503,7 @@ void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants } } -void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector<std::shared_ptr<const CTransaction>>* removed) +void CTxMemPool::removeRecursive(const CTransaction &origTx, std::vector<CTransactionRef>* removed) { // Remove transaction from memory pool { @@ -576,7 +576,7 @@ void CTxMemPool::removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMem RemoveStaged(setAllRemoves, false); } -void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector<std::shared_ptr<const CTransaction>>* removed) +void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector<CTransactionRef>* removed) { // Remove transactions which depend on inputs of tx, recursively LOCK(cs); @@ -596,29 +596,29 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::vector<std::shared /** * Called when a block is connected. Removes from mempool and updates the miner fee estimator. */ -void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, - std::vector<std::shared_ptr<const CTransaction>>* conflicts, bool fCurrentEstimate) +void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight, + std::vector<CTransactionRef>* conflicts, bool fCurrentEstimate) { LOCK(cs); std::vector<CTxMemPoolEntry> entries; - BOOST_FOREACH(const CTransaction& tx, vtx) + for (const auto& tx : vtx) { - uint256 hash = tx.GetHash(); + uint256 hash = tx->GetHash(); indexed_transaction_set::iterator i = mapTx.find(hash); if (i != mapTx.end()) entries.push_back(*i); } - BOOST_FOREACH(const CTransaction& tx, vtx) + for (const auto& tx : vtx) { - txiter it = mapTx.find(tx.GetHash()); + txiter it = mapTx.find(tx->GetHash()); if (it != mapTx.end()) { setEntries stage; stage.insert(it); RemoveStaged(stage, true); } - removeConflicts(tx, conflicts); - ClearPrioritisation(tx.GetHash()); + removeConflicts(*tx, conflicts); + ClearPrioritisation(tx->GetHash()); } // After the txs in the new block have been removed from the mempool, update policy estimates minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate); @@ -851,7 +851,7 @@ std::vector<TxMempoolInfo> CTxMemPool::infoAll() const return ret; } -std::shared_ptr<const CTransaction> CTxMemPool::get(const uint256& hash) const +CTransactionRef CTxMemPool::get(const uint256& hash) const { LOCK(cs); indexed_transaction_set::const_iterator i = mapTx.find(hash); @@ -978,7 +978,7 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const { // If an entry in the mempool exists, always return that one, as it's guaranteed to never // conflict with the underlying cache, and it cannot have pruned entries (as it contains full) // transactions. First checking the underlying cache risks returning a pruned entry instead. - shared_ptr<const CTransaction> ptx = mempool.get(txid); + CTransactionRef ptx = mempool.get(txid); if (ptx) { coins = CCoins(*ptx, MEMPOOL_HEIGHT); return true; diff --git a/src/txmempool.h b/src/txmempool.h index 9b0ca4655e..29b59363a2 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -80,7 +80,7 @@ class CTxMemPool; class CTxMemPoolEntry { private: - std::shared_ptr<const CTransaction> tx; + CTransactionRef tx; CAmount nFee; //!< Cached to avoid expensive parent-transaction lookups size_t nTxWeight; //!< ... and avoid recomputing tx weight (also used for GetTxSize()) size_t nModSize; //!< ... and modified size for priority @@ -118,7 +118,7 @@ public: CTxMemPoolEntry(const CTxMemPoolEntry& other); const CTransaction& GetTx() const { return *this->tx; } - std::shared_ptr<const CTransaction> GetSharedTx() const { return this->tx; } + CTransactionRef GetSharedTx() const { return this->tx; } /** * Fast calculation of lower bound of current priority as update * from entry priority. Only inputs that were originally in-chain will age. @@ -322,7 +322,7 @@ class CBlockPolicyEstimator; struct TxMempoolInfo { /** The transaction itself */ - std::shared_ptr<const CTransaction> tx; + CTransactionRef tx; /** Time the transaction entered the mempool. */ int64_t nTime; @@ -527,11 +527,11 @@ public: bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true); bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true); - void removeRecursive(const CTransaction &tx, std::vector<std::shared_ptr<const CTransaction>>* removed = NULL); + void removeRecursive(const CTransaction &tx, std::vector<CTransactionRef>* removed = NULL); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); - void removeConflicts(const CTransaction &tx, std::vector<std::shared_ptr<const CTransaction>>* removed = NULL); - void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight, - std::vector<std::shared_ptr<const CTransaction>>* conflicts = NULL, bool fCurrentEstimate = true); + void removeConflicts(const CTransaction &tx, std::vector<CTransactionRef>* removed = NULL); + void removeForBlock(const std::vector<CTransactionRef>& vtx, unsigned int nBlockHeight, + std::vector<CTransactionRef>* conflicts = NULL, bool fCurrentEstimate = true); void clear(); void _clear(); //lock free bool CompareDepthAndScore(const uint256& hasha, const uint256& hashb); @@ -623,7 +623,7 @@ public: return (mapTx.count(hash) != 0); } - std::shared_ptr<const CTransaction> get(const uint256& hash) const; + CTransactionRef get(const uint256& hash) const; TxMempoolInfo info(const uint256& hash) const; std::vector<TxMempoolInfo> infoAll() const; diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index acf980c784..ecbbcb145d 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -266,7 +266,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests) // test with many inputs for (CAmount amt=1500; amt < COIN; amt*=10) { empty_wallet(); - // Create 676 inputs (= MAX_STANDARD_TX_SIZE / 148 bytes per input) + // Create 676 inputs (= (old MAX_STANDARD_TX_SIZE == 100000) / 148 bytes per input) for (uint16_t j = 0; j < 676; j++) add_coin(amt); BOOST_CHECK(wallet.SelectCoinsMinConf(2000, 1, 1, vCoins, setCoinsRet, nValueRet)); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7537604814..9d7ea577de 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1492,7 +1492,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) int posInBlock; for (posInBlock = 0; posInBlock < (int)block.vtx.size(); posInBlock++) { - if (AddToWalletIfInvolvingMe(block.vtx[posInBlock], pindex, posInBlock, fUpdate)) + if (AddToWalletIfInvolvingMe(*block.vtx[posInBlock], pindex, posInBlock, fUpdate)) ret++; } pindex = chainActive.Next(pindex); @@ -1608,7 +1608,7 @@ CAmount CWalletTx::GetCredit(const isminefilter& filter) const if (IsCoinBase() && GetBlocksToMaturity() > 0) return 0; - int64_t credit = 0; + CAmount credit = 0; if (filter & ISMINE_SPENDABLE) { // GetBalance can assume transactions in mapWallet won't change diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index a527c6d84e..409d817046 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -600,7 +600,7 @@ public: */ mutable CCriticalSection cs_wallet; - std::string strWalletFile; + const std::string strWalletFile; void LoadKeyPool(int nIndex, const CKeyPool &keypool) { @@ -625,11 +625,9 @@ public: SetNull(); } - CWallet(const std::string& strWalletFileIn) + CWallet(const std::string& strWalletFileIn) : strWalletFile(strWalletFileIn) { SetNull(); - - strWalletFile = strWalletFileIn; fFileBacked = true; } |