aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am13
-rw-r--r--contrib/gitian-descriptors/gitian-linux.yml4
-rw-r--r--contrib/gitian-descriptors/gitian-osx-signer.yml2
-rw-r--r--contrib/gitian-descriptors/gitian-osx.yml4
-rw-r--r--contrib/gitian-descriptors/gitian-win.yml4
-rw-r--r--contrib/macdeploy/Base.lproj/InfoPlist.strings1
-rw-r--r--contrib/macdeploy/DS_Storebin10244 -> 10244 bytes
-rwxr-xr-xcontrib/macdeploy/detached-sig-create.sh2
-rw-r--r--contrib/macdeploy/fancy.plist2
-rwxr-xr-xcontrib/macdeploy/macdeployqtplus6
-rw-r--r--doc/build-osx.md4
-rwxr-xr-xqa/pull-tester/rpc-tests.sh1
-rwxr-xr-xqa/rpc-tests/p2p-acceptblock.py226
-rw-r--r--share/certs/PrivateKeyNotes.md4
-rw-r--r--share/qt/Info.plist.in8
-rw-r--r--src/json/json_spirit_reader_template.h6
-rw-r--r--src/main.cpp40
-rw-r--r--src/main.h7
-rw-r--r--src/miner.cpp2
-rw-r--r--src/rpcmining.cpp4
-rw-r--r--src/test/miner_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp18
22 files changed, 314 insertions, 46 deletions
diff --git a/Makefile.am b/Makefile.am
index 56c8c09223..2f478e4b41 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,11 +14,12 @@ BITCOIN_QT_BIN=$(top_builddir)/src/qt/bitcoin-qt$(EXEEXT)
BITCOIN_CLI_BIN=$(top_builddir)/src/bitcoin-cli$(EXEEXT)
BITCOIN_WIN_INSTALLER=$(PACKAGE)-$(PACKAGE_VERSION)-win$(WINDOWS_BITS)-setup$(EXEEXT)
-OSX_APP=Bitcoin-Core.app
+OSX_APP=Bitcoin-Qt.app
OSX_DMG=Bitcoin-Core.dmg
OSX_BACKGROUND_IMAGE=background.tiff
OSX_DEPLOY_SCRIPT=$(top_srcdir)/contrib/macdeploy/macdeployqtplus
OSX_FANCY_PLIST=$(top_srcdir)/contrib/macdeploy/fancy.plist
+OSX_BASE_LPROJ_DIR=$(top_srcdir)/contrib/macdeploy/Base.lproj/InfoPlist.strings
OSX_INSTALLER_ICONS=$(top_srcdir)/src/qt/res/icons/bitcoin.icns
OSX_PLIST=$(top_srcdir)/share/qt/Info.plist #not installed
OSX_QT_TRANSLATIONS = da,de,es,hu,ru,uk,zh_CN,zh_TW
@@ -30,7 +31,7 @@ WINDOWS_PACKAGING = $(top_srcdir)/share/pixmaps/bitcoin.ico \
$(top_srcdir)/share/pixmaps/nsis-wizard.bmp \
$(top_srcdir)/doc/README_windows.txt
-OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) \
+OSX_PACKAGING = $(OSX_DEPLOY_SCRIPT) $(OSX_FANCY_PLIST) $(OSX_INSTALLER_ICONS) $(OSX_BASE_LPROJ_DIR) \
$(top_srcdir)/contrib/macdeploy/$(OSX_BACKGROUND_IMAGE) \
$(top_srcdir)/contrib/macdeploy/DS_Store \
$(top_srcdir)/contrib/macdeploy/detached-sig-apply.sh \
@@ -72,7 +73,7 @@ $(OSX_APP)/Contents/PkgInfo:
$(OSX_APP)/Contents/Resources/empty.lproj:
$(MKDIR_P) $(@D)
- @touch $@
+ @touch $@
$(OSX_APP)/Contents/Info.plist: $(OSX_PLIST)
$(MKDIR_P) $(@D)
@@ -86,9 +87,13 @@ $(OSX_APP)/Contents/MacOS/Bitcoin-Qt: $(BITCOIN_QT_BIN)
$(MKDIR_P) $(@D)
STRIPPROG="$(STRIP)" $(INSTALL_STRIP_PROGRAM) $< $@
+$(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings: $(OSX_BASE_LPROJ_DIR)
+ $(MKDIR_P) $(@D)
+ $(INSTALL_DATA) $< $@
+
OSX_APP_BUILT=$(OSX_APP)/Contents/PkgInfo $(OSX_APP)/Contents/Resources/empty.lproj \
$(OSX_APP)/Contents/Resources/bitcoin.icns $(OSX_APP)/Contents/Info.plist \
- $(OSX_APP)/Contents/MacOS/Bitcoin-Qt
+ $(OSX_APP)/Contents/MacOS/Bitcoin-Qt $(OSX_APP)/Contents/Resources/Base.lproj/InfoPlist.strings
if BUILD_DARWIN
$(OSX_DMG): $(OSX_APP_BUILT) $(OSX_PACKAGING)
diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml
index dde4af3491..440d95a355 100644
--- a/contrib/gitian-descriptors/gitian-linux.yml
+++ b/contrib/gitian-descriptors/gitian-linux.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-linux-0.10"
+name: "bitcoin-linux-0.12"
enable_cache: true
suites:
- "precise"
@@ -16,7 +16,7 @@ packages:
- "bsdmainutils"
- "binutils-gold"
- "libstdc++6-4.6-pic"
-reference_datetime: "2013-06-01 00:00:00"
+reference_datetime: "2015-06-01 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
diff --git a/contrib/gitian-descriptors/gitian-osx-signer.yml b/contrib/gitian-descriptors/gitian-osx-signer.yml
index afe03c7a22..c0c0b0c98b 100644
--- a/contrib/gitian-descriptors/gitian-osx-signer.yml
+++ b/contrib/gitian-descriptors/gitian-osx-signer.yml
@@ -7,7 +7,7 @@ architectures:
packages:
- "libc6:i386"
- "faketime"
-reference_datetime: "2013-06-01 00:00:00"
+reference_datetime: "2015-06-01 00:00:00"
remotes: []
files:
- "bitcoin-osx-unsigned.tar.gz"
diff --git a/contrib/gitian-descriptors/gitian-osx.yml b/contrib/gitian-descriptors/gitian-osx.yml
index 61eb5b1001..bad9a0e768 100644
--- a/contrib/gitian-descriptors/gitian-osx.yml
+++ b/contrib/gitian-descriptors/gitian-osx.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-osx-0.10"
+name: "bitcoin-osx-0.12"
enable_cache: true
suites:
- "precise"
@@ -18,7 +18,7 @@ packages:
- "libcap-dev"
- "libz-dev"
- "libbz2-dev"
-reference_datetime: "2013-06-01 00:00:00"
+reference_datetime: "2015-06-01 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
diff --git a/contrib/gitian-descriptors/gitian-win.yml b/contrib/gitian-descriptors/gitian-win.yml
index 2d72f7b6e5..20cfb29859 100644
--- a/contrib/gitian-descriptors/gitian-win.yml
+++ b/contrib/gitian-descriptors/gitian-win.yml
@@ -1,5 +1,5 @@
---
-name: "bitcoin-win-0.10"
+name: "bitcoin-win-0.12"
enable_cache: true
suites:
- "precise"
@@ -18,7 +18,7 @@ packages:
- "g++-mingw-w64"
- "nsis"
- "zip"
-reference_datetime: "2013-06-01 00:00:00"
+reference_datetime: "2015-06-01 00:00:00"
remotes:
- "url": "https://github.com/bitcoin/bitcoin.git"
"dir": "bitcoin"
diff --git a/contrib/macdeploy/Base.lproj/InfoPlist.strings b/contrib/macdeploy/Base.lproj/InfoPlist.strings
new file mode 100644
index 0000000000..b259ea141c
--- /dev/null
+++ b/contrib/macdeploy/Base.lproj/InfoPlist.strings
@@ -0,0 +1 @@
+{ CFBundleDisplayName = "Bitcoin Core"; CFBundleName = "Bitcoin Core"; }
diff --git a/contrib/macdeploy/DS_Store b/contrib/macdeploy/DS_Store
index ca19b207c0..db9d16f1d7 100644
--- a/contrib/macdeploy/DS_Store
+++ b/contrib/macdeploy/DS_Store
Binary files differ
diff --git a/contrib/macdeploy/detached-sig-create.sh b/contrib/macdeploy/detached-sig-create.sh
index fd7314bd7e..18f8661cea 100755
--- a/contrib/macdeploy/detached-sig-create.sh
+++ b/contrib/macdeploy/detached-sig-create.sh
@@ -2,7 +2,7 @@
set -e
ROOTDIR=dist
-BUNDLE="${ROOTDIR}/Bitcoin Core.app"
+BUNDLE="${ROOTDIR}/Bitcoin-Qt.app"
CODESIGN=codesign
TEMPDIR=sign.temp
TEMPLIST=${TEMPDIR}/signatures.txt
diff --git a/contrib/macdeploy/fancy.plist b/contrib/macdeploy/fancy.plist
index a333f5dccd..ef277a7f14 100644
--- a/contrib/macdeploy/fancy.plist
+++ b/contrib/macdeploy/fancy.plist
@@ -22,7 +22,7 @@
<integer>370</integer>
<integer>156</integer>
</array>
- <key>Bitcoin Core.app</key>
+ <key>Bitcoin-Qt.app</key>
<array>
<integer>128</integer>
<integer>156</integer>
diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus
index a625987ca7..2253c40af1 100755
--- a/contrib/macdeploy/macdeployqtplus
+++ b/contrib/macdeploy/macdeployqtplus
@@ -596,7 +596,7 @@ if os.path.exists("dist"):
# ------------------------------------------------
-target = os.path.join("dist", "Bitcoin Core.app")
+target = os.path.join("dist", "Bitcoin-Qt.app")
if verbose >= 2:
print "+ Copying source bundle +"
@@ -757,7 +757,7 @@ if config.dmg is not None:
if fancy is None:
try:
- runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname=app_bundle_name, ov=True)
+ runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname="Bitcoin-Core", ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
else:
@@ -772,7 +772,7 @@ if config.dmg is not None:
if verbose >= 3:
print "Creating temp image for modification..."
try:
- runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=app_bundle_name, ov=True)
+ runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname="Bitcoin-Core", ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
diff --git a/doc/build-osx.md b/doc/build-osx.md
index 02adff0615..913e72519f 100644
--- a/doc/build-osx.md
+++ b/doc/build-osx.md
@@ -100,7 +100,7 @@ Creating a release build
------------------------
You can ignore this section if you are building `bitcoind` for your own use.
-bitcoind/bitcoin-cli binaries are not included in the Bitcoin-Core.app bundle.
+bitcoind/bitcoin-cli binaries are not included in the Bitcoin-Qt.app bundle.
If you are building `bitcoind` or `Bitcoin-Qt` for others, your build machine should be set up
as follows for maximum compatibility:
@@ -111,7 +111,7 @@ All dependencies should be compiled with these flags:
-arch x86_64
-isysroot $(xcode-select --print-path)/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk
-Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin-Core.app
+Once dependencies are compiled, see [doc/release-process.md](release-process.md) for how the Bitcoin-Qt.app
bundle is packaged and signed to create the .dmg disk image that is distributed.
Running
diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh
index 88772a9c32..9b318650e9 100755
--- a/qa/pull-tester/rpc-tests.sh
+++ b/qa/pull-tester/rpc-tests.sh
@@ -51,6 +51,7 @@ testScriptsExt=(
'invalidblockrequest.py'
'rawtransactions.py'
# 'forknotify.py'
+ 'p2p-acceptblock.py'
);
extArg="-extended"
diff --git a/qa/rpc-tests/p2p-acceptblock.py b/qa/rpc-tests/p2p-acceptblock.py
new file mode 100755
index 0000000000..fcdd1e1b99
--- /dev/null
+++ b/qa/rpc-tests/p2p-acceptblock.py
@@ -0,0 +1,226 @@
+#!/usr/bin/env python2
+#
+# Distributed under the MIT/X11 software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#
+
+from test_framework.mininode import *
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import time
+from test_framework.blocktools import create_block, create_coinbase
+
+'''
+AcceptBlockTest -- test processing of unrequested blocks.
+
+Since behavior differs when receiving unrequested blocks from whitelisted peers
+versus non-whitelisted peers, this tests the behavior of both (effectively two
+separate tests running in parallel).
+
+Setup: two nodes, node0 and node1, not connected to each other. Node0 does not
+whitelist localhost, but node1 does. They will each be on their own chain for
+this test.
+
+We have one NodeConn connection to each, test_node and white_node respectively.
+
+The test:
+1. Generate one block on each node, to leave IBD.
+
+2. Mine a new block on each tip, and deliver to each node from node's peer.
+ The tip should advance.
+
+3. Mine a block that forks the previous block, and deliver to each node from
+ corresponding peer.
+ Node0 should not process this block (just accept the header), because it is
+ unrequested and doesn't have more work than the tip.
+ Node1 should process because this is coming from a whitelisted peer.
+
+4. Send another block that builds on the forking block.
+ Node0 should process this block but be stuck on the shorter chain, because
+ it's missing an intermediate block.
+ Node1 should reorg to this longer chain.
+
+5. Send a duplicate of the block in #3 to Node0.
+ Node0 should not process the block because it is unrequested, and stay on
+ the shorter chain.
+
+6. Send Node0 an inv for the height 3 block produced in #4 above.
+ Node0 should figure out that Node0 has the missing height 2 block and send a
+ getdata.
+
+7. Send Node0 the missing block again.
+ Node0 should process and the tip should advance.
+'''
+
+# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
+# p2p messages to a node, generating the messages in the main testing logic.
+class TestNode(NodeConnCB):
+ def __init__(self):
+ NodeConnCB.__init__(self)
+ self.create_callback_map()
+ self.connection = None
+
+ def add_connection(self, conn):
+ self.connection = conn
+
+ # Track the last getdata message we receive (used in the test)
+ def on_getdata(self, conn, message):
+ self.last_getdata = message
+
+ # Spin until verack message is received from the node.
+ # We use this to signal that our test can begin. This
+ # is called from the testing thread, so it needs to acquire
+ # the global lock.
+ def wait_for_verack(self):
+ while True:
+ with mininode_lock:
+ if self.verack_received:
+ return
+ time.sleep(0.05)
+
+ # Wrapper for the NodeConn's send_message function
+ def send_message(self, message):
+ self.connection.send_message(message)
+
+class AcceptBlockTest(BitcoinTestFramework):
+ def add_options(self, parser):
+ parser.add_option("--testbinary", dest="testbinary",
+ default=os.getenv("BITCOIND", "bitcoind"),
+ help="bitcoind binary to test")
+
+ def setup_chain(self):
+ initialize_chain_clean(self.options.tmpdir, 2)
+
+ def setup_network(self):
+ # Node0 will be used to test behavior of processing unrequested blocks
+ # from peers which are not whitelisted, while Node1 will be used for
+ # the whitelisted case.
+ self.nodes = []
+ self.nodes.append(start_node(0, self.options.tmpdir, ["-debug"],
+ binary=self.options.testbinary))
+ self.nodes.append(start_node(1, self.options.tmpdir,
+ ["-debug", "-whitelist=127.0.0.1"],
+ binary=self.options.testbinary))
+
+ def run_test(self):
+ # Setup the p2p connections and start up the network thread.
+ test_node = TestNode() # connects to node0 (not whitelisted)
+ white_node = TestNode() # connects to node1 (whitelisted)
+
+ connections = []
+ connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
+ connections.append(NodeConn('127.0.0.1', p2p_port(1), self.nodes[1], white_node))
+ test_node.add_connection(connections[0])
+ white_node.add_connection(connections[1])
+
+ NetworkThread().start() # Start up network handling in another thread
+
+ # Test logic begins here
+ test_node.wait_for_verack()
+ white_node.wait_for_verack()
+
+ # 1. Have both nodes mine a block (leave IBD)
+ [ n.generate(1) for n in self.nodes ]
+ tips = [ int ("0x" + n.getbestblockhash() + "L", 0) for n in self.nodes ]
+
+ # 2. Send one block that builds on each tip.
+ # This should be accepted.
+ blocks_h2 = [] # the height 2 blocks on each node's chain
+ for i in xrange(2):
+ blocks_h2.append(create_block(tips[i], create_coinbase(), time.time()+1))
+ blocks_h2[i].solve()
+ test_node.send_message(msg_block(blocks_h2[0]))
+ white_node.send_message(msg_block(blocks_h2[1]))
+
+ time.sleep(1)
+ assert_equal(self.nodes[0].getblockcount(), 2)
+ assert_equal(self.nodes[1].getblockcount(), 2)
+ print "First height 2 block accepted by both nodes"
+
+ # 3. Send another block that builds on the original tip.
+ blocks_h2f = [] # Blocks at height 2 that fork off the main chain
+ for i in xrange(2):
+ blocks_h2f.append(create_block(tips[i], create_coinbase(), blocks_h2[i].nTime+1))
+ blocks_h2f[i].solve()
+ test_node.send_message(msg_block(blocks_h2f[0]))
+ white_node.send_message(msg_block(blocks_h2f[1]))
+
+ time.sleep(1) # Give time to process the block
+ for x in self.nodes[0].getchaintips():
+ if x['hash'] == blocks_h2f[0].hash:
+ assert_equal(x['status'], "headers-only")
+
+ for x in self.nodes[1].getchaintips():
+ if x['hash'] == blocks_h2f[1].hash:
+ assert_equal(x['status'], "valid-headers")
+
+ print "Second height 2 block accepted only from whitelisted peer"
+
+ # 4. Now send another block that builds on the forking chain.
+ blocks_h3 = []
+ for i in xrange(2):
+ blocks_h3.append(create_block(blocks_h2f[i].sha256, create_coinbase(), blocks_h2f[i].nTime+1))
+ blocks_h3[i].solve()
+ test_node.send_message(msg_block(blocks_h3[0]))
+ white_node.send_message(msg_block(blocks_h3[1]))
+
+ time.sleep(1)
+ # Since the earlier block was not processed by node0, the new block
+ # can't be fully validated.
+ for x in self.nodes[0].getchaintips():
+ if x['hash'] == blocks_h3[0].hash:
+ assert_equal(x['status'], "headers-only")
+
+ # But this block should be accepted by node0 since it has more work.
+ try:
+ self.nodes[0].getblock(blocks_h3[0].hash)
+ print "Unrequested more-work block accepted from non-whitelisted peer"
+ except:
+ raise AssertionError("Unrequested more work block was not processed")
+
+ # Node1 should have accepted and reorged.
+ assert_equal(self.nodes[1].getblockcount(), 3)
+ print "Successfully reorged to length 3 chain from whitelisted peer"
+
+ # 5. Test handling of unrequested block on the node that didn't process
+ # Should still not be processed (even though it has a child that has more
+ # work).
+ test_node.send_message(msg_block(blocks_h2f[0]))
+
+ # Here, if the sleep is too short, the test could falsely succeed (if the
+ # node hasn't processed the block by the time the sleep returns, and then
+ # the node processes it and incorrectly advances the tip).
+ # But this would be caught later on, when we verify that an inv triggers
+ # a getdata request for this block.
+ time.sleep(1)
+ assert_equal(self.nodes[0].getblockcount(), 2)
+ print "Unrequested block that would complete more-work chain was ignored"
+
+ # 6. Try to get node to request the missing block.
+ # Poke the node with an inv for block at height 3 and see if that
+ # triggers a getdata on block 2 (it should if block 2 is missing).
+ with mininode_lock:
+ # Clear state so we can check the getdata request
+ test_node.last_getdata = None
+ test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
+
+ time.sleep(1)
+ with mininode_lock:
+ getdata = test_node.last_getdata
+
+ # Check that the getdata is for the right block
+ assert_equal(len(getdata.inv), 1)
+ assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
+ print "Inv at tip triggered getdata for unprocessed block"
+
+ # 7. Send the missing block for the third time (now it is requested)
+ test_node.send_message(msg_block(blocks_h2f[0]))
+
+ time.sleep(1)
+ assert_equal(self.nodes[0].getblockcount(), 3)
+ print "Successfully reorged to length 3 chain from non-whitelisted peer"
+
+ [ c.disconnect_node() for c in connections ]
+
+if __name__ == '__main__':
+ AcceptBlockTest().main()
diff --git a/share/certs/PrivateKeyNotes.md b/share/certs/PrivateKeyNotes.md
index cbd060c268..da299d168f 100644
--- a/share/certs/PrivateKeyNotes.md
+++ b/share/certs/PrivateKeyNotes.md
@@ -7,7 +7,7 @@ signing requests.
For OSX, the private key was generated by Keychain.app on Gavin's main work machine.
The key and certificate is in a separate, passphrase-protected keychain file that is
-unlocked to sign the Bitcoin-Core.app bundle.
+unlocked to sign the Bitcoin-Qt.app bundle.
For Windows, the private key was generated by Firefox running on Gavin's main work machine.
The key and certificate were exported into a separate, passphrase-protected PKCS#12 file, and
@@ -17,7 +17,7 @@ Threat analysis
--
Gavin is a single point of failure. He could be coerced to divulge the secret signing keys,
-allowing somebody to distribute a Bitcoin-Core.app or bitcoin-qt-setup.exe with a valid
+allowing somebody to distribute a Bitcoin-Qt.app or bitcoin-qt-setup.exe with a valid
signature but containing a malicious binary.
Or the machine Gavin uses to sign the binaries could be compromised, either remotely or
diff --git a/share/qt/Info.plist.in b/share/qt/Info.plist.in
index dd6edde8d2..a389332a52 100644
--- a/share/qt/Info.plist.in
+++ b/share/qt/Info.plist.in
@@ -3,7 +3,7 @@
<plist version="0.9">
<dict>
<key>LSMinimumSystemVersion</key>
- <string>10.6.0</string>
+ <string>10.7.0</string>
<key>LSArchitecturePriority</key>
<array>
@@ -30,6 +30,12 @@
<key>CFBundleExecutable</key>
<string>Bitcoin-Qt</string>
+
+ <key>CFBundleName</key>
+ <string>Bitcoin-Qt</string>
+
+ <key>LSHasLocalizedDisplayName</key>
+ <true/>
<key>CFBundleIdentifier</key>
<string>org.bitcoinfoundation.Bitcoin-Qt</string>
diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h
index 46f5892f62..47e3c1ca84 100644
--- a/src/json/json_spirit_reader_template.h
+++ b/src/json/json_spirit_reader_template.h
@@ -521,12 +521,11 @@ namespace json_spirit
const spirit_namespace::parse_info< Iter_type > info =
spirit_namespace::parse( begin, end,
- Json_grammer< Value_type, Iter_type >( semantic_actions ),
+ Json_grammer< Value_type, Iter_type >( semantic_actions ) >> spirit_namespace::end_p,
spirit_namespace::space_p );
if( !info.hit )
{
- assert( false ); // in theory exception should already have been thrown
throw_error( info.stop, "error" );
}
@@ -570,7 +569,8 @@ namespace json_spirit
{
typename String_type::const_iterator begin = s.begin();
- return read_range( begin, s.end(), value );
+ bool success = read_range( begin, s.end(), value );
+ return success && begin == s.end();
}
template< class Istream_type >
diff --git a/src/main.cpp b/src/main.cpp
index efb7fb3f87..760cda5dee 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -296,7 +296,8 @@ void FinalizeNode(NodeId nodeid) {
}
// Requires cs_main.
-void MarkBlockAsReceived(const uint256& hash) {
+// Returns a bool indicating whether we requested this block.
+bool MarkBlockAsReceived(const uint256& hash) {
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
@@ -306,7 +307,9 @@ void MarkBlockAsReceived(const uint256& hash) {
state->nBlocksInFlight--;
state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
+ return true;
}
+ return false;
}
// Requires cs_main.
@@ -2826,7 +2829,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
return true;
}
-bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp)
+bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
{
const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
@@ -2836,13 +2839,18 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (!AcceptBlockHeader(block, state, &pindex))
return false;
- // If we're pruning, ensure that we don't allow a peer to dump a copy
- // of old blocks. But we might need blocks that are not on the main chain
- // to handle a reorg, even if we've processed once.
- if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
- // TODO: deal better with duplicate blocks.
- // return state.DoS(20, error("AcceptBlock(): already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
- return true;
+ // Try to process all requested blocks that we don't have, but only
+ // process an unrequested block if it's new and has enough work to
+ // advance our tip.
+ bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
+ bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
+
+ // TODO: deal better with return value and error conditions for duplicate
+ // and unrequested blocks.
+ if (fAlreadyHave) return true;
+ if (!fRequested) { // If we didn't ask for it:
+ if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
+ if (!fHasMoreWork) return true; // Don't process less-work chains
}
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
@@ -2891,21 +2899,22 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
-bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
+bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
{
// Preliminary checks
bool checked = CheckBlock(*pblock, state);
{
LOCK(cs_main);
- MarkBlockAsReceived(pblock->GetHash());
+ bool fRequested = MarkBlockAsReceived(pblock->GetHash());
+ fRequested |= fForceProcessing;
if (!checked) {
return error("%s: CheckBlock FAILED", __func__);
}
// Store to disk
CBlockIndex *pindex = NULL;
- bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
+ bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp);
if (pindex && pfrom) {
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
}
@@ -3453,7 +3462,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
- if (ProcessNewBlock(state, NULL, &block, dbp))
+ if (ProcessNewBlock(state, NULL, &block, true, dbp))
nLoaded++;
if (state.IsError())
break;
@@ -3475,7 +3484,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
head.ToString());
CValidationState dummy;
- if (ProcessNewBlock(dummy, NULL, &block, &it->second))
+ if (ProcessNewBlock(dummy, NULL, &block, true, &it->second))
{
nLoaded++;
queue.push_back(block.GetHash());
@@ -4462,7 +4471,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->AddInventoryKnown(inv);
CValidationState state;
- ProcessNewBlock(state, pfrom, &block);
+ // Process all blocks from whitelisted peers, even if not requested.
+ ProcessNewBlock(state, pfrom, &block, pfrom->fWhitelisted, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
diff --git a/src/main.h b/src/main.h
index 3b25217869..669ea7128a 100644
--- a/src/main.h
+++ b/src/main.h
@@ -153,10 +153,11 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
+ * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
* @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
+bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -400,8 +401,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-/** Store block on disk. If dbp is provided, the file is known to already reside on disk */
-bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
+/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
+bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
diff --git a/src/miner.cpp b/src/miner.cpp
index dfabfd48d0..f5919ca3af 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -434,7 +434,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
// Process this block the same as if we had received it from another node
CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock))
+ if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
return error("BitcoinMiner: ProcessNewBlock, block not accepted");
return true;
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index d58d438573..528d5406f4 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -164,7 +164,7 @@ Value generate(const Array& params, bool fHelp)
++pblock->nNonce;
}
CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock))
+ if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -650,7 +650,7 @@ Value submitblock(const Array& params, bool fHelp)
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(state, NULL, &block);
+ bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL);
UnregisterValidationInterface(&sc);
if (fBlockPresent)
{
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index e3e9061cce..9e4fd8513e 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = blockinfo[i].nonce;
CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
+ BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL));
BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 45cb551d04..5899671d2f 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -140,6 +140,24 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
}
+BOOST_AUTO_TEST_CASE(json_parse_errors)
+{
+ Value value;
+ // Valid
+ BOOST_CHECK_EQUAL(read_string(std::string("1.0"), value), true);
+ // Valid, with trailing whitespace
+ BOOST_CHECK_EQUAL(read_string(std::string("1.0 "), value), true);
+ // Invalid, initial garbage
+ BOOST_CHECK_EQUAL(read_string(std::string("[1.0"), value), false);
+ BOOST_CHECK_EQUAL(read_string(std::string("a1.0"), value), false);
+ // Invalid, trailing garbage
+ BOOST_CHECK_EQUAL(read_string(std::string("1.0sds"), value), false);
+ BOOST_CHECK_EQUAL(read_string(std::string("1.0]"), value), false);
+ // BTC addresses should fail parsing
+ BOOST_CHECK_EQUAL(read_string(std::string("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), value), false);
+ BOOST_CHECK_EQUAL(read_string(std::string("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), value), false);
+}
+
BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
{
// Check IPv4 addresses