aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xqa/pull-tester/rpc-tests.py1
-rwxr-xr-xqa/rpc-tests/keypool.py163
-rwxr-xr-xqa/rpc-tests/multi_rpc.py122
-rw-r--r--qa/rpc-tests/test_framework/util.py3
-rwxr-xr-xqa/rpc-tests/wallet.py39
-rw-r--r--share/rpcuser/README.md11
-rwxr-xr-xshare/rpcuser/rpcuser.py41
-rw-r--r--src/chainparams.h2
-rw-r--r--src/coins.cpp6
-rw-r--r--src/coins.h8
-rw-r--r--src/httprpc.cpp56
-rw-r--r--src/init.cpp22
-rw-r--r--src/main.cpp71
-rw-r--r--src/main.h2
-rw-r--r--src/net.cpp6
-rw-r--r--src/net.h3
-rw-r--r--src/qt/bitcoin.cpp10
-rw-r--r--src/qt/bitcoingui.cpp18
-rw-r--r--src/qt/bitcoingui.h3
-rw-r--r--src/qt/clientmodel.cpp65
-rw-r--r--src/qt/clientmodel.h10
-rw-r--r--src/qt/optionsdialog.cpp75
-rw-r--r--src/qt/optionsdialog.h23
-rw-r--r--src/qt/qvalidatedlineedit.cpp16
-rw-r--r--src/qt/qvalidatedlineedit.h4
-rw-r--r--src/qt/rpcconsole.cpp6
-rw-r--r--src/qt/rpcconsole.h2
-rw-r--r--src/qt/sendcoinsdialog.cpp2
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/rpcrawtransaction.cpp3
-rw-r--r--src/test/policyestimator_tests.cpp2
-rw-r--r--src/test/rpc_tests.cpp1
-rw-r--r--src/test/test_bitcoin.cpp9
-rw-r--r--src/torcontrol.cpp4
-rw-r--r--src/txmempool.cpp17
-rw-r--r--src/txmempool.h14
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/utiltime.cpp16
-rw-r--r--src/wallet/wallet.cpp2
39 files changed, 558 insertions, 305 deletions
diff --git a/qa/pull-tester/rpc-tests.py b/qa/pull-tester/rpc-tests.py
index 5004b09c18..73205dc217 100755
--- a/qa/pull-tester/rpc-tests.py
+++ b/qa/pull-tester/rpc-tests.py
@@ -79,6 +79,7 @@ testScripts = [
'mempool_spendcoinbase.py',
'mempool_coinbase_spends.py',
'httpbasics.py',
+ 'multi_rpc.py',
'zapwallettxes.py',
'proxy_test.py',
'merkle_blocks.py',
diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py
index 5a67220021..92d91e029a 100755
--- a/qa/rpc-tests/keypool.py
+++ b/qa/rpc-tests/keypool.py
@@ -6,15 +6,8 @@
# Exercise the wallet keypool, and interaction with wallet encryption/locking
# Add python-bitcoinrpc to module search path:
-import os
-import sys
-
-import json
-import shutil
-import subprocess
-import tempfile
-import traceback
+from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -39,107 +32,65 @@ def check_array_result(object_array, to_match, expected):
if num_matched == 0:
raise AssertionError("No objects matched %s"%(str(to_match)))
-def run_test(nodes, tmpdir):
- # Encrypt wallet and wait to terminate
- nodes[0].encryptwallet('test')
- bitcoind_processes[0].wait()
- # Restart node 0
- nodes[0] = start_node(0, tmpdir)
- # Keep creating keys
- addr = nodes[0].getnewaddress()
- try:
- addr = nodes[0].getnewaddress()
- raise AssertionError('Keypool should be exhausted after one address')
- except JSONRPCException,e:
- assert(e.error['code']==-12)
-
- # put three new keys in the keypool
- nodes[0].walletpassphrase('test', 12000)
- nodes[0].keypoolrefill(3)
- nodes[0].walletlock()
-
- # drain the keys
- addr = set()
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- addr.add(nodes[0].getrawchangeaddress())
- # assert that four unique addresses were returned
- assert(len(addr) == 4)
- # the next one should fail
- try:
- addr = nodes[0].getrawchangeaddress()
- raise AssertionError('Keypool should be exhausted after three addresses')
- except JSONRPCException,e:
- assert(e.error['code']==-12)
-
- # refill keypool with three new addresses
- nodes[0].walletpassphrase('test', 12000)
- nodes[0].keypoolrefill(3)
- nodes[0].walletlock()
+class KeyPoolTest(BitcoinTestFramework):
- # drain them by mining
- nodes[0].generate(1)
- nodes[0].generate(1)
- nodes[0].generate(1)
- nodes[0].generate(1)
- try:
+ def run_test(self):
+ nodes = self.nodes
+ # Encrypt wallet and wait to terminate
+ nodes[0].encryptwallet('test')
+ bitcoind_processes[0].wait()
+ # Restart node 0
+ nodes[0] = start_node(0, self.options.tmpdir)
+ # Keep creating keys
+ addr = nodes[0].getnewaddress()
+ try:
+ addr = nodes[0].getnewaddress()
+ raise AssertionError('Keypool should be exhausted after one address')
+ except JSONRPCException,e:
+ assert(e.error['code']==-12)
+
+ # put three new keys in the keypool
+ nodes[0].walletpassphrase('test', 12000)
+ nodes[0].keypoolrefill(3)
+ nodes[0].walletlock()
+
+ # drain the keys
+ addr = set()
+ addr.add(nodes[0].getrawchangeaddress())
+ addr.add(nodes[0].getrawchangeaddress())
+ addr.add(nodes[0].getrawchangeaddress())
+ addr.add(nodes[0].getrawchangeaddress())
+ # assert that four unique addresses were returned
+ assert(len(addr) == 4)
+ # the next one should fail
+ try:
+ addr = nodes[0].getrawchangeaddress()
+ raise AssertionError('Keypool should be exhausted after three addresses')
+ except JSONRPCException,e:
+ assert(e.error['code']==-12)
+
+ # refill keypool with three new addresses
+ nodes[0].walletpassphrase('test', 12000)
+ nodes[0].keypoolrefill(3)
+ nodes[0].walletlock()
+
+ # drain them by mining
nodes[0].generate(1)
- raise AssertionError('Keypool should be exhausted after three addesses')
- except JSONRPCException,e:
- assert(e.error['code']==-12)
-
-def main():
- import optparse
-
- parser = optparse.OptionParser(usage="%prog [options]")
- parser.add_option("--nocleanup", dest="nocleanup", default=False, action="store_true",
- help="Leave bitcoinds and test.* datadir on exit or error")
- parser.add_option("--srcdir", dest="srcdir", default="../../src",
- help="Source directory containing bitcoind/bitcoin-cli (default: %default%)")
- parser.add_option("--tmpdir", dest="tmpdir", default=tempfile.mkdtemp(prefix="test"),
- help="Root directory for datadirs")
- (options, args) = parser.parse_args()
-
- os.environ['PATH'] = options.srcdir+":"+os.environ['PATH']
-
- check_json_precision()
-
- success = False
- nodes = []
- try:
- print("Initializing test directory "+options.tmpdir)
- if not os.path.isdir(options.tmpdir):
- os.makedirs(options.tmpdir)
- initialize_chain(options.tmpdir)
-
- nodes = start_nodes(1, options.tmpdir)
-
- run_test(nodes, options.tmpdir)
-
- success = True
-
- except AssertionError as e:
- print("Assertion failed: "+e.message)
- except JSONRPCException as e:
- print("JSONRPC error: "+e.error['message'])
- traceback.print_tb(sys.exc_info()[2])
- except Exception as e:
- print("Unexpected exception caught during testing: "+str(sys.exc_info()[0]))
- traceback.print_tb(sys.exc_info()[2])
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ nodes[0].generate(1)
+ try:
+ nodes[0].generate(1)
+ raise AssertionError('Keypool should be exhausted after three addesses')
+ except JSONRPCException,e:
+ assert(e.error['code']==-12)
- if not options.nocleanup:
- print("Cleaning up")
- stop_nodes(nodes)
- wait_bitcoinds()
- shutil.rmtree(options.tmpdir)
+ def setup_chain(self):
+ print("Initializing test directory "+self.options.tmpdir)
+ initialize_chain(self.options.tmpdir)
- if success:
- print("Tests successful")
- sys.exit(0)
- else:
- print("Failed")
- sys.exit(1)
+ def setup_network(self):
+ self.nodes = start_nodes(1, self.options.tmpdir)
if __name__ == '__main__':
- main()
+ KeyPoolTest().main()
diff --git a/qa/rpc-tests/multi_rpc.py b/qa/rpc-tests/multi_rpc.py
new file mode 100755
index 0000000000..62071d426e
--- /dev/null
+++ b/qa/rpc-tests/multi_rpc.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python2
+# Copyright (c) 2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#
+# Test mulitple rpc user config option rpcauth
+#
+
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import *
+import base64
+
+try:
+ import http.client as httplib
+except ImportError:
+ import httplib
+try:
+ import urllib.parse as urlparse
+except ImportError:
+ import urlparse
+
+class HTTPBasicsTest (BitcoinTestFramework):
+ def setup_nodes(self):
+ return start_nodes(4, self.options.tmpdir)
+
+ def setup_chain(self):
+ print("Initializing test directory "+self.options.tmpdir)
+ initialize_chain(self.options.tmpdir)
+ #Append rpcauth to bitcoin.conf before initialization
+ rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
+ rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
+ with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a') as f:
+ f.write(rpcauth+"\n")
+ f.write(rpcauth2+"\n")
+
+ def run_test(self):
+
+ ##################################################
+ # Check correctness of the rpcauth config option #
+ ##################################################
+ url = urlparse.urlparse(self.nodes[0].url)
+
+ #Old authpair
+ authpair = url.username + ':' + url.password
+
+ #New authpair generated via contrib/rpcuser tool
+ rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
+ password = "cA773lm788buwYe4g4WT+05pKyNruVKjQ25x3n0DQcM="
+
+ #Second authpair with different username
+ rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
+ password2 = "8/F3uMDw4KSEbw96U3CA1C4X05dkHDN2BPFjTgZW4KI="
+ authpairnew = "rt:"+password
+
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, False)
+ conn.close()
+
+ #Use new authpair to confirm both work
+ headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, False)
+ conn.close()
+
+ #Wrong login name with rt's password
+ authpairnew = "rtwrong:"+password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, True)
+ conn.close()
+
+ #Wrong password for rt
+ authpairnew = "rt:"+password+"wrong"
+ headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, True)
+ conn.close()
+
+ #Correct for rt2
+ authpairnew = "rt2:"+password2
+ headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, False)
+ conn.close()
+
+ #Wrong password for rt2
+ authpairnew = "rt2:"+password2+"wrong"
+ headers = {"Authorization": "Basic " + base64.b64encode(authpairnew)}
+
+ conn = httplib.HTTPConnection(url.hostname, url.port)
+ conn.connect()
+ conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
+ resp = conn.getresponse()
+ assert_equal(resp.status==401, True)
+ conn.close()
+
+
+
+if __name__ == '__main__':
+ HTTPBasicsTest ().main ()
diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py
index 30dd5de585..d9d5129f21 100644
--- a/qa/rpc-tests/test_framework/util.py
+++ b/qa/rpc-tests/test_framework/util.py
@@ -67,6 +67,9 @@ def check_json_precision():
if satoshis != 2000000000000003:
raise RuntimeError("JSON encode/decode loses precision")
+def count_bytes(hex_string):
+ return len(bytearray.fromhex(hex_string))
+
def sync_blocks(rpc_connections, wait=1):
"""
Wait until everybody has the same block count
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index f9ec6f429b..6f6bc31895 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -24,6 +24,17 @@ from test_framework.util import *
class WalletTest (BitcoinTestFramework):
+ def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size):
+ """Return curr_balance after asserting the fee was in range"""
+ fee = balance_with_fee - curr_balance
+ target_fee = fee_per_byte * tx_size
+ if fee < target_fee:
+ raise AssertionError("Fee of %s BTC too low! (Should be %s BTC)"%(str(fee), str(target_fee)))
+ # allow the node's estimation to be at most 2 bytes off
+ if fee > fee_per_byte * (tx_size + 2):
+ raise AssertionError("Fee of %s BTC too high! (Should be %s BTC)"%(str(fee), str(target_fee)))
+ return curr_balance
+
def setup_chain(self):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain_clean(self.options.tmpdir, 4)
@@ -104,33 +115,37 @@ class WalletTest (BitcoinTestFramework):
# Send 10 BTC normal
address = self.nodes[0].getnewaddress("test")
- self.nodes[2].settxfee(Decimal('0.001'))
+ fee_per_byte = Decimal('0.001') / 1000
+ self.nodes[2].settxfee(fee_per_byte * 1000)
txid = self.nodes[2].sendtoaddress(address, 10, "", "", False)
self.nodes[2].generate(1)
self.sync_all()
- assert_equal(self.nodes[2].getbalance(), Decimal('89.99900000'))
- assert_equal(self.nodes[0].getbalance(), Decimal('10.00000000'))
+ node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), Decimal('90'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
+ assert_equal(self.nodes[0].getbalance(), Decimal('10'))
# Send 10 BTC with subtract fee from amount
txid = self.nodes[2].sendtoaddress(address, 10, "", "", True)
self.nodes[2].generate(1)
self.sync_all()
- assert_equal(self.nodes[2].getbalance(), Decimal('79.99900000'))
- assert_equal(self.nodes[0].getbalance(), Decimal('19.99900000'))
+ node_2_bal -= Decimal('10')
+ assert_equal(self.nodes[2].getbalance(), node_2_bal)
+ node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), Decimal('20'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
# Sendmany 10 BTC
txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [])
self.nodes[2].generate(1)
self.sync_all()
- assert_equal(self.nodes[2].getbalance(), Decimal('69.99800000'))
- assert_equal(self.nodes[0].getbalance(), Decimal('29.99900000'))
+ node_0_bal += Decimal('10')
+ node_2_bal = self.check_fee_amount(self.nodes[2].getbalance(), node_2_bal - Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
+ assert_equal(self.nodes[0].getbalance(), node_0_bal)
# Sendmany 10 BTC with subtract fee from amount
txid = self.nodes[2].sendmany('from1', {address: 10}, 0, "", [address])
self.nodes[2].generate(1)
self.sync_all()
- assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000'))
- assert_equal(self.nodes[0].getbalance(), Decimal('39.99800000'))
+ node_2_bal -= Decimal('10')
+ assert_equal(self.nodes[2].getbalance(), node_2_bal)
+ node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, count_bytes(self.nodes[2].getrawtransaction(txid)))
# Test ResendWalletTransactions:
# Create a couple of transactions, then start up a fourth
@@ -191,14 +206,14 @@ class WalletTest (BitcoinTestFramework):
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
self.nodes[1].generate(1) #mine a block, tx should not be in there
self.sync_all()
- assert_equal(self.nodes[2].getbalance(), Decimal('59.99800000')); #should not be changed because tx was not broadcasted
+ assert_equal(self.nodes[2].getbalance(), node_2_bal); #should not be changed because tx was not broadcasted
#now broadcast from another node, mine a block, sync, and check the balance
self.nodes[1].sendrawtransaction(txObjNotBroadcasted['hex'])
self.nodes[1].generate(1)
self.sync_all()
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
- assert_equal(self.nodes[2].getbalance(), Decimal('61.99800000')); #should not be
+ assert_equal(self.nodes[2].getbalance(), node_2_bal + Decimal('2')); #should not be
#create another tx
txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2);
@@ -216,7 +231,7 @@ class WalletTest (BitcoinTestFramework):
sync_blocks(self.nodes)
#tx should be added to balance because after restarting the nodes tx should be broadcastet
- assert_equal(self.nodes[2].getbalance(), Decimal('63.99800000')); #should not be
+ assert_equal(self.nodes[2].getbalance(), node_2_bal + Decimal('4')); #should not be
#send a tx with value in a string (PR#6380 +)
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2")
diff --git a/share/rpcuser/README.md b/share/rpcuser/README.md
new file mode 100644
index 0000000000..7c2c909a42
--- /dev/null
+++ b/share/rpcuser/README.md
@@ -0,0 +1,11 @@
+RPC Tools
+---------------------
+
+### [RPCUser](/share/rpcuser) ###
+
+Create an RPC user login credential.
+
+Usage:
+
+./rpcuser.py <username>
+
diff --git a/share/rpcuser/rpcuser.py b/share/rpcuser/rpcuser.py
new file mode 100755
index 0000000000..9fd176908b
--- /dev/null
+++ b/share/rpcuser/rpcuser.py
@@ -0,0 +1,41 @@
+#!/usr/bin/env python2
+# Copyright (c) 2015 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+import hashlib
+import sys
+import os
+from random import SystemRandom
+import base64
+import hmac
+
+if len(sys.argv) < 2:
+ sys.stderr.write('Please include username as an argument.\n')
+ sys.exit(0)
+
+username = sys.argv[1]
+
+#This uses os.urandom() underneath
+cryptogen = SystemRandom()
+
+#Create 16 byte hex salt
+salt_sequence = [cryptogen.randrange(256) for i in range(16)]
+hexseq = list(map(hex, salt_sequence))
+salt = "".join([x[2:] for x in hexseq])
+
+#Create 32 byte b64 password
+password = base64.urlsafe_b64encode(os.urandom(32))
+
+digestmod = hashlib.sha256
+
+if sys.version_info.major >= 3:
+ password = password.decode('utf-8')
+ digestmod = 'SHA256'
+
+m = hmac.new(bytearray(salt, 'utf-8'), bytearray(password, 'utf-8'), digestmod)
+result = m.hexdigest()
+
+print("String to be appended to bitcoin.conf:")
+print("rpcauth="+username+":"+salt+"$"+result)
+print("Your password:\n"+password)
diff --git a/src/chainparams.h b/src/chainparams.h
index cb061d596e..8aa0c71d61 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -65,7 +65,7 @@ public:
/** Policy: Filter transactions that do not match well-defined patterns */
bool RequireStandard() const { return fRequireStandard; }
int64_t MaxTipAge() const { return nMaxTipAge; }
- int64_t PruneAfterHeight() const { return nPruneAfterHeight; }
+ uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
/** Make miner stop after a block is found. In RPC, don't return until nGenProcLimit blocks are generated */
bool MineBlocksOnDemand() const { return fMineBlocksOnDemand; }
/** In the future use NetworkIDString() for RPC fields */
diff --git a/src/coins.cpp b/src/coins.cpp
index f0ea5c0459..723e114708 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -243,8 +243,9 @@ bool CCoinsViewCache::HaveInputs(const CTransaction& tx) const
return true;
}
-double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
+double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const
{
+ inChainInputValue = 0;
if (tx.IsCoinBase())
return 0.0;
double dResult = 0.0;
@@ -253,8 +254,9 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
const CCoins* coins = AccessCoins(txin.prevout.hash);
assert(coins);
if (!coins->IsAvailable(txin.prevout.n)) continue;
- if (coins->nHeight < nHeight) {
+ if (coins->nHeight <= nHeight) {
dResult += coins->vout[txin.prevout.n].nValue * (nHeight-coins->nHeight);
+ inChainInputValue += coins->vout[txin.prevout.n].nValue;
}
}
return tx.ComputePriority(dResult);
diff --git a/src/coins.h b/src/coins.h
index 99b25de45b..d174422100 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -456,8 +456,12 @@ public:
//! Check whether all prevouts of the transaction are present in the UTXO set represented by this view
bool HaveInputs(const CTransaction& tx) const;
- //! Return priority of tx at height nHeight
- double GetPriority(const CTransaction &tx, int nHeight) const;
+ /**
+ * Return priority of tx at height nHeight. Also calculate the sum of the values of the inputs
+ * that are already in the chain. These are the inputs that will age and increase priority as
+ * new blocks are added to the chain.
+ */
+ double GetPriority(const CTransaction &tx, int nHeight, CAmount &inChainInputValue) const;
const CTxOut &GetOutputFor(const CTxIn& input) const;
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 98ac750bb1..2920aa26f7 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -10,8 +10,12 @@
#include "util.h"
#include "utilstrencodings.h"
#include "ui_interface.h"
+#include "crypto/hmac_sha256.h"
+#include <stdio.h>
+#include "utilstrencodings.h"
#include <boost/algorithm/string.hpp> // boost::trim
+#include <boost/foreach.hpp> //BOOST_FOREACH
/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
* re-lock the wellet.
@@ -72,6 +76,50 @@ static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const Uni
req->WriteReply(nStatus, strReply);
}
+//This function checks username and password against -rpcauth
+//entries from config file.
+static bool multiUserAuthorized(std::string strUserPass)
+{
+ if (strUserPass.find(":") == std::string::npos) {
+ return false;
+ }
+ std::string strUser = strUserPass.substr(0, strUserPass.find(":"));
+ std::string strPass = strUserPass.substr(strUserPass.find(":") + 1);
+
+ if (mapMultiArgs.count("-rpcauth") > 0) {
+ //Search for multi-user login/pass "rpcauth" from config
+ BOOST_FOREACH(std::string strRPCAuth, mapMultiArgs["-rpcauth"])
+ {
+ std::vector<std::string> vFields;
+ boost::split(vFields, strRPCAuth, boost::is_any_of(":$"));
+ if (vFields.size() != 3) {
+ //Incorrect formatting in config file
+ continue;
+ }
+
+ std::string strName = vFields[0];
+ if (!TimingResistantEqual(strName, strUser)) {
+ continue;
+ }
+
+ std::string strSalt = vFields[1];
+ std::string strHash = vFields[2];
+
+ unsigned int KEY_SIZE = 32;
+ unsigned char *out = new unsigned char[KEY_SIZE];
+
+ CHMAC_SHA256(reinterpret_cast<const unsigned char*>(strSalt.c_str()), strSalt.size()).Write(reinterpret_cast<const unsigned char*>(strPass.c_str()), strPass.size()).Finalize(out);
+ std::vector<unsigned char> hexvec(out, out+KEY_SIZE);
+ std::string strHashFromPass = HexStr(hexvec);
+
+ if (TimingResistantEqual(strHashFromPass, strHash)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static bool RPCAuthorized(const std::string& strAuth)
{
if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
@@ -81,7 +129,12 @@ static bool RPCAuthorized(const std::string& strAuth)
std::string strUserPass64 = strAuth.substr(6);
boost::trim(strUserPass64);
std::string strUserPass = DecodeBase64(strUserPass64);
- return TimingResistantEqual(strUserPass, strRPCUserColonPass);
+
+ //Check if authorized under single-user field
+ if (TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
+ return true;
+ }
+ return multiUserAuthorized(strUserPass);
}
static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
@@ -157,6 +210,7 @@ static bool InitRPCAuthentication()
return false;
}
} else {
+ LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcuser for rpcauth auth generation.");
strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
return true;
diff --git a/src/init.cpp b/src/init.cpp
index 1c2f3f49d4..3fd60abfc2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -441,7 +441,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
}
- string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, zmq"; // Don't translate these and qt below
+ string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent, tor, zmq"; // Don't translate these and qt below
if (mode == HMM_BITCOIN_QT)
debugCategories += ", qt";
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -491,6 +491,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-rpcbind=<addr>", _("Bind to given address to listen for JSON-RPC connections. Use [host]:port notation for IPv6. This option can be specified multiple times (default: bind to all interfaces)"));
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
+ strUsage += HelpMessageOpt("-rpcauth=<userpw>", _("Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. This option can be specified multiple times"));
strUsage += HelpMessageOpt("-rpcport=<port>", strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332));
strUsage += HelpMessageOpt("-rpcallowip=<ip>", _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times"));
strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));
@@ -515,11 +516,14 @@ std::string LicenseInfo()
"\n";
}
-static void BlockNotifyCallback(const uint256& hashNewTip)
+static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex)
{
+ if (initialSync || !pBlockIndex)
+ return;
+
std::string strCmd = GetArg("-blocknotify", "");
- boost::replace_all(strCmd, "%s", hashNewTip.GetHex());
+ boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
@@ -820,7 +824,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 2: parameter interactions
const CChainParams& chainparams = Params();
-
+ // also see: InitParameterInteraction()
// if using block pruning, then disable txindex
if (GetArg("-prune", 0)) {
@@ -833,16 +837,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
#endif
}
- // disable walletbroadcast and whitelistalwaysrelay in blocksonly mode
- if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) {
- if (SoftSetBoolArg("-whitelistalwaysrelay", false))
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistalwaysrelay=0\n", __func__);
-#ifdef ENABLE_WALLET
- if (SoftSetBoolArg("-walletbroadcast", false))
- LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -walletbroadcast=0\n", __func__);
-#endif
- }
-
// Make sure enough file descriptors are available
int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
int nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
diff --git a/src/main.cpp b/src/main.cpp
index 31913956b7..eea53a58de 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -950,9 +950,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
- double dPriority = view.GetPriority(tx, chainActive.Height());
+ CAmount inChainInputValue;
+ double dPriority = view.GetPriority(tx, chainActive.Height(), inChainInputValue);
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx));
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue);
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
@@ -964,7 +965,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
- } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
+ } else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(entry.GetPriority(chainActive.Height() + 1))) {
// Require that free transactions have sufficient priority to be mined in the next block.
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient priority");
}
@@ -2606,37 +2607,41 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
- if (!fInitialDownload) {
- // Find the hashes of all blocks that weren't previously in the best chain.
- std::vector<uint256> vHashes;
- CBlockIndex *pindexToAnnounce = pindexNewTip;
- while (pindexToAnnounce != pindexFork) {
- vHashes.push_back(pindexToAnnounce->GetBlockHash());
- pindexToAnnounce = pindexToAnnounce->pprev;
- if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
- // Limit announcements in case of a huge reorganization.
- // Rely on the peer's synchronization mechanism in that case.
- break;
+ // Always notify the UI if a new block tip was connected
+ if (pindexFork != pindexNewTip) {
+ uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
+
+ if (!fInitialDownload) {
+ // Find the hashes of all blocks that weren't previously in the best chain.
+ std::vector<uint256> vHashes;
+ CBlockIndex *pindexToAnnounce = pindexNewTip;
+ while (pindexToAnnounce != pindexFork) {
+ vHashes.push_back(pindexToAnnounce->GetBlockHash());
+ pindexToAnnounce = pindexToAnnounce->pprev;
+ if (vHashes.size() == MAX_BLOCKS_TO_ANNOUNCE) {
+ // Limit announcements in case of a huge reorganization.
+ // Rely on the peer's synchronization mechanism in that case.
+ break;
+ }
}
- }
- // Relay inventory, but don't relay old inventory during initial block download.
- int nBlockEstimate = 0;
- if (fCheckpointsEnabled)
- nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes) {
- if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
- BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
- pnode->PushBlockHash(hash);
+ // Relay inventory, but don't relay old inventory during initial block download.
+ int nBlockEstimate = 0;
+ if (fCheckpointsEnabled)
+ nBlockEstimate = Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints());
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate)) {
+ BOOST_REVERSE_FOREACH(const uint256& hash, vHashes) {
+ pnode->PushBlockHash(hash);
+ }
}
}
}
- }
- // Notify external listeners about the new tip.
- if (!vHashes.empty()) {
- GetMainSignals().UpdatedBlockTip(pindexNewTip);
- uiInterface.NotifyBlockTip(vHashes.front());
+ // Notify external listeners about the new tip.
+ if (!vHashes.empty()) {
+ GetMainSignals().UpdatedBlockTip(pindexNewTip);
+ }
}
}
} while(pindexMostWork != chainActive.Tip());
@@ -3290,7 +3295,7 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight
if (chainActive.Tip() == NULL || nPruneTarget == 0) {
return;
}
- if (chainActive.Tip()->nHeight <= nPruneAfterHeight) {
+ if ((uint64_t)chainActive.Tip()->nHeight <= nPruneAfterHeight) {
return;
}
@@ -4670,6 +4675,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
bool fMissingInputs = false;
CValidationState state;
+ pfrom->setAskFor.erase(inv.hash);
mapAlreadyAskedFor.erase(inv);
if (!AlreadyHave(inv) && AcceptToMemoryPool(mempool, state, tx, true, &fMissingInputs))
@@ -5618,6 +5624,9 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->PushMessage("getdata", vGetData);
vGetData.clear();
}
+ } else {
+ //If we're not going to ask, don't expect a response.
+ pto->setAskFor.erase(inv.hash);
}
pto->mapAskFor.erase(pto->mapAskFor.begin());
}
diff --git a/src/main.h b/src/main.h
index 3dec613fc7..bdbfa3826e 100644
--- a/src/main.h
+++ b/src/main.h
@@ -222,7 +222,7 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
*
* Pruning functions are called from FlushStateToDisk when the global fCheckForPruning flag has been set.
* Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
- * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 10 on regtest).
+ * Pruning cannot take place until the longest chain is at least a certain length (100000 on mainnet, 1000 on testnet, 1000 on regtest).
* Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
* The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
* A db flag records the fact that at least some block files have been pruned.
diff --git a/src/net.cpp b/src/net.cpp
index abc7cbb8f4..e5659efc01 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -2407,8 +2407,12 @@ CNode::~CNode()
void CNode::AskFor(const CInv& inv)
{
- if (mapAskFor.size() > MAPASKFOR_MAX_SZ)
+ if (mapAskFor.size() > MAPASKFOR_MAX_SZ || setAskFor.size() > SETASKFOR_MAX_SZ)
return;
+ // a peer may not have multiple non-responded queue positions for a single inv item
+ if (!setAskFor.insert(inv.hash).second)
+ return;
+
// We're using mapAskFor as a priority queue,
// the key is the earliest time the request can be sent
int64_t nRequestTime;
diff --git a/src/net.h b/src/net.h
index fb299fb0b4..a5a5c770d6 100644
--- a/src/net.h
+++ b/src/net.h
@@ -58,6 +58,8 @@ static const bool DEFAULT_UPNP = false;
#endif
/** The maximum number of entries in mapAskFor */
static const size_t MAPASKFOR_MAX_SZ = MAX_INV_SZ;
+/** The maximum number of entries in setAskFor (larger due to getdata latency)*/
+static const size_t SETASKFOR_MAX_SZ = 2 * MAX_INV_SZ;
/** The maximum number of peer connections to maintain. */
static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
/** The default for -maxuploadtarget. 0 = Unlimited */
@@ -389,6 +391,7 @@ public:
mruset<CInv> setInventoryKnown;
std::vector<CInv> vInventoryToSend;
CCriticalSection cs_inventory;
+ std::set<uint256> setAskFor;
std::multimap<int64_t, CInv> mapAskFor;
// Used for headers announcements - unfiltered blocks to relay
// Also protected by cs_inventory
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 1fa5ef5f5d..6e6330d2a4 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -311,14 +311,8 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv):
// UI per-platform customization
// This must be done inside the BitcoinApplication constructor, or after it, because
// PlatformStyle::instantiate requires a QApplication
-#if defined(Q_OS_MAC)
- std::string platformName = "macosx";
-#elif defined(Q_OS_WIN)
- std::string platformName = "windows";
-#else
- std::string platformName = "other";
-#endif
- platformName = GetArg("-uiplatform", platformName);
+ std::string platformName;
+ platformName = GetArg("-uiplatform", BitcoinGUI::DEFAULT_UIPLATFORM);
platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
if (!platformStyle) // Fall back to "other" if specified name not found
platformStyle = PlatformStyle::instantiate("other");
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 6f9f6e90d6..b2bd167aea 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -59,6 +59,16 @@
#include <QUrlQuery>
#endif
+const std::string BitcoinGUI::DEFAULT_UIPLATFORM =
+#if defined(Q_OS_MAC)
+ "macosx"
+#elif defined(Q_OS_WIN)
+ "windows"
+#else
+ "other"
+#endif
+ ;
+
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
@@ -443,8 +453,8 @@ void BitcoinGUI::setClientModel(ClientModel *clientModel)
setNumConnections(clientModel->getNumConnections());
connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate());
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime)));
+ setNumBlocks(clientModel->getNumBlocks(), clientModel->getLastBlockDate(), clientModel->getVerificationProgress(NULL));
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
// Receive and report messages from client model
connect(clientModel, SIGNAL(message(QString,QString,unsigned int)), this, SLOT(message(QString,QString,unsigned int)));
@@ -672,7 +682,7 @@ void BitcoinGUI::setNumConnections(int count)
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
-void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
+void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
{
if(!clientModel)
return;
@@ -749,7 +759,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
progressBarLabel->setVisible(true);
progressBar->setFormat(tr("%1 behind").arg(timeBehindText));
progressBar->setMaximum(1000000000);
- progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5);
+ progressBar->setValue(nVerificationProgress * 1000000000.0 + 0.5);
progressBar->setVisible(true);
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 2b98dabc56..b121a443e7 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -48,6 +48,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
+ static const std::string DEFAULT_UIPLATFORM;
explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0);
~BitcoinGUI();
@@ -149,7 +150,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
/** Notify the user of an event from the core network or transaction handling code.
@param[in] title the message box / notification title
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 566e8fa62d..d36d129c1a 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -22,17 +22,16 @@
#include <QDebug>
#include <QTimer>
+class CBlockIndex;
+
static const int64_t nClientStartupTime = GetTime();
+static int64_t nLastBlockTipUpdateNotification = 0;
ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent),
optionsModel(optionsModel),
peerTableModel(0),
banTableModel(0),
- cachedNumBlocks(0),
- cachedBlockDate(QDateTime()),
- cachedReindexing(0),
- cachedImporting(0),
pollTimer(0)
{
peerTableModel = new PeerTableModel(this);
@@ -99,40 +98,21 @@ size_t ClientModel::getMempoolDynamicUsage() const
return mempool.DynamicMemoryUsage();
}
-double ClientModel::getVerificationProgress() const
+double ClientModel::getVerificationProgress(const CBlockIndex *tipIn) const
{
- LOCK(cs_main);
- return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip());
+ CBlockIndex *tip = const_cast<CBlockIndex *>(tipIn);
+ if (!tip)
+ {
+ LOCK(cs_main);
+ tip = chainActive.Tip();
+ }
+ return Checkpoints::GuessVerificationProgress(Params().Checkpoints(), tip);
}
void ClientModel::updateTimer()
{
- // Get required lock upfront. This avoids the GUI from getting stuck on
- // periodical polls if the core is holding the locks for a longer time -
- // for example, during a wallet rescan.
- TRY_LOCK(cs_main, lockMain);
- if (!lockMain)
- return;
-
- // Some quantities (such as number of blocks) change so fast that we don't want to be notified for each change.
- // Periodically check and update with a timer.
- int newNumBlocks = getNumBlocks();
- QDateTime newBlockDate = getLastBlockDate();
-
- // check for changed number of blocks we have, number of blocks peers claim to have, reindexing state and importing state
- if (cachedNumBlocks != newNumBlocks ||
- cachedBlockDate != newBlockDate ||
- cachedReindexing != fReindex ||
- cachedImporting != fImporting)
- {
- cachedNumBlocks = newNumBlocks;
- cachedBlockDate = newBlockDate;
- cachedReindexing = fReindex;
- cachedImporting = fImporting;
-
- Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate);
- }
-
+ // no locking required at this point
+ // the following calls will aquire the required lock
Q_EMIT mempoolSizeChanged(getMempoolSize(), getMempoolDynamicUsage());
Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
@@ -261,6 +241,23 @@ static void BannedListChanged(ClientModel *clientmodel)
QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
}
+static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CBlockIndex *pIndex)
+{
+ // lock free async UI updates in case we have a new block tip
+ // during initial sync, only update the UI if the last update
+ // was > 250ms (MODEL_UPDATE_DELAY) ago
+ int64_t now = 0;
+ if (initialSync)
+ now = GetTimeMillis();
+
+ // if we are in-sync, update the UI regardless of last update time
+ if (!initialSync || now - nLastBlockTipUpdateNotification > MODEL_UPDATE_DELAY) {
+ //pass a async signal to the UI thread
+ Q_EMIT clientmodel->numBlocksChanged(pIndex->nHeight, QDateTime::fromTime_t(pIndex->GetBlockTime()), clientmodel->getVerificationProgress(pIndex));
+ nLastBlockTipUpdateNotification = now;
+ }
+}
+
void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
@@ -268,6 +265,7 @@ void ClientModel::subscribeToCoreSignals()
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
+ uiInterface.NotifyBlockTip.connect(boost::bind(BlockTipChanged, this, _1, _2));
}
void ClientModel::unsubscribeFromCoreSignals()
@@ -277,4 +275,5 @@ void ClientModel::unsubscribeFromCoreSignals()
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
+ uiInterface.NotifyBlockTip.disconnect(boost::bind(BlockTipChanged, this, _1, _2));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 493a759331..2d204fdb67 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -15,6 +15,7 @@ class PeerTableModel;
class TransactionTableModel;
class CWallet;
+class CBlockIndex;
QT_BEGIN_NAMESPACE
class QTimer;
@@ -59,7 +60,7 @@ public:
quint64 getTotalBytesRecv() const;
quint64 getTotalBytesSent() const;
- double getVerificationProgress() const;
+ double getVerificationProgress(const CBlockIndex *tip) const;
QDateTime getLastBlockDate() const;
//! Return true if core is doing initial block download
@@ -81,11 +82,6 @@ private:
PeerTableModel *peerTableModel;
BanTableModel *banTableModel;
- int cachedNumBlocks;
- QDateTime cachedBlockDate;
- bool cachedReindexing;
- bool cachedImporting;
-
QTimer *pollTimer;
void subscribeToCoreSignals();
@@ -93,7 +89,7 @@ private:
Q_SIGNALS:
void numConnectionsChanged(int count);
- void numBlocksChanged(int count, const QDateTime& blockDate);
+ void numBlocksChanged(int count, const QDateTime& blockDate, double nVerificationProgress);
void mempoolSizeChanged(long count, size_t mempoolSizeInBytes);
void alertsChanged(const QString &warnings);
void bytesChanged(quint64 totalBytesIn, quint64 totalBytesOut);
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index d0191fa6d8..647c860bdc 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -34,8 +34,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
QDialog(parent),
ui(new Ui::OptionsDialog),
model(0),
- mapper(0),
- fProxyIpsValid(true)
+ mapper(0)
{
ui->setupUi(this);
@@ -60,12 +59,11 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
+ connect(ui->connectSocks, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState()));
connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyIpTor, SLOT(setEnabled(bool)));
connect(ui->connectSocksTor, SIGNAL(toggled(bool)), ui->proxyPortTor, SLOT(setEnabled(bool)));
-
- ui->proxyIp->installEventFilter(this);
- ui->proxyIpTor->installEventFilter(this);
+ connect(ui->connectSocksTor, SIGNAL(toggled(bool)), this, SLOT(updateProxyValidationState()));
/* Window elements init */
#ifdef Q_OS_MAC
@@ -119,7 +117,12 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
mapper->setOrientation(Qt::Vertical);
/* setup/change UI elements when proxy IPs are invalid/valid */
- connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int)));
+ ui->proxyIp->setCheckValidator(new ProxyAddressValidator(parent));
+ ui->proxyIpTor->setCheckValidator(new ProxyAddressValidator(parent));
+ connect(ui->proxyIp, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState()));
+ connect(ui->proxyIpTor, SIGNAL(validationDidChange(QValidatedLineEdit *)), this, SLOT(updateProxyValidationState()));
+ connect(ui->proxyPort, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState()));
+ connect(ui->proxyPortTor, SIGNAL(textChanged(const QString&)), this, SLOT(updateProxyValidationState()));
}
OptionsDialog::~OptionsDialog()
@@ -200,18 +203,6 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
}
-void OptionsDialog::enableOkButton()
-{
- /* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */
- if(fProxyIpsValid)
- setOkButtonState(true);
-}
-
-void OptionsDialog::disableOkButton()
-{
- setOkButtonState(false);
-}
-
void OptionsDialog::setOkButtonState(bool fState)
{
ui->okButton->setEnabled(fState);
@@ -269,24 +260,20 @@ void OptionsDialog::clearStatusLabel()
ui->statusLabel->clear();
}
-void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort)
+void OptionsDialog::updateProxyValidationState()
{
- Q_UNUSED(nProxyPort);
-
- CService addrProxy;
-
- /* Check for a valid IPv4 / IPv6 address */
- if (!(fProxyIpsValid = LookupNumeric(pUiProxyIp->text().toStdString().c_str(), addrProxy)))
+ QValidatedLineEdit *pUiProxyIp = ui->proxyIp;
+ QValidatedLineEdit *otherProxyWidget = (pUiProxyIp == ui->proxyIpTor) ? ui->proxyIp : ui->proxyIpTor;
+ if (pUiProxyIp->isValid() && (!ui->proxyPort->isEnabled() || ui->proxyPort->text().toInt() > 0) && (!ui->proxyPortTor->isEnabled() || ui->proxyPortTor->text().toInt() > 0))
{
- disableOkButton();
- pUiProxyIp->setValid(false);
- ui->statusLabel->setStyleSheet("QLabel { color: red; }");
- ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
+ setOkButtonState(otherProxyWidget->isValid()); //only enable ok button if both proxys are valid
+ ui->statusLabel->clear();
}
else
{
- enableOkButton();
- ui->statusLabel->clear();
+ setOkButtonState(false);
+ ui->statusLabel->setStyleSheet("QLabel { color: red; }");
+ ui->statusLabel->setText(tr("The supplied proxy address is invalid."));
}
}
@@ -312,18 +299,18 @@ void OptionsDialog::updateDefaultProxyNets()
(strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
}
-bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
+ProxyAddressValidator::ProxyAddressValidator(QObject *parent) :
+QValidator(parent)
{
- if(event->type() == QEvent::FocusOut)
- {
- if(object == ui->proxyIp)
- {
- Q_EMIT proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
- }
- else if(object == ui->proxyIpTor)
- {
- Q_EMIT proxyIpChecks(ui->proxyIpTor, ui->proxyPortTor->text().toInt());
- }
- }
- return QDialog::eventFilter(object, event);
+}
+
+QValidator::State ProxyAddressValidator::validate(QString &input, int &pos) const
+{
+ Q_UNUSED(pos);
+ // Validate the proxy
+ proxyType addrProxy = proxyType(CService(input.toStdString(), 9050), true);
+ if (addrProxy.IsValid())
+ return QValidator::Acceptable;
+
+ return QValidator::Invalid;
}
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index 348489c599..489e35da49 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -6,6 +6,7 @@
#define BITCOIN_QT_OPTIONSDIALOG_H
#include <QDialog>
+#include <QValidator>
class OptionsModel;
class QValidatedLineEdit;
@@ -18,6 +19,18 @@ namespace Ui {
class OptionsDialog;
}
+/** Proxy address widget validator, checks for a valid proxy address.
+ */
+class ProxyAddressValidator : public QValidator
+{
+ Q_OBJECT
+
+public:
+ explicit ProxyAddressValidator(QObject *parent);
+
+ State validate(QString &input, int &pos) const;
+};
+
/** Preferences dialog. */
class OptionsDialog : public QDialog
{
@@ -30,14 +43,7 @@ public:
void setModel(OptionsModel *model);
void setMapper();
-protected:
- bool eventFilter(QObject *object, QEvent *event);
-
private Q_SLOTS:
- /* enable OK button */
- void enableOkButton();
- /* disable OK button */
- void disableOkButton();
/* set OK button state (enabled / disabled) */
void setOkButtonState(bool fState);
void on_resetButton_clicked();
@@ -46,7 +52,7 @@ private Q_SLOTS:
void showRestartWarning(bool fPersistent = false);
void clearStatusLabel();
- void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
+ void updateProxyValidationState();
/* query the networks, for which the default proxy is used */
void updateDefaultProxyNets();
@@ -57,7 +63,6 @@ private:
Ui::OptionsDialog *ui;
OptionsModel *model;
QDataWidgetMapper *mapper;
- bool fProxyIpsValid;
};
#endif // BITCOIN_QT_OPTIONSDIALOG_H
diff --git a/src/qt/qvalidatedlineedit.cpp b/src/qt/qvalidatedlineedit.cpp
index 346369392c..5658a0bdcf 100644
--- a/src/qt/qvalidatedlineedit.cpp
+++ b/src/qt/qvalidatedlineedit.cpp
@@ -99,9 +99,25 @@ void QValidatedLineEdit::checkValidity()
}
else
setValid(false);
+
+ Q_EMIT validationDidChange(this);
}
void QValidatedLineEdit::setCheckValidator(const QValidator *v)
{
checkValidator = v;
}
+
+bool QValidatedLineEdit::isValid()
+{
+ // use checkValidator in case the QValidatedLineEdit is disabled
+ if (checkValidator)
+ {
+ QString address = text();
+ int pos = 0;
+ if (checkValidator->validate(address, pos) == QValidator::Acceptable)
+ return true;
+ }
+
+ return valid;
+}
diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h
index 8665acda5e..8cb6a425fa 100644
--- a/src/qt/qvalidatedlineedit.h
+++ b/src/qt/qvalidatedlineedit.h
@@ -18,6 +18,7 @@ public:
explicit QValidatedLineEdit(QWidget *parent);
void clear();
void setCheckValidator(const QValidator *v);
+ bool isValid();
protected:
void focusInEvent(QFocusEvent *evt);
@@ -31,6 +32,9 @@ public Q_SLOTS:
void setValid(bool valid);
void setEnabled(bool enabled);
+Q_SIGNALS:
+ void validationDidChange(QValidatedLineEdit *validatedLineEdit);
+
private Q_SLOTS:
void markValid();
void checkValidity();
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index b2b4fd0fab..30e551de19 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -343,8 +343,8 @@ void RPCConsole::setClientModel(ClientModel *model)
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
- setNumBlocks(model->getNumBlocks(), model->getLastBlockDate());
- connect(model, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(setNumBlocks(int,QDateTime)));
+ setNumBlocks(model->getNumBlocks(), model->getLastBlockDate(), model->getVerificationProgress(NULL));
+ connect(model, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(setNumBlocks(int,QDateTime,double)));
updateTrafficStats(model->getTotalBytesRecv(), model->getTotalBytesSent());
connect(model, SIGNAL(bytesChanged(quint64,quint64)), this, SLOT(updateTrafficStats(quint64, quint64)));
@@ -525,7 +525,7 @@ void RPCConsole::setNumConnections(int count)
ui->numberOfConnections->setText(connections);
}
-void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate)
+void RPCConsole::setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress)
{
ui->numberOfBlocks->setText(QString::number(count));
ui->lastBlockTime->setText(blockDate.toString());
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 4b242affcd..4aebad480c 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -83,7 +83,7 @@ public Q_SLOTS:
/** Set number of connections shown in the UI */
void setNumConnections(int count);
/** Set number of blocks and last block date shown in the UI */
- void setNumBlocks(int count, const QDateTime& blockDate);
+ void setNumBlocks(int count, const QDateTime& blockDate, double nVerificationProgress);
/** Set size (number of transactions and memory usage) of the mempool in the UI */
void setMempoolSize(long numberOfTxs, size_t dynUsage);
/** Go forward or back in history */
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 7b714be5b1..0fd86da034 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -124,7 +124,7 @@ void SendCoinsDialog::setClientModel(ClientModel *clientModel)
this->clientModel = clientModel;
if (clientModel) {
- connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime)), this, SLOT(updateSmartFeeLabel()));
+ connect(clientModel, SIGNAL(numBlocksChanged(int,QDateTime,double)), this, SLOT(updateSmartFeeLabel()));
}
}
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index da85ab2b30..f609289749 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -86,7 +86,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
strUsage += HelpMessageOpt("-splash", strprintf(_("Show splash screen on startup (default: %u)"), DEFAULT_SPLASHSCREEN));
strUsage += HelpMessageOpt("-resetguisettings", _("Reset all settings changes made over the GUI"));
if (showDebug) {
- strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)");
+ strUsage += HelpMessageOpt("-uiplatform", strprintf("Select platform to customize UI for (one of windows, macosx, other; default: %s)", BitcoinGUI::DEFAULT_UIPLATFORM));
}
QString coreOptions = QString::fromStdString(strUsage);
text = version + "\n" + header + "\n" + coreOptions;
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index 3bda459245..1f2d77aef0 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -62,6 +62,7 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fInclud
void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
+ entry.push_back(Pair("size", (int)::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION)));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
UniValue vin(UniValue::VARR);
@@ -133,6 +134,7 @@ UniValue getrawtransaction(const UniValue& params, bool fHelp)
"{\n"
" \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
+ " \"size\" : n, (numeric) The transaction size\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
@@ -429,6 +431,7 @@ UniValue decoderawtransaction(const UniValue& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"txid\" : \"id\", (string) The transaction id\n"
+ " \"size\" : n, (numeric) The transaction size\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
index 1315146f10..644c3da213 100644
--- a/src/test/policyestimator_tests.cpp
+++ b/src/test/policyestimator_tests.cpp
@@ -196,7 +196,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
// Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee
// and that estimateSmartPriority returns essentially an infinite value
- mpool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, feeV[0][5], GetTime(), priV[1][5], blocknum, mpool.HasNoInputsOf(tx)));
+ mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[0][5]).Time(GetTime()).Priority(priV[1][5]).Height(blocknum).FromTx(tx, &mpool));
// evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[0][5]
mpool.TrimToSize(1);
BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[0][5]);
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 2a486f08e4..ce22975005 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -72,6 +72,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_CHECK_THROW(CallRPC("decoderawtransaction DEADBEEF"), runtime_error);
string rawtx = "0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000";
BOOST_CHECK_NO_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx));
+ BOOST_CHECK_EQUAL(find_value(r.get_obj(), "size").get_int(), 193);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "version").get_int(), 1);
BOOST_CHECK_EQUAL(find_value(r.get_obj(), "locktime").get_int(), 0);
BOOST_CHECK_THROW(r = CallRPC(string("decoderawtransaction ")+rawtx+" extra"), runtime_error);
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index 2fe190f885..351870014d 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -144,8 +144,13 @@ TestChain100Setup::~TestChain100Setup()
CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(CMutableTransaction &tx, CTxMemPool *pool) {
- return CTxMemPoolEntry(tx, nFee, nTime, dPriority, nHeight,
- pool ? pool->HasNoInputsOf(tx) : hadNoDependencies);
+ CTransaction txn(tx);
+ bool hasNoDependencies = pool ? pool->HasNoInputsOf(tx) : hadNoDependencies;
+ // Hack to assume either its completely dependent on other mempool txs or not at all
+ CAmount inChainValue = hasNoDependencies ? txn.GetValueOut() : 0;
+
+ return CTxMemPoolEntry(txn, nFee, nTime, dPriority, nHeight,
+ hasNoDependencies, inChainValue);
}
void Shutdown(void* parg)
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 31a2917203..8eccc81e30 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -617,7 +617,9 @@ void TorController::disconnected_cb(TorControlConnection& conn)
service = CService();
if (!reconnect)
return;
- LogPrintf("tor: Disconnected from Tor control port %s, trying to reconnect\n", target);
+
+ LogPrint("tor", "tor: Disconnected from Tor control port %s, trying to reconnect\n", target);
+
// Single-shot timer for reconnect. Use exponential backoff.
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index ec7971c2f1..6d1df0b3d1 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -19,10 +19,10 @@
using namespace std;
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
- int64_t _nTime, double _dPriority,
- unsigned int _nHeight, bool poolHasNoInputsOf):
- tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
- hadNoDependencies(poolHasNoInputsOf)
+ int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
+ bool poolHasNoInputsOf, CAmount _inChainInputValue):
+ tx(_tx), nFee(_nFee), nTime(_nTime), entryPriority(_entryPriority), entryHeight(_entryHeight),
+ hadNoDependencies(poolHasNoInputsOf), inChainInputValue(_inChainInputValue)
{
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
nModSize = tx.CalculateModifiedSize(nTxSize);
@@ -31,6 +31,8 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
nCountWithDescendants = 1;
nSizeWithDescendants = nTxSize;
nFeesWithDescendants = nFee;
+ CAmount nValueIn = tx.GetValueOut()+nFee;
+ assert(inChainInputValue <= nValueIn);
}
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
@@ -41,9 +43,10 @@ CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
double
CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
{
- CAmount nValueIn = tx.GetValueOut()+nFee;
- double deltaPriority = ((double)(currentHeight-nHeight)*nValueIn)/nModSize;
- double dResult = dPriority + deltaPriority;
+ double deltaPriority = ((double)(currentHeight-entryHeight)*inChainInputValue)/nModSize;
+ double dResult = entryPriority + deltaPriority;
+ if (dResult < 0) // This should only happen if it was called with a height below entry height
+ dResult = 0;
return dResult;
}
diff --git a/src/txmempool.h b/src/txmempool.h
index 7f43120f7f..c470bbe28f 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -63,9 +63,10 @@ private:
size_t nModSize; //! ... and modified size for priority
size_t nUsageSize; //! ... and total memory usage
int64_t nTime; //! Local time when entering the mempool
- double dPriority; //! Priority when entering the mempool
- unsigned int nHeight; //! Chain height when entering the mempool
+ double entryPriority; //! Priority when entering the mempool
+ unsigned int entryHeight; //! Chain height when entering the mempool
bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
+ CAmount inChainInputValue; //! Sum of all txin values that are already in blockchain
// Information about descendants of this transaction that are in the
// mempool; if we remove this transaction we must remove all of these
@@ -78,15 +79,20 @@ private:
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
- int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf = false);
+ int64_t _nTime, double _entryPriority, unsigned int _entryHeight,
+ bool poolHasNoInputsOf, CAmount _inChainInputValue);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() 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.
+ */
double GetPriority(unsigned int currentHeight) const;
const CAmount& GetFee() const { return nFee; }
size_t GetTxSize() const { return nTxSize; }
int64_t GetTime() const { return nTime; }
- unsigned int GetHeight() const { return nHeight; }
+ unsigned int GetHeight() const { return entryHeight; }
bool WasClearAtEntry() const { return hadNoDependencies; }
size_t DynamicMemoryUsage() const { return nUsageSize; }
diff --git a/src/ui_interface.h b/src/ui_interface.h
index e402479933..00d9303124 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -15,6 +15,7 @@
class CBasicKeyStore;
class CWallet;
class uint256;
+class CBlockIndex;
/** General change type (added, updated, removed). */
enum ChangeType
@@ -94,7 +95,7 @@ public:
boost::signals2::signal<void (const std::string &title, int nProgress)> ShowProgress;
/** New block has been accepted */
- boost::signals2::signal<void (const uint256& hash)> NotifyBlockTip;
+ boost::signals2::signal<void (bool, const CBlockIndex *)> NotifyBlockTip;
/** Banlist did change. */
boost::signals2::signal<void (void)> BannedListChanged;
diff --git a/src/utiltime.cpp b/src/utiltime.cpp
index 3202c47f1d..7d9f6210eb 100644
--- a/src/utiltime.cpp
+++ b/src/utiltime.cpp
@@ -20,7 +20,9 @@ int64_t GetTime()
{
if (nMockTime) return nMockTime;
- return time(NULL);
+ time_t now = time(NULL);
+ assert(now > 0);
+ return now;
}
void SetMockTime(int64_t nMockTimeIn)
@@ -30,14 +32,18 @@ void SetMockTime(int64_t nMockTimeIn)
int64_t GetTimeMillis()
{
- return (boost::posix_time::microsec_clock::universal_time() -
- boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
+ int64_t now = (boost::posix_time::microsec_clock::universal_time() -
+ boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
+ assert(now > 0);
+ return now;
}
int64_t GetTimeMicros()
{
- return (boost::posix_time::microsec_clock::universal_time() -
- boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
+ int64_t now = (boost::posix_time::microsec_clock::universal_time() -
+ boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
+ assert(now > 0);
+ return now;
}
/** Return a time useful for the debug log */
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 57a41ec665..78c9357842 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -41,7 +41,7 @@ CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = DEFAULT_SPEND_ZEROCONF_CHANGE;
bool fSendFreeTransactions = DEFAULT_SEND_FREE_TRANSACTIONS;
-bool fPayAtLeastCustomFee = true;
+bool fPayAtLeastCustomFee = false;
/**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)