aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac25
-rw-r--r--depends/packages/bdb.mk3
-rw-r--r--doc/bips.md1
-rwxr-xr-xqa/rpc-tests/sendheaders.py18
-rwxr-xr-xqa/rpc-tests/test_framework/mininode.py15
-rwxr-xr-xqa/rpc-tests/wallet.py62
-rw-r--r--src/httprpc.cpp4
-rw-r--r--src/init.cpp26
-rw-r--r--src/main.cpp18
-rw-r--r--src/main.h2
-rw-r--r--src/policy/policy.cpp3
-rw-r--r--src/qt/intro.cpp20
-rw-r--r--src/qt/rpcconsole.cpp6
-rw-r--r--src/reverselock.h5
-rw-r--r--src/rpcserver.cpp22
-rw-r--r--src/rpcserver.h10
-rw-r--r--src/test/reverselock_tests.cpp16
-rw-r--r--src/wallet/test/wallet_tests.cpp25
-rw-r--r--src/wallet/wallet.cpp7
-rw-r--r--src/wallet/wallet.h164
-rw-r--r--src/wallet/walletdb.cpp13
21 files changed, 287 insertions, 178 deletions
diff --git a/configure.ac b/configure.ac
index 9161e2b2c0..07f9a4a6f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -619,6 +619,31 @@ if test x$use_boost = xyes; then
BOOST_LIBS="$BOOST_LDFLAGS $BOOST_SYSTEM_LIB $BOOST_FILESYSTEM_LIB $BOOST_PROGRAM_OPTIONS_LIB $BOOST_THREAD_LIB $BOOST_CHRONO_LIB"
+TEMP_LIBS="$LIBS"
+LIBS="$BOOST_LIBS $LIBS"
+TEMP_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+AC_MSG_CHECKING([for mismatched boost c++11 scoped enums])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+ #include "boost/config.hpp"
+ #include "boost/version.hpp"
+ #if !defined(BOOST_NO_SCOPED_ENUMS) && !defined(BOOST_NO_CXX11_SCOPED_ENUMS) && BOOST_VERSION < 105700
+ #define BOOST_NO_SCOPED_ENUMS
+ #define BOOST_NO_CXX11_SCOPED_ENUMS
+ #define CHECK
+ #endif
+ #include "boost/filesystem.hpp"
+ ]],[[
+ #if defined(CHECK)
+ boost::filesystem::copy_file("foo", "bar");
+ #else
+ choke;
+ #endif
+ ]])],
+ [AC_MSG_RESULT(mismatched); AC_DEFINE(FORCE_BOOST_EMULATED_SCOPED_ENUMS, 1, [Define this symbol if boost scoped enums are emulated])], [AC_MSG_RESULT(ok)])
+LIBS="$TEMP_LIBS"
+CPPFLAGS="$TEMP_CPPFLAGS"
+
dnl Boost >= 1.50 uses sleep_for rather than the now-deprecated sleep, however
dnl it was broken from 1.50 to 1.52 when backed by nanosleep. Use sleep_for if
dnl a working version is available, else fall back to sleep. sleep was removed
diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk
index 68841afdb8..e2f85ad4fc 100644
--- a/depends/packages/bdb.mk
+++ b/depends/packages/bdb.mk
@@ -12,7 +12,8 @@ $(package)_config_opts_linux=--with-pic
endef
define $(package)_preprocess_cmds
- sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h
+ sed -i.old 's/__atomic_compare_exchange/__atomic_compare_exchange_db/' dbinc/atomic.h && \
+ sed -i.old 's/atomic_init/atomic_init_db/' dbinc/atomic.h mp/mp_region.c mp/mp_mvcc.c mp/mp_fget.c mutex/mut_method.c mutex/mut_tas.c
endef
define $(package)_config_cmds
diff --git a/doc/bips.md b/doc/bips.md
index 962b216123..e73add0130 100644
--- a/doc/bips.md
+++ b/doc/bips.md
@@ -18,4 +18,5 @@ BIPs that are implemented by Bitcoin Core (up-to-date up to **v0.12.0**):
* [`BIP 66`](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki): The strict DER rules and associated version 3 blocks have been implemented since **v0.10.0** ([PR #5713](https://github.com/bitcoin/bitcoin/pull/5713)).
* [`BIP 70`](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki) [`71`](https://github.com/bitcoin/bips/blob/master/bip-0071.mediawiki) [`72`](https://github.com/bitcoin/bips/blob/master/bip-0072.mediawiki): Payment Protocol support has been available in Bitcoin Core GUI since **v0.9.0** ([PR #5216](https://github.com/bitcoin/bitcoin/pull/5216)).
* [`BIP 111`](https://github.com/bitcoin/bips/blob/master/bip-0111.mediawiki): `NODE_BLOOM` service bit added, but only enforced for peer versions `>=70011` as of **v0.12.0** ([PR #6579](https://github.com/bitcoin/bitcoin/pull/6579)).
+* [`BIP 125`](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki): Opt-in full replace-by-fee signaling honoured in mempool and mining as of **v0.12.0** ([PR 6871](https://github.com/bitcoin/bitcoin/pull/6871)).
* [`BIP 130`](https://github.com/bitcoin/bips/blob/master/bip-0130.mediawiki): direct headers announcement is negotiated with peer versions `>=70012` as of **v0.12.0** ([PR 6494](https://github.com/bitcoin/bitcoin/pull/6494)).
diff --git a/qa/rpc-tests/sendheaders.py b/qa/rpc-tests/sendheaders.py
index e6e26dbce3..7572bc2776 100755
--- a/qa/rpc-tests/sendheaders.py
+++ b/qa/rpc-tests/sendheaders.py
@@ -220,18 +220,20 @@ class SendHeadersTest(BitcoinTestFramework):
# mine count blocks and return the new tip
def mine_blocks(self, count):
+ # Clear out last block announcement from each p2p listener
+ [ x.clear_last_announcement() for x in self.p2p_connections ]
self.nodes[0].generate(count)
return int(self.nodes[0].getbestblockhash(), 16)
# mine a reorg that invalidates length blocks (replacing them with
# length+1 blocks).
- # peers is the p2p nodes we're using; we clear their state after the
+ # Note: we clear the state of our p2p connections after the
# to-be-reorged-out blocks are mined, so that we don't break later tests.
# return the list of block hashes newly mined
- def mine_reorg(self, length, peers):
+ def mine_reorg(self, length):
self.nodes[0].generate(length) # make sure all invalidated blocks are node0's
sync_blocks(self.nodes, wait=0.1)
- [x.clear_last_announcement() for x in peers]
+ [x.clear_last_announcement() for x in self.p2p_connections]
tip_height = self.nodes[1].getblockcount()
hash_to_invalidate = self.nodes[1].getblockhash(tip_height-(length-1))
@@ -245,6 +247,8 @@ class SendHeadersTest(BitcoinTestFramework):
inv_node = InvNode()
test_node = TestNode()
+ self.p2p_connections = [inv_node, test_node]
+
connections = []
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], inv_node))
# Set nServices to 0 for test_node, so no block download will occur outside of
@@ -303,7 +307,6 @@ class SendHeadersTest(BitcoinTestFramework):
prev_tip = int(self.nodes[0].getbestblockhash(), 16)
test_node.get_headers(locator=[prev_tip], hashstop=0L)
test_node.sync_with_ping()
- test_node.clear_last_announcement() # Clear out empty headers response
# Now that we've synced headers, headers announcements should work
tip = self.mine_blocks(1)
@@ -352,8 +355,6 @@ class SendHeadersTest(BitcoinTestFramework):
# broadcast it)
assert_equal(inv_node.last_inv, None)
assert_equal(inv_node.last_headers, None)
- inv_node.clear_last_announcement()
- test_node.clear_last_announcement()
tip = self.mine_blocks(1)
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
@@ -368,7 +369,7 @@ class SendHeadersTest(BitcoinTestFramework):
# getheaders or inv from peer.
for j in xrange(2):
# First try mining a reorg that can propagate with header announcement
- new_block_hashes = self.mine_reorg(length=7, peers=[test_node, inv_node])
+ new_block_hashes = self.mine_reorg(length=7)
tip = new_block_hashes[-1]
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(headers=new_block_hashes), True)
@@ -376,7 +377,7 @@ class SendHeadersTest(BitcoinTestFramework):
block_time += 8
# Mine a too-large reorg, which should be announced with a single inv
- new_block_hashes = self.mine_reorg(length=8, peers=[test_node, inv_node])
+ new_block_hashes = self.mine_reorg(length=8)
tip = new_block_hashes[-1]
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
assert_equal(test_node.check_last_announcement(inv=[tip]), True)
@@ -407,7 +408,6 @@ class SendHeadersTest(BitcoinTestFramework):
test_node.get_headers(locator=[fork_point], hashstop=new_block_hashes[1])
test_node.get_data([tip])
test_node.wait_for_block(tip)
- test_node.clear_last_announcement()
elif i == 2:
test_node.get_data([tip])
test_node.wait_for_block(tip)
diff --git a/qa/rpc-tests/test_framework/mininode.py b/qa/rpc-tests/test_framework/mininode.py
index 8e49b56565..ca65fb6e79 100755
--- a/qa/rpc-tests/test_framework/mininode.py
+++ b/qa/rpc-tests/test_framework/mininode.py
@@ -1004,6 +1004,18 @@ class msg_reject(object):
class NodeConnCB(object):
def __init__(self):
self.verack_received = False
+ # deliver_sleep_time is helpful for debugging race conditions in p2p
+ # tests; it causes message delivery to sleep for the specified time
+ # before acquiring the global lock and delivering the next message.
+ self.deliver_sleep_time = None
+
+ def set_deliver_sleep_time(self, value):
+ with mininode_lock:
+ self.deliver_sleep_time = value
+
+ def get_deliver_sleep_time(self):
+ with mininode_lock:
+ return self.deliver_sleep_time
# Spin until verack message is received from the node.
# Tests may want to use this as a signal that the test can begin.
@@ -1017,6 +1029,9 @@ class NodeConnCB(object):
time.sleep(0.05)
def deliver(self, conn, message):
+ deliver_sleep = self.get_deliver_sleep_time()
+ if deliver_sleep is not None:
+ time.sleep(deliver_sleep)
with mininode_lock:
try:
getattr(self, 'on_' + message.command)(conn, message)
diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py
index 6045b8268c..43ec621a40 100755
--- a/qa/rpc-tests/wallet.py
+++ b/qa/rpc-tests/wallet.py
@@ -3,21 +3,6 @@
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#
-# Exercise the wallet. Ported from wallet.sh.
-# Does the following:
-# a) creates 3 nodes, with an empty chain (no blocks).
-# b) node0 mines a block
-# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none.
-# d) node0 sends 21 btc to node2, in two transactions (11 btc, then 10 btc).
-# e) node0 mines a block, collects the fee on the second transaction
-# f) node1 mines 100 blocks, to mature node0's just-mined block
-# g) check that node0 has 100-21, node2 has 21
-# h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1
-# i) have node1 mine a block
-# j) check balances - node0 should have 0, node2 should have 100
-# k) test ResendWalletTransactions - create transactions, startup fourth node, make sure it syncs
-#
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
@@ -190,7 +175,7 @@ class WalletTest (BitcoinTestFramework):
for uTx in unspentTxs:
if uTx['txid'] == zeroValueTxid:
found = True
- assert_equal(uTx['amount'], Decimal('0.00000000'));
+ assert_equal(uTx['amount'], Decimal('0'))
assert(found)
#do some -walletbroadcast tests
@@ -202,21 +187,22 @@ class WalletTest (BitcoinTestFramework):
connect_nodes_bi(self.nodes,0,2)
self.sync_all()
- txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2);
+ txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
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(), node_2_bal); #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()
+ node_2_bal += 2
txObjNotBroadcasted = self.nodes[0].gettransaction(txIdNotBroadcasted)
- assert_equal(self.nodes[2].getbalance(), node_2_bal + Decimal('2')); #should not be
+ assert_equal(self.nodes[2].getbalance(), node_2_bal)
#create another tx
- txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2);
+ txIdNotBroadcasted = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
#restart the nodes with -walletbroadcast=1
stop_nodes(self.nodes)
@@ -229,23 +215,24 @@ class WalletTest (BitcoinTestFramework):
self.nodes[0].generate(1)
sync_blocks(self.nodes)
+ node_2_bal += 2
#tx should be added to balance because after restarting the nodes tx should be broadcastet
- assert_equal(self.nodes[2].getbalance(), node_2_bal + Decimal('4')); #should not be
+ assert_equal(self.nodes[2].getbalance(), node_2_bal)
#send a tx with value in a string (PR#6380 +)
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2")
txObj = self.nodes[0].gettransaction(txId)
- assert_equal(txObj['amount'], Decimal('-2.00000000'))
+ assert_equal(txObj['amount'], Decimal('-2'))
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001")
txObj = self.nodes[0].gettransaction(txId)
- assert_equal(txObj['amount'], Decimal('-0.00010000'))
+ assert_equal(txObj['amount'], Decimal('-0.0001'))
#check if JSON parser can handle scientific notation in strings
txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4")
txObj = self.nodes[0].gettransaction(txId)
- assert_equal(txObj['amount'], Decimal('-0.00010000'))
+ assert_equal(txObj['amount'], Decimal('-0.0001'))
#this should fail
errorString = ""
@@ -254,7 +241,7 @@ class WalletTest (BitcoinTestFramework):
except JSONRPCException,e:
errorString = e.error['message']
- assert_equal("Invalid amount" in errorString, True);
+ assert_equal("Invalid amount" in errorString, True)
errorString = ""
try:
@@ -262,7 +249,30 @@ class WalletTest (BitcoinTestFramework):
except JSONRPCException,e:
errorString = e.error['message']
- assert_equal("not an integer" in errorString, True);
+ assert_equal("not an integer" in errorString, True)
+
+ #check if wallet or blochchain maintenance changes the balance
+ self.sync_all()
+ self.nodes[0].generate(1)
+ self.sync_all()
+ balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
+
+ maintenance = [
+ '-rescan',
+ '-reindex',
+ '-zapwallettxes=1',
+ '-zapwallettxes=2',
+ '-salvagewallet',
+ ]
+ for m in maintenance:
+ stop_nodes(self.nodes)
+ wait_bitcoinds()
+ self.nodes = start_nodes(3, self.options.tmpdir, [[m]] * 3)
+ connect_nodes_bi(self.nodes,0,1)
+ connect_nodes_bi(self.nodes,1,2)
+ connect_nodes_bi(self.nodes,0,2)
+ self.sync_all()
+ assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
if __name__ == '__main__':
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
index 2920aa26f7..1466dc0cbf 100644
--- a/src/httprpc.cpp
+++ b/src/httprpc.cpp
@@ -226,7 +226,7 @@ bool StartHTTPRPC()
assert(EventBase());
httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
- RPCRegisterTimerInterface(httpRPCTimerInterface);
+ RPCSetTimerInterface(httpRPCTimerInterface);
return true;
}
@@ -240,7 +240,7 @@ void StopHTTPRPC()
LogPrint("rpc", "Stopping HTTP RPC server\n");
UnregisterHTTPHandler("/", true);
if (httpRPCTimerInterface) {
- RPCUnregisterTimerInterface(httpRPCTimerInterface);
+ RPCUnsetTimerInterface(httpRPCTimerInterface);
delete httpRPCTimerInterface;
httpRPCTimerInterface = 0;
}
diff --git a/src/init.cpp b/src/init.cpp
index ba85a7972e..374e756abd 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -476,6 +476,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("Node relay options:"));
if (showDebug)
strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !Params(CBaseChainParams::TESTNET).RequireStandard()));
+ strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Minimum bytes per sigop in transactions we relay and mine (default: %u)"), DEFAULT_BYTES_PER_SIGOP));
strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -750,6 +751,16 @@ void InitParameterInteraction()
}
}
+static std::string ResolveErrMsg(const char * const optname, const std::string& strBind)
+{
+ return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind);
+}
+
+static std::string AmountErrMsg(const char * const optname, const std::string& strValue)
+{
+ return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue);
+}
+
void InitLogging()
{
fPrintToConsole = GetBoolArg("-printtoconsole", false);
@@ -933,12 +944,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (ParseMoney(mapArgs["-minrelaytxfee"], n) && n > 0)
::minRelayTxFee = CFeeRate(n);
else
- return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
+ return InitError(AmountErrMsg("minrelaytxfee", mapArgs["-minrelaytxfee"]));
}
fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
if (Params().RequireStandard() && !fRequireStandard)
return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
+ nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp);
#ifdef ENABLE_WALLET
if (mapArgs.count("-mintxfee"))
@@ -947,7 +959,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
if (ParseMoney(mapArgs["-mintxfee"], n) && n > 0)
CWallet::minTxFee = CFeeRate(n);
else
- return InitError(strprintf(_("Invalid amount for -mintxfee=<amount>: '%s'"), mapArgs["-mintxfee"]));
+ return InitError(AmountErrMsg("mintxfee", mapArgs["-mintxfee"]));
}
if (mapArgs.count("-fallbackfee"))
{
@@ -962,7 +974,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
CAmount nFeePerK = 0;
if (!ParseMoney(mapArgs["-paytxfee"], nFeePerK))
- return InitError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s'"), mapArgs["-paytxfee"]));
+ return InitError(AmountErrMsg("paytxfee", mapArgs["-paytxfee"]));
if (nFeePerK > nHighTransactionFeeWarning)
InitWarning(_("-paytxfee is set very high! This is the transaction fee you will pay if you send a transaction."));
payTxFee = CFeeRate(nFeePerK, 1000);
@@ -976,7 +988,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
CAmount nMaxFee = 0;
if (!ParseMoney(mapArgs["-maxtxfee"], nMaxFee))
- return InitError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s'"), mapArgs["-maptxfee"]));
+ return InitError(AmountErrMsg("maxtxfee", mapArgs["-maptxfee"]));
if (nMaxFee > nHighTransactionMaxFeeWarning)
InitWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
maxTxFee = nMaxFee;
@@ -1188,13 +1200,13 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-bind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, GetListenPort(), false))
- return InitError(strprintf(_("Cannot resolve -bind address: '%s'"), strBind));
+ return InitError(ResolveErrMsg("bind", strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
BOOST_FOREACH(const std::string& strBind, mapMultiArgs["-whitebind"]) {
CService addrBind;
if (!Lookup(strBind.c_str(), addrBind, 0, false))
- return InitError(strprintf(_("Cannot resolve -whitebind address: '%s'"), strBind));
+ return InitError(ResolveErrMsg("whitebind", strBind));
if (addrBind.GetPort() == 0)
return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR | BF_WHITELIST));
@@ -1214,7 +1226,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-externalip"]) {
CService addrLocal(strAddr, GetListenPort(), fNameLookup);
if (!addrLocal.IsValid())
- return InitError(strprintf(_("Cannot resolve -externalip address: '%s'"), strAddr));
+ return InitError(ResolveErrMsg("externalip", strAddr));
AddLocal(CService(strAddr, GetListenPort(), fNameLookup), LOCAL_MANUAL);
}
}
diff --git a/src/main.cpp b/src/main.cpp
index c058843ae3..06374cc1b6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -69,6 +69,7 @@ bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
+unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
size_t nCoinCacheUsage = 5000 * 300;
@@ -929,16 +930,8 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
if (fRequireStandard && !AreInputsStandard(tx, view))
return state.Invalid(false, REJECT_NONSTANDARD, "bad-txns-nonstandard-inputs");
- // Check that the transaction doesn't have an excessive number of
- // sigops, making it impossible to mine. Since the coinbase transaction
- // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
- // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
- // merely non-standard transaction.
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
- if (nSigOps > MAX_STANDARD_TX_SIGOPS)
- return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
- strprintf("%d > %d", nSigOps, MAX_STANDARD_TX_SIGOPS));
CAmount nValueOut = tx.GetValueOut();
CAmount nFees = nValueIn-nValueOut;
@@ -964,6 +957,15 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState &state, const C
CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), pool.HasNoInputsOf(tx), inChainInputValue, fSpendsCoinbase, nSigOps);
unsigned int nSize = entry.GetTxSize();
+ // Check that the transaction doesn't have an excessive number of
+ // sigops, making it impossible to mine. Since the coinbase transaction
+ // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than
+ // MAX_BLOCK_SIGOPS; we still consider this an invalid rather than
+ // merely non-standard transaction.
+ if ((nSigOps > MAX_STANDARD_TX_SIGOPS) || (nBytesPerSigOp && nSigOps > nSize / nBytesPerSigOp))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false,
+ strprintf("%d", nSigOps));
+
CAmount mempoolRejectFee = pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(nSize);
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) {
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nFees, mempoolRejectFee));
diff --git a/src/main.h b/src/main.h
index cadd281c89..cefaedabf5 100644
--- a/src/main.h
+++ b/src/main.h
@@ -100,6 +100,7 @@ static const bool DEFAULT_RELAYPRIORITY = true;
/** Default for -permitbaremultisig */
static const bool DEFAULT_PERMIT_BAREMULTISIG = true;
+static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
static const bool DEFAULT_TXINDEX = false;
static const unsigned int DEFAULT_BANSCORE_THRESHOLD = 100;
@@ -130,6 +131,7 @@ extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
extern bool fRequireStandard;
+extern unsigned int nBytesPerSigOp;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
extern size_t nCoinCacheUsage;
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
index 273a482fa1..019df72279 100644
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -23,9 +23,6 @@
* 2. P2SH scripts with a crazy number of expensive
* CHECKSIG/CHECKMULTISIG operations
*
- * Check transaction inputs, and make sure any
- * pay-to-script-hash transactions are evaluating IsStandard scripts
- *
* Why bother? To avoid denial-of-service attacks; an attacker
* can submit a standard HASH... OP_EQUAL transaction,
* which will get accepted into blocks. The redemption
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index e0b84ba13f..f324c6dc5a 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -15,9 +15,15 @@
#include <QSettings>
#include <QMessageBox>
-/* Minimum free space (in bytes) needed for data directory */
+#include <cmath>
+
static const uint64_t GB_BYTES = 1000000000LL;
-static const uint64_t BLOCK_CHAIN_SIZE = 20LL * GB_BYTES;
+/* Minimum free space (in GB) needed for data directory */
+static const uint64_t BLOCK_CHAIN_SIZE = 80;
+/* Minimum free space (in GB) needed for data directory when pruned; Does not include prune target */
+static const uint64_t CHAIN_STATE_SIZE = 2;
+/* Total required space (in GB) depending on user choice (prune, not prune) */
+static uint64_t requiredSpace;
/* Check free space asynchronously to prevent hanging the UI thread.
@@ -112,7 +118,11 @@ Intro::Intro(QWidget *parent) :
signalled(false)
{
ui->setupUi(this);
- ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE/GB_BYTES));
+ uint64_t pruneTarget = std::max<int64_t>(0, GetArg("-prune", 0));
+ requiredSpace = BLOCK_CHAIN_SIZE;
+ if (pruneTarget)
+ requiredSpace = CHAIN_STATE_SIZE + std::ceil(pruneTarget * 1024 * 1024.0 / GB_BYTES);
+ ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(requiredSpace));
startThread();
}
@@ -216,9 +226,9 @@ void Intro::setStatus(int status, const QString &message, quint64 bytesAvailable
ui->freeSpace->setText("");
} else {
QString freeString = tr("%n GB of free space available", "", bytesAvailable/GB_BYTES);
- if(bytesAvailable < BLOCK_CHAIN_SIZE)
+ if(bytesAvailable < requiredSpace * GB_BYTES)
{
- freeString += " " + tr("(of %n GB needed)", "", BLOCK_CHAIN_SIZE/GB_BYTES);
+ freeString += " " + tr("(of %n GB needed)", "", requiredSpace);
ui->freeSpace->setStyleSheet("QLabel { color: #800000 }");
} else {
ui->freeSpace->setStyleSheet("");
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 4c869b9ac5..7178bc00e6 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -278,7 +278,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
#endif
// Register RPC timer interface
rpcTimerInterface = new QtRPCTimerInterface();
- RPCRegisterTimerInterface(rpcTimerInterface);
+ // avoid accidentally overwriting an existing, non QTThread
+ // based timer interface
+ RPCSetTimerInterfaceIfUnset(rpcTimerInterface);
startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
@@ -293,7 +295,7 @@ RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
Q_EMIT stopExecutor();
- RPCUnregisterTimerInterface(rpcTimerInterface);
+ RPCUnsetTimerInterface(rpcTimerInterface);
delete rpcTimerInterface;
delete ui;
}
diff --git a/src/reverselock.h b/src/reverselock.h
index 567636e16a..fac1ccb793 100644
--- a/src/reverselock.h
+++ b/src/reverselock.h
@@ -15,10 +15,12 @@ public:
explicit reverse_lock(Lock& lock) : lock(lock) {
lock.unlock();
+ lock.swap(templock);
}
~reverse_lock() {
- lock.lock();
+ templock.lock();
+ templock.swap(lock);
}
private:
@@ -26,6 +28,7 @@ private:
reverse_lock& operator=(reverse_lock const&);
Lock& lock;
+ Lock templock;
};
#endif // BITCOIN_REVERSELOCK_H
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index bc419d14d9..78d6898bc3 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -33,7 +33,7 @@ static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
-static std::vector<RPCTimerInterface*> timerInterfaces;
+static RPCTimerInterface* timerInterface = NULL;
/* Map of name to timer.
* @note Can be changed to std::unique_ptr when C++11 */
static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
@@ -546,24 +546,28 @@ std::string HelpExampleRpc(const std::string& methodname, const std::string& arg
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
-void RPCRegisterTimerInterface(RPCTimerInterface *iface)
+void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{
- timerInterfaces.push_back(iface);
+ if (!timerInterface)
+ timerInterface = iface;
}
-void RPCUnregisterTimerInterface(RPCTimerInterface *iface)
+void RPCSetTimerInterface(RPCTimerInterface *iface)
{
- std::vector<RPCTimerInterface*>::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface);
- assert(i != timerInterfaces.end());
- timerInterfaces.erase(i);
+ timerInterface = iface;
+}
+
+void RPCUnsetTimerInterface(RPCTimerInterface *iface)
+{
+ if (timerInterface == iface)
+ timerInterface = NULL;
}
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
{
- if (timerInterfaces.empty())
+ if (!timerInterface)
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
deadlineTimers.erase(name);
- RPCTimerInterface* timerInterface = timerInterfaces[0];
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}
diff --git a/src/rpcserver.h b/src/rpcserver.h
index f85ab42f02..9dce318872 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -100,10 +100,12 @@ public:
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
};
-/** Register factory function for timers */
-void RPCRegisterTimerInterface(RPCTimerInterface *iface);
-/** Unregister factory function for timers */
-void RPCUnregisterTimerInterface(RPCTimerInterface *iface);
+/** Set the factory function for timers */
+void RPCSetTimerInterface(RPCTimerInterface *iface);
+/** Set the factory function for timer, but only, if unset */
+void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
+/** Unset factory function for timers */
+void RPCUnsetTimerInterface(RPCTimerInterface *iface);
/**
* Run func nSeconds from now.
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
index e7e627ae0f..8bdff97000 100644
--- a/src/test/reverselock_tests.cpp
+++ b/src/test/reverselock_tests.cpp
@@ -42,22 +42,18 @@ BOOST_AUTO_TEST_CASE(reverselock_errors)
BOOST_CHECK(failed);
BOOST_CHECK(!lock.owns_lock());
- // Make sure trying to lock a lock after it has been reverse locked fails
- failed = false;
- bool locked = false;
+ // Locking the original lock after it has been taken by a reverse lock
+ // makes no sense. Ensure that the original lock no longer owns the lock
+ // after giving it to a reverse one.
lock.lock();
BOOST_CHECK(lock.owns_lock());
-
- try {
+ {
reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
- lock.lock();
- locked = true;
- } catch(...) {
- failed = true;
+ BOOST_CHECK(!lock.owns_lock());
}
- BOOST_CHECK(locked && failed);
+ BOOST_CHECK(failed);
BOOST_CHECK(lock.owns_lock());
}
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index f03cb4896c..e84d588026 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -328,7 +328,7 @@ BOOST_AUTO_TEST_CASE(coin_selection_tests)
empty_wallet();
}
-BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
+BOOST_AUTO_TEST_CASE(ApproximateBestSubset)
{
CoinSet setCoinsRet;
CAmount nValueRet;
@@ -336,15 +336,28 @@ BOOST_AUTO_TEST_CASE(pruning_in_ApproximateBestSet)
LOCK(wallet.cs_wallet);
empty_wallet();
+
+ // Test vValue sort order
+ for (int i = 0; i < 1000; i++)
+ add_coin(1000 * COIN);
+ add_coin(3 * COIN);
+
+ BOOST_CHECK(wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK_EQUAL(nValueRet, 1003 * COIN);
+ BOOST_CHECK_EQUAL(setCoinsRet.size(), 2U);
+
+ empty_wallet();
+
+ // Test trimming
for (int i = 0; i < 100; i++)
- add_coin(10 * CENT);
+ add_coin(10 * COIN);
for (int i = 0; i < 100; i++)
- add_coin(1000 * CENT);
+ add_coin(1000 * COIN);
- BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * CENT, 1, 6, vCoins, setCoinsRet, nValueRet));
+ BOOST_CHECK(wallet.SelectCoinsMinConf(100001 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet));
// We need all 100 larger coins and exactly one small coin.
- // Superfluous small coins must be pruned:
- BOOST_CHECK_EQUAL(nValueRet, 100010 * CENT);
+ // Superfluous small coins must be trimmed from the set:
+ BOOST_CHECK_EQUAL(nValueRet, 100010 * COIN);
BOOST_CHECK_EQUAL(setCoinsRet.size(), 101);
}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 581c688fc7..6b2ebebba7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -817,6 +817,13 @@ void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx)
}
iter++;
}
+ // If a transaction changes 'conflicted' state, that changes the balance
+ // available of the outputs it spends. So force those to be recomputed
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ if (mapWallet.count(txin.prevout.hash))
+ mapWallet[txin.prevout.hash].MarkDirty();
+ }
}
}
}
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index ce57f4dae1..9bbd52f14c 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -61,7 +61,6 @@ static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWa
static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
static const bool DEFAULT_WALLETBROADCAST = true;
-class CAccountingEntry;
class CBlockIndex;
class CCoinControl;
class COutput;
@@ -447,6 +446,86 @@ public:
}
};
+/**
+ * Internal transfers.
+ * Database key is acentry<account><counter>.
+ */
+class CAccountingEntry
+{
+public:
+ std::string strAccount;
+ CAmount nCreditDebit;
+ int64_t nTime;
+ std::string strOtherAccount;
+ std::string strComment;
+ mapValue_t mapValue;
+ int64_t nOrderPos; //! position in ordered transaction list
+ uint64_t nEntryNo;
+
+ CAccountingEntry()
+ {
+ SetNull();
+ }
+
+ void SetNull()
+ {
+ nCreditDebit = 0;
+ nTime = 0;
+ strAccount.clear();
+ strOtherAccount.clear();
+ strComment.clear();
+ nOrderPos = -1;
+ nEntryNo = 0;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ if (!(nType & SER_GETHASH))
+ READWRITE(nVersion);
+ //! Note: strAccount is serialized as part of the key, not here.
+ READWRITE(nCreditDebit);
+ READWRITE(nTime);
+ READWRITE(LIMITED_STRING(strOtherAccount, 65536));
+
+ if (!ser_action.ForRead())
+ {
+ WriteOrderPos(nOrderPos, mapValue);
+
+ if (!(mapValue.empty() && _ssExtra.empty()))
+ {
+ CDataStream ss(nType, nVersion);
+ ss.insert(ss.begin(), '\0');
+ ss << mapValue;
+ ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
+ strComment.append(ss.str());
+ }
+ }
+
+ READWRITE(LIMITED_STRING(strComment, 65536));
+
+ size_t nSepPos = strComment.find("\0", 0, 1);
+ if (ser_action.ForRead())
+ {
+ mapValue.clear();
+ if (std::string::npos != nSepPos)
+ {
+ CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
+ ss >> mapValue;
+ _ssExtra = std::vector<char>(ss.begin(), ss.end());
+ }
+ ReadOrderPos(nOrderPos, mapValue);
+ }
+ if (std::string::npos != nSepPos)
+ strComment.erase(nSepPos);
+
+ mapValue.erase("n");
+ }
+
+private:
+ std::vector<char> _ssExtra;
+};
/**
@@ -843,87 +922,4 @@ public:
}
};
-
-
-/**
- * Internal transfers.
- * Database key is acentry<account><counter>.
- */
-class CAccountingEntry
-{
-public:
- std::string strAccount;
- CAmount nCreditDebit;
- int64_t nTime;
- std::string strOtherAccount;
- std::string strComment;
- mapValue_t mapValue;
- int64_t nOrderPos; //! position in ordered transaction list
- uint64_t nEntryNo;
-
- CAccountingEntry()
- {
- SetNull();
- }
-
- void SetNull()
- {
- nCreditDebit = 0;
- nTime = 0;
- strAccount.clear();
- strOtherAccount.clear();
- strComment.clear();
- nOrderPos = -1;
- nEntryNo = 0;
- }
-
- ADD_SERIALIZE_METHODS;
-
- template <typename Stream, typename Operation>
- inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
- if (!(nType & SER_GETHASH))
- READWRITE(nVersion);
- //! Note: strAccount is serialized as part of the key, not here.
- READWRITE(nCreditDebit);
- READWRITE(nTime);
- READWRITE(LIMITED_STRING(strOtherAccount, 65536));
-
- if (!ser_action.ForRead())
- {
- WriteOrderPos(nOrderPos, mapValue);
-
- if (!(mapValue.empty() && _ssExtra.empty()))
- {
- CDataStream ss(nType, nVersion);
- ss.insert(ss.begin(), '\0');
- ss << mapValue;
- ss.insert(ss.end(), _ssExtra.begin(), _ssExtra.end());
- strComment.append(ss.str());
- }
- }
-
- READWRITE(LIMITED_STRING(strComment, 65536));
-
- size_t nSepPos = strComment.find("\0", 0, 1);
- if (ser_action.ForRead())
- {
- mapValue.clear();
- if (std::string::npos != nSepPos)
- {
- CDataStream ss(std::vector<char>(strComment.begin() + nSepPos + 1, strComment.end()), nType, nVersion);
- ss >> mapValue;
- _ssExtra = std::vector<char>(ss.begin(), ss.end());
- }
- ReadOrderPos(nOrderPos, mapValue);
- }
- if (std::string::npos != nSepPos)
- strComment.erase(nSepPos);
-
- mapValue.erase("n");
- }
-
-private:
- std::vector<char> _ssExtra;
-};
-
#endif // BITCOIN_WALLET_WALLET_H
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 88dc3102da..5266946ca0 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -15,6 +15,12 @@
#include "utiltime.h"
#include "wallet/wallet.h"
+#if defined(FORCE_BOOST_EMULATED_SCOPED_ENUMS)
+#define BOOST_NO_SCOPED_ENUMS
+#define BOOST_NO_CXX11_SCOPED_ENUMS
+#endif
+
+#include <boost/version.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <boost/scoped_ptr.hpp>
@@ -960,8 +966,13 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
CDataStream ssKey(row.first, SER_DISK, CLIENT_VERSION);
CDataStream ssValue(row.second, SER_DISK, CLIENT_VERSION);
string strType, strErr;
- bool fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
+ bool fReadOK;
+ {
+ // Required in LoadKeyMetadata():
+ LOCK(dummyWallet.cs_wallet);
+ fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue,
wss, strType, strErr);
+ }
if (!IsKeyType(strType))
continue;
if (!fReadOK)