aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am113
-rw-r--r--src/Makefile.qt.include16
-rw-r--r--src/Makefile.qttest.include6
-rw-r--r--src/Makefile.test.include11
-rw-r--r--src/addrman.cpp20
-rw-r--r--src/addrman.h12
-rw-r--r--src/alert.cpp5
-rw-r--r--src/alert.h2
-rw-r--r--src/amount.cpp4
-rw-r--r--src/amount.h12
-rw-r--r--src/base58.h9
-rw-r--r--src/bitcoin-cli-res.rc4
-rw-r--r--src/bitcoin-cli.cpp189
-rw-r--r--src/bitcoin-tx-res.rc35
-rw-r--r--src/bitcoin-tx.cpp44
-rw-r--r--src/bitcoind-res.rc4
-rw-r--r--src/bitcoind.cpp15
-rw-r--r--src/bloom.cpp34
-rw-r--r--src/bloom.h16
-rw-r--r--src/chain.cpp7
-rw-r--r--src/chainparams.cpp114
-rw-r--r--src/chainparams.h22
-rw-r--r--src/chainparamsbase.cpp5
-rw-r--r--src/chainparamsseeds.h1273
-rw-r--r--src/checkpoints.cpp10
-rw-r--r--src/checkpoints.h12
-rw-r--r--src/clientversion.h2
-rw-r--r--src/coincontrol.h8
-rw-r--r--src/coins.cpp24
-rw-r--r--src/coins.h20
-rw-r--r--src/compat.h8
-rw-r--r--src/compat/endian.h2
-rw-r--r--src/consensus/consensus.h2
-rw-r--r--src/consensus/validation.h85
-rw-r--r--src/core_io.h2
-rw-r--r--src/core_memusage.h62
-rw-r--r--src/core_read.cpp2
-rw-r--r--src/ecwrapper.cpp33
-rw-r--r--src/httprpc.cpp193
-rw-r--r--src/httprpc.h37
-rw-r--r--src/httpserver.cpp594
-rw-r--r--src/httpserver.h149
-rw-r--r--src/init.cpp517
-rw-r--r--src/init.h5
-rw-r--r--src/json/LICENSE.txt24
-rw-r--r--src/json/json_spirit.h18
-rw-r--r--src/json/json_spirit_error_position.h54
-rw-r--r--src/json/json_spirit_reader.cpp137
-rw-r--r--src/json/json_spirit_reader.h62
-rw-r--r--src/json/json_spirit_reader_template.h612
-rw-r--r--src/json/json_spirit_stream_reader.h70
-rw-r--r--src/json/json_spirit_utils.h61
-rw-r--r--src/json/json_spirit_value.cpp8
-rw-r--r--src/json/json_spirit_value.h534
-rw-r--r--src/json/json_spirit_writer.cpp95
-rw-r--r--src/json/json_spirit_writer.h50
-rw-r--r--src/json/json_spirit_writer_template.h249
-rw-r--r--src/keystore.cpp41
-rw-r--r--src/keystore.h5
-rw-r--r--src/leveldbwrapper.cpp3
-rw-r--r--src/limitedmap.h19
-rw-r--r--src/main.cpp963
-rw-r--r--src/main.h193
-rw-r--r--src/memusage.h124
-rw-r--r--src/merkleblock.cpp2
-rw-r--r--src/miner.cpp99
-rw-r--r--src/miner.h8
-rw-r--r--src/net.cpp602
-rw-r--r--src/net.h113
-rw-r--r--src/netbase.cpp101
-rw-r--r--src/netbase.h15
-rw-r--r--src/policy/fees.cpp530
-rw-r--r--src/policy/fees.h276
-rw-r--r--src/policy/policy.cpp178
-rw-r--r--src/policy/policy.h58
-rw-r--r--src/primitives/transaction.h7
-rw-r--r--src/protocol.h4
-rw-r--r--src/qt/addressbookpage.cpp29
-rw-r--r--src/qt/addressbookpage.h9
-rw-r--r--src/qt/addresstablemodel.cpp2
-rw-r--r--src/qt/addresstablemodel.h2
-rw-r--r--src/qt/askpassphrasedialog.h2
-rw-r--r--src/qt/bantablemodel.cpp181
-rw-r--r--src/qt/bantablemodel.h72
-rw-r--r--src/qt/bitcoin.cpp73
-rw-r--r--src/qt/bitcoin.qrc1
-rw-r--r--src/qt/bitcoinamountfield.cpp4
-rw-r--r--src/qt/bitcoinamountfield.h4
-rw-r--r--src/qt/bitcoingui.cpp86
-rw-r--r--src/qt/bitcoingui.h17
-rw-r--r--src/qt/bitcoinstrings.cpp1
-rw-r--r--src/qt/clientmodel.cpp43
-rw-r--r--src/qt/clientmodel.h9
-rw-r--r--src/qt/coincontroldialog.cpp40
-rw-r--r--src/qt/coincontroldialog.h7
-rw-r--r--src/qt/editaddressdialog.h2
-rw-r--r--src/qt/forms/optionsdialog.ui189
-rw-r--r--src/qt/forms/overviewpage.ui64
-rw-r--r--src/qt/forms/rpcconsole.ui278
-rw-r--r--src/qt/forms/sendcoinsentry.ui33
-rw-r--r--src/qt/guiconstants.h2
-rw-r--r--src/qt/guiutil.cpp17
-rw-r--r--src/qt/guiutil.h12
-rw-r--r--src/qt/intro.cpp13
-rw-r--r--src/qt/intro.h6
-rw-r--r--src/qt/locale/bitcoin_ar.ts6
-rw-r--r--src/qt/locale/bitcoin_be_BY.ts618
-rw-r--r--src/qt/locale/bitcoin_bg.ts202
-rw-r--r--src/qt/locale/bitcoin_ca.ts4
-rw-r--r--src/qt/locale/bitcoin_ca@valencia.ts4
-rw-r--r--src/qt/locale/bitcoin_ca_ES.ts4
-rw-r--r--src/qt/locale/bitcoin_cs.ts4
-rw-r--r--src/qt/locale/bitcoin_da.ts12
-rw-r--r--src/qt/locale/bitcoin_de.ts172
-rw-r--r--src/qt/locale/bitcoin_el_GR.ts228
-rw-r--r--src/qt/locale/bitcoin_en.ts83
-rw-r--r--src/qt/locale/bitcoin_eo.ts6
-rw-r--r--src/qt/locale/bitcoin_es.ts4
-rw-r--r--src/qt/locale/bitcoin_es_CL.ts6
-rw-r--r--src/qt/locale/bitcoin_es_DO.ts6
-rw-r--r--src/qt/locale/bitcoin_et.ts6
-rw-r--r--src/qt/locale/bitcoin_fa.ts82
-rw-r--r--src/qt/locale/bitcoin_fa_IR.ts6
-rw-r--r--src/qt/locale/bitcoin_fi.ts4
-rw-r--r--src/qt/locale/bitcoin_fr.ts8
-rw-r--r--src/qt/locale/bitcoin_gl.ts6
-rw-r--r--src/qt/locale/bitcoin_he.ts4
-rw-r--r--src/qt/locale/bitcoin_hu.ts6
-rw-r--r--src/qt/locale/bitcoin_id_ID.ts6
-rw-r--r--src/qt/locale/bitcoin_it.ts226
-rw-r--r--src/qt/locale/bitcoin_ja.ts238
-rw-r--r--src/qt/locale/bitcoin_ka.ts6
-rw-r--r--src/qt/locale/bitcoin_ko_KR.ts6
-rw-r--r--src/qt/locale/bitcoin_ky.ts6
-rw-r--r--src/qt/locale/bitcoin_la.ts6
-rw-r--r--src/qt/locale/bitcoin_lt.ts6
-rw-r--r--src/qt/locale/bitcoin_lv_LV.ts6
-rw-r--r--src/qt/locale/bitcoin_nb.ts148
-rw-r--r--src/qt/locale/bitcoin_nl.ts76
-rw-r--r--src/qt/locale/bitcoin_pam.ts6
-rw-r--r--src/qt/locale/bitcoin_pl.ts6
-rw-r--r--src/qt/locale/bitcoin_pt_BR.ts42
-rw-r--r--src/qt/locale/bitcoin_pt_PT.ts4
-rw-r--r--src/qt/locale/bitcoin_ro_RO.ts106
-rw-r--r--src/qt/locale/bitcoin_ru.ts4
-rw-r--r--src/qt/locale/bitcoin_sk.ts6
-rw-r--r--src/qt/locale/bitcoin_sl_SI.ts6
-rw-r--r--src/qt/locale/bitcoin_sv.ts8
-rw-r--r--src/qt/locale/bitcoin_tr.ts246
-rw-r--r--src/qt/locale/bitcoin_uk.ts8
-rw-r--r--src/qt/locale/bitcoin_zh_CN.ts20
-rw-r--r--src/qt/locale/bitcoin_zh_TW.ts4
-rw-r--r--src/qt/macdockiconhandler.h2
-rw-r--r--src/qt/macdockiconhandler.mm2
-rw-r--r--src/qt/networkstyle.cpp1
-rw-r--r--src/qt/notificator.h2
-rw-r--r--src/qt/openuridialog.h4
-rw-r--r--src/qt/optionsdialog.cpp59
-rw-r--r--src/qt/optionsdialog.h8
-rw-r--r--src/qt/optionsmodel.cpp65
-rw-r--r--src/qt/optionsmodel.h5
-rw-r--r--src/qt/overviewpage.cpp29
-rw-r--r--src/qt/overviewpage.h9
-rw-r--r--src/qt/paymentrequestplus.cpp4
-rw-r--r--src/qt/paymentserver.cpp98
-rw-r--r--src/qt/paymentserver.h12
-rw-r--r--src/qt/peertablemodel.cpp28
-rw-r--r--src/qt/peertablemodel.h4
-rw-r--r--src/qt/platformstyle.cpp147
-rw-r--r--src/qt/platformstyle.h55
-rw-r--r--src/qt/qvalidatedlineedit.h4
-rw-r--r--src/qt/qvaluecombobox.cpp2
-rw-r--r--src/qt/qvaluecombobox.h4
-rw-r--r--src/qt/receivecoinsdialog.cpp34
-rw-r--r--src/qt/receivecoinsdialog.h9
-rw-r--r--src/qt/receiverequestdialog.h4
-rw-r--r--src/qt/recentrequeststablemodel.cpp4
-rw-r--r--src/qt/recentrequeststablemodel.h2
-rw-r--r--src/qt/res/bitcoin-qt-res.rc2
-rw-r--r--src/qt/res/icons/about_qt.pngbin2338 -> 2240 bytes
-rw-r--r--src/qt/res/icons/clock1.pngbin1921 -> 2618 bytes
-rw-r--r--src/qt/res/icons/clock2.pngbin1731 -> 2398 bytes
-rw-r--r--src/qt/res/icons/clock3.pngbin1557 -> 2055 bytes
-rw-r--r--src/qt/res/icons/clock4.pngbin1395 -> 1909 bytes
-rw-r--r--src/qt/res/icons/clock5.pngbin1889 -> 1659 bytes
-rw-r--r--src/qt/res/icons/connect0.pngbin2290 -> 2446 bytes
-rw-r--r--src/qt/res/icons/connect1.pngbin2242 -> 2163 bytes
-rw-r--r--src/qt/res/icons/connect2.pngbin1966 -> 1927 bytes
-rw-r--r--src/qt/res/icons/connect3.pngbin1966 -> 1750 bytes
-rw-r--r--src/qt/res/icons/connect4.pngbin1490 -> 1548 bytes
-rw-r--r--src/qt/res/icons/transaction0.pngbin1220 -> 1310 bytes
-rw-r--r--src/qt/res/icons/warning.pngbin0 -> 2801 bytes
-rwxr-xr-xsrc/qt/res/movies/makespinner.sh7
-rw-r--r--src/qt/res/movies/spinner-000.pngbin1835 -> 1794 bytes
-rw-r--r--src/qt/res/src/clock_1.svg4
-rw-r--r--src/qt/res/src/clock_2.svg3
-rw-r--r--src/qt/res/src/clock_3.svg6
-rw-r--r--src/qt/res/src/clock_4.svg41
-rw-r--r--src/qt/res/src/connect-0.svg77
-rw-r--r--src/qt/res/src/connect-1.svg90
-rw-r--r--src/qt/res/src/connect-2.svg81
-rw-r--r--src/qt/res/src/connect-3.svg88
-rw-r--r--src/qt/res/src/connect-4.svg65
-rw-r--r--src/qt/res/src/qt.svg51
-rw-r--r--src/qt/res/src/spinner.png (renamed from src/qt/res/spinner.png)bin16636 -> 16636 bytes
-rw-r--r--src/qt/res/src/transaction0.svg35
-rw-r--r--src/qt/rpcconsole.cpp307
-rw-r--r--src/qt/rpcconsole.h38
-rw-r--r--src/qt/scicon.cpp84
-rw-r--r--src/qt/scicon.h24
-rw-r--r--src/qt/sendcoinsdialog.cpp45
-rw-r--r--src/qt/sendcoinsdialog.h12
-rw-r--r--src/qt/sendcoinsentry.cpp26
-rw-r--r--src/qt/sendcoinsentry.h10
-rw-r--r--src/qt/signverifymessagedialog.cpp35
-rw-r--r--src/qt/signverifymessagedialog.h6
-rw-r--r--src/qt/splashscreen.cpp2
-rw-r--r--src/qt/splashscreen.h2
-rw-r--r--src/qt/test/paymentservertests.cpp5
-rw-r--r--src/qt/test/paymentservertests.h4
-rw-r--r--src/qt/test/test_main.cpp4
-rw-r--r--src/qt/test/uritests.h2
-rw-r--r--src/qt/trafficgraphwidget.cpp4
-rw-r--r--src/qt/trafficgraphwidget.h2
-rw-r--r--src/qt/transactiondesc.cpp12
-rw-r--r--src/qt/transactionrecord.cpp8
-rw-r--r--src/qt/transactiontablemodel.cpp21
-rw-r--r--src/qt/transactiontablemodel.h6
-rw-r--r--src/qt/transactionview.cpp67
-rw-r--r--src/qt/transactionview.h9
-rw-r--r--src/qt/utilitydialog.cpp2
-rw-r--r--src/qt/utilitydialog.h2
-rw-r--r--src/qt/walletframe.cpp7
-rw-r--r--src/qt/walletframe.h7
-rw-r--r--src/qt/walletmodel.cpp29
-rw-r--r--src/qt/walletmodel.h8
-rw-r--r--src/qt/walletmodeltransaction.cpp2
-rw-r--r--src/qt/walletview.cpp54
-rw-r--r--src/qt/walletview.h11
-rw-r--r--src/rest.cpp444
-rw-r--r--src/reverselock.h31
-rw-r--r--src/rpcblockchain.cpp327
-rw-r--r--src/rpcclient.cpp39
-rw-r--r--src/rpcclient.h10
-rw-r--r--src/rpcmining.cpp143
-rw-r--r--src/rpcmisc.cpp89
-rw-r--r--src/rpcnet.cpp223
-rw-r--r--src/rpcprotocol.cpp315
-rw-r--r--src/rpcprotocol.h109
-rw-r--r--src/rpcrawtransaction.cpp171
-rw-r--r--src/rpcserver.cpp702
-rw-r--r--src/rpcserver.h308
-rw-r--r--src/scheduler.cpp131
-rw-r--r--src/scheduler.h83
-rw-r--r--src/script/interpreter.cpp83
-rw-r--r--src/script/interpreter.h11
-rw-r--r--src/script/script.h24
-rw-r--r--src/script/script_error.cpp4
-rw-r--r--src/script/script_error.h4
-rw-r--r--src/script/sign.cpp39
-rw-r--r--src/script/sign.h8
-rw-r--r--src/script/standard.cpp25
-rw-r--r--src/script/standard.h18
-rw-r--r--src/serialize.h4
-rw-r--r--src/support/pagelocker.h1
-rw-r--r--src/sync.cpp49
-rw-r--r--src/sync.h10
-rw-r--r--src/test/Checkpoints_tests.cpp18
-rw-r--r--src/test/DoS_tests.cpp5
-rw-r--r--src/test/README.md14
-rw-r--r--src/test/alert_tests.cpp70
-rw-r--r--src/test/base58_tests.cpp58
-rw-r--r--src/test/bip32_tests.cpp11
-rw-r--r--src/test/bloom_tests.cpp6
-rw-r--r--src/test/checkblock_tests.cpp12
-rw-r--r--src/test/coins_tests.cpp27
-rw-r--r--src/test/data/bitcoin-util-test.json32
-rw-r--r--src/test/data/tx_invalid.json72
-rw-r--r--src/test/data/tx_valid.json42
-rw-r--r--src/test/data/txcreatedata1.hex1
-rw-r--r--src/test/data/txcreatedata2.hex1
-rw-r--r--src/test/data/txcreatesign.hex2
-rw-r--r--src/test/getarg_tests.cpp22
-rw-r--r--src/test/limitedmap_tests.cpp101
-rw-r--r--src/test/main_tests.cpp39
-rw-r--r--src/test/mempool_tests.cpp182
-rw-r--r--src/test/miner_tests.cpp19
-rw-r--r--src/test/multisig_tests.cpp2
-rw-r--r--src/test/netbase_tests.cpp111
-rw-r--r--src/test/policyestimator_tests.cpp186
-rw-r--r--src/test/pow_tests.cpp4
-rw-r--r--src/test/reverselock_tests.cpp64
-rw-r--r--src/test/rpc_tests.cpp218
-rw-r--r--src/test/rpc_wallet_tests.cpp60
-rw-r--r--src/test/scheduler_tests.cpp119
-rw-r--r--src/test/script_P2SH_tests.cpp1
-rw-r--r--src/test/script_tests.cpp58
-rw-r--r--src/test/scriptnum_tests.cpp2
-rw-r--r--src/test/sighash_tests.cpp29
-rw-r--r--src/test/skiplist_tests.cpp2
-rw-r--r--src/test/test_bitcoin.cpp58
-rw-r--r--src/test/test_bitcoin.h28
-rw-r--r--src/test/transaction_tests.cpp63
-rw-r--r--src/test/txvalidationcache_tests.cpp86
-rw-r--r--src/test/univalue_tests.cpp81
-rw-r--r--src/test/util_tests.cpp179
-rw-r--r--src/timedata.cpp6
-rw-r--r--src/txdb.cpp6
-rw-r--r--src/txdb.h2
-rw-r--r--src/txmempool.cpp812
-rw-r--r--src/txmempool.h334
-rw-r--r--src/ui_interface.h3
-rw-r--r--src/univalue/gen.cpp1
-rw-r--r--src/univalue/univalue.cpp106
-rw-r--r--src/univalue/univalue.h99
-rw-r--r--src/univalue/univalue_escapes.h2
-rw-r--r--src/univalue/univalue_read.cpp29
-rw-r--r--src/univalue/univalue_write.cpp2
-rw-r--r--src/util.cpp195
-rw-r--r--src/util.h48
-rw-r--r--src/utilmoneystr.cpp4
-rw-r--r--src/utilmoneystr.h2
-rw-r--r--src/utilstrencodings.cpp183
-rw-r--r--src/utilstrencodings.h41
-rw-r--r--src/validationinterface.cpp12
-rw-r--r--src/validationinterface.h26
-rw-r--r--src/version.h5
-rw-r--r--src/wallet/crypter.cpp6
-rw-r--r--src/wallet/db.cpp12
-rw-r--r--src/wallet/db.h7
-rw-r--r--src/wallet/rpcdump.cpp180
-rw-r--r--src/wallet/rpcwallet.cpp435
-rw-r--r--src/wallet/wallet.cpp190
-rw-r--r--src/wallet/wallet.h32
-rw-r--r--src/wallet/wallet_ismine.cpp10
-rw-r--r--src/wallet/wallet_ismine.h11
-rw-r--r--src/wallet/walletdb.cpp6
-rw-r--r--src/wallet/walletdb.h1
-rw-r--r--src/zmq/zmqabstractnotifier.cpp22
-rw-r--r--src/zmq/zmqabstractnotifier.h42
-rw-r--r--src/zmq/zmqconfig.h24
-rw-r--r--src/zmq/zmqnotificationinterface.cpp155
-rw-r--r--src/zmq/zmqnotificationinterface.h35
-rw-r--r--src/zmq/zmqpublishnotifier.cpp172
-rw-r--r--src/zmq/zmqpublishnotifier.h41
345 files changed, 16237 insertions, 7485 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 72d79619b2..67e848be39 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -14,7 +14,7 @@ $(LIBLEVELDB): $(LIBMEMENV)
$(LIBLEVELDB) $(LIBMEMENV):
@echo "Building LevelDB ..." && $(MAKE) -C $(@D) $(@F) CXX="$(CXX)" \
CC="$(CC)" PLATFORM=$(TARGET_OS) AR="$(AR)" $(LEVELDB_TARGET_FLAGS) \
- OPT="$(CXXFLAGS) $(CPPFLAGS)"
+ OPT="$(CXXFLAGS) $(CPPFLAGS) -D__STDC_LIMIT_MACROS"
endif
BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config
@@ -48,6 +48,9 @@ if ENABLE_WALLET
BITCOIN_INCLUDES += $(BDB_CPPFLAGS)
EXTRA_LIBRARIES += libbitcoin_wallet.a
endif
+if ENABLE_ZMQ
+EXTRA_LIBRARIES += libbitcoin_zmq.a
+endif
if BUILD_BITCOIN_LIBS
lib_LTLIBRARIES = libbitcoinconsensus.la
@@ -77,8 +80,8 @@ BITCOIN_CORE_H = \
base58.h \
bloom.h \
chain.h \
- chainparamsbase.h \
chainparams.h \
+ chainparamsbase.h \
chainparamsseeds.h \
checkpoints.h \
checkqueue.h \
@@ -86,38 +89,49 @@ BITCOIN_CORE_H = \
coincontrol.h \
coins.h \
compat.h \
+ compat/byteswap.h \
+ compat/endian.h \
+ compat/sanity.h \
compressor.h \
consensus/consensus.h \
consensus/params.h \
+ consensus/validation.h \
core_io.h \
- wallet/db.h \
+ core_memusage.h \
eccryptoverify.h \
ecwrapper.h \
hash.h \
+ httprpc.h \
+ httpserver.h \
init.h \
key.h \
keystore.h \
leveldbwrapper.h \
limitedmap.h \
main.h \
+ memusage.h \
merkleblock.h \
miner.h \
mruset.h \
- netbase.h \
net.h \
+ netbase.h \
noui.h \
+ policy/fees.h \
+ policy/policy.h \
pow.h \
primitives/block.h \
primitives/transaction.h \
protocol.h \
pubkey.h \
random.h \
+ reverselock.h \
rpcclient.h \
rpcprotocol.h \
rpcserver.h \
+ scheduler.h \
script/interpreter.h \
- script/script_error.h \
script/script.h \
+ script/script_error.h \
script/sigcache.h \
script/sign.h \
script/standard.h \
@@ -143,23 +157,15 @@ BITCOIN_CORE_H = \
validationinterface.h \
version.h \
wallet/crypter.h \
- wallet/walletdb.h \
+ wallet/db.h \
wallet/wallet.h \
wallet/wallet_ismine.h \
- compat/byteswap.h \
- compat/endian.h \
- compat/sanity.h
-
-JSON_H = \
- json/json_spirit.h \
- json/json_spirit_error_position.h \
- json/json_spirit_reader.h \
- json/json_spirit_reader_template.h \
- json/json_spirit_stream_reader.h \
- json/json_spirit_utils.h \
- json/json_spirit_value.h \
- json/json_spirit_writer.h \
- json/json_spirit_writer_template.h
+ wallet/walletdb.h \
+ zmq/zmqabstractnotifier.h \
+ zmq/zmqconfig.h\
+ zmq/zmqnotificationinterface.h \
+ zmq/zmqpublishnotifier.h
+
obj/build.h: FORCE
@$(MKDIR_P) $(builddir)/obj
@@ -168,13 +174,15 @@ obj/build.h: FORCE
libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
# server: shared between bitcoind and bitcoin-qt
-libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS)
+libbitcoin_server_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(MINIUPNPC_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_server_a_SOURCES = \
addrman.cpp \
alert.cpp \
bloom.cpp \
chain.cpp \
checkpoints.cpp \
+ httprpc.cpp \
+ httpserver.cpp \
init.cpp \
leveldbwrapper.cpp \
main.cpp \
@@ -182,6 +190,8 @@ libbitcoin_server_a_SOURCES = \
miner.cpp \
net.cpp \
noui.cpp \
+ policy/fees.cpp \
+ policy/policy.cpp \
pow.cpp \
rest.cpp \
rpcblockchain.cpp \
@@ -195,9 +205,19 @@ libbitcoin_server_a_SOURCES = \
txdb.cpp \
txmempool.cpp \
validationinterface.cpp \
- $(JSON_H) \
$(BITCOIN_CORE_H)
+if ENABLE_ZMQ
+LIBBITCOIN_ZMQ=libbitcoin_zmq.a
+
+libbitcoin_zmq_a_CPPFLAGS = $(BITCOIN_INCLUDES)
+libbitcoin_zmq_a_SOURCES = \
+ zmq/zmqabstractnotifier.cpp \
+ zmq/zmqnotificationinterface.cpp \
+ zmq/zmqpublishnotifier.cpp
+endif
+
+
# wallet: shared between bitcoind and bitcoin-qt, but only linked
# when wallet enabled
libbitcoin_wallet_a_CPPFLAGS = $(BITCOIN_INCLUDES)
@@ -214,39 +234,37 @@ libbitcoin_wallet_a_SOURCES = \
# crypto primitives library
crypto_libbitcoin_crypto_a_CPPFLAGS = $(BITCOIN_CONFIG_INCLUDES)
crypto_libbitcoin_crypto_a_SOURCES = \
- crypto/sha1.cpp \
- crypto/sha256.cpp \
- crypto/sha512.cpp \
- crypto/hmac_sha256.cpp \
- crypto/hmac_sha512.cpp \
- crypto/ripemd160.cpp \
crypto/common.h \
- crypto/sha256.h \
- crypto/sha512.h \
+ crypto/hmac_sha256.cpp \
crypto/hmac_sha256.h \
+ crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \
+ crypto/ripemd160.cpp \
+ crypto/ripemd160.h \
+ crypto/sha1.cpp \
crypto/sha1.h \
- crypto/ripemd160.h
+ crypto/sha256.cpp \
+ crypto/sha256.h \
+ crypto/sha512.cpp \
+ crypto/sha512.h
# univalue JSON library
univalue_libbitcoin_univalue_a_SOURCES = \
univalue/univalue.cpp \
- univalue/univalue_read.cpp \
- univalue/univalue_write.cpp \
+ univalue/univalue.h \
univalue/univalue_escapes.h \
- univalue/univalue.h
+ univalue/univalue_read.cpp \
+ univalue/univalue_write.cpp
# common: shared between bitcoind, and bitcoin-qt and non-server tools
libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES)
libbitcoin_common_a_SOURCES = \
- arith_uint256.cpp \
amount.cpp \
+ arith_uint256.cpp \
base58.cpp \
chainparams.cpp \
coins.cpp \
compressor.cpp \
- primitives/block.cpp \
- primitives/transaction.cpp \
core_read.cpp \
core_write.cpp \
eccryptoverify.cpp \
@@ -255,13 +273,16 @@ libbitcoin_common_a_SOURCES = \
key.cpp \
keystore.cpp \
netbase.cpp \
+ primitives/block.cpp \
+ primitives/transaction.cpp \
protocol.cpp \
pubkey.cpp \
+ scheduler.cpp \
script/interpreter.cpp \
script/script.cpp \
+ script/script_error.cpp \
script/sign.cpp \
script/standard.cpp \
- script/script_error.cpp \
$(BITCOIN_CORE_H)
# util: shared between all executables.
@@ -318,16 +339,19 @@ bitcoind_LDADD = \
$(LIBMEMENV) \
$(LIBSECP256K1)
+if ENABLE_ZMQ
+bitcoind_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
+endif
+
if ENABLE_WALLET
bitcoind_LDADD += libbitcoin_wallet.a
endif
-bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
-#
+bitcoind_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
# bitcoin-cli binary #
bitcoin_cli_SOURCES = bitcoin-cli.cpp
-bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES)
+bitcoin_cli_CPPFLAGS = $(BITCOIN_INCLUDES) $(EVENT_CFLAGS)
bitcoin_cli_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
if TARGET_WINDOWS
@@ -336,10 +360,11 @@ endif
bitcoin_cli_LDADD = \
$(LIBBITCOIN_CLI) \
+ $(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_UTIL) \
$(LIBSECP256K1)
-bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS)
+bitcoin_cli_LDADD += $(BOOST_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(EVENT_LIBS)
#
# bitcoin-tx binary #
@@ -347,6 +372,10 @@ bitcoin_tx_SOURCES = bitcoin-tx.cpp
bitcoin_tx_CPPFLAGS = $(BITCOIN_INCLUDES)
bitcoin_tx_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
+if TARGET_WINDOWS
+bitcoin_tx_SOURCES += bitcoin-tx-res.rc
+endif
+
bitcoin_tx_LDADD = \
$(LIBBITCOIN_UNIVALUE) \
$(LIBBITCOIN_COMMON) \
diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include
index 31fe3a9f69..480bd9dc8a 100644
--- a/src/Makefile.qt.include
+++ b/src/Makefile.qt.include
@@ -97,6 +97,7 @@ QT_MOC_CPP = \
qt/moc_addressbookpage.cpp \
qt/moc_addresstablemodel.cpp \
qt/moc_askpassphrasedialog.cpp \
+ qt/moc_bantablemodel.cpp \
qt/moc_bitcoinaddressvalidator.cpp \
qt/moc_bitcoinamountfield.cpp \
qt/moc_bitcoingui.cpp \
@@ -162,6 +163,7 @@ BITCOIN_QT_H = \
qt/addressbookpage.h \
qt/addresstablemodel.h \
qt/askpassphrasedialog.h \
+ qt/bantablemodel.h \
qt/bitcoinaddressvalidator.h \
qt/bitcoinamountfield.h \
qt/bitcoingui.h \
@@ -185,13 +187,13 @@ BITCOIN_QT_H = \
qt/paymentrequestplus.h \
qt/paymentserver.h \
qt/peertablemodel.h \
+ qt/platformstyle.h \
qt/qvalidatedlineedit.h \
qt/qvaluecombobox.h \
qt/receivecoinsdialog.h \
qt/receiverequestdialog.h \
qt/recentrequeststablemodel.h \
qt/rpcconsole.h \
- qt/scicon.h \
qt/sendcoinsdialog.h \
qt/sendcoinsentry.h \
qt/signverifymessagedialog.h \
@@ -256,9 +258,11 @@ RES_ICONS = \
qt/res/icons/tx_input.png \
qt/res/icons/tx_output.png \
qt/res/icons/tx_mined.png \
+ qt/res/icons/warning.png \
qt/res/icons/verify.png
BITCOIN_QT_CPP = \
+ qt/bantablemodel.cpp \
qt/bitcoinaddressvalidator.cpp \
qt/bitcoinamountfield.cpp \
qt/bitcoingui.cpp \
@@ -272,10 +276,10 @@ BITCOIN_QT_CPP = \
qt/optionsdialog.cpp \
qt/optionsmodel.cpp \
qt/peertablemodel.cpp \
+ qt/platformstyle.cpp \
qt/qvalidatedlineedit.cpp \
qt/qvaluecombobox.cpp \
qt/rpcconsole.cpp \
- qt/scicon.cpp \
qt/splashscreen.cpp \
qt/trafficgraphwidget.cpp \
qt/utilitydialog.cpp
@@ -321,7 +325,7 @@ RES_MOVIES = $(wildcard qt/res/movies/spinner-*.png)
BITCOIN_RC = qt/res/bitcoin-qt-res.rc
BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \
- -I$(builddir)/qt/forms
+ -I$(builddir)/qt/forms -DQT_NO_KEYWORDS
qt_libbitcoinqt_a_CPPFLAGS = $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \
$(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
@@ -360,8 +364,12 @@ qt_bitcoin_qt_LDADD = qt/libbitcoinqt.a $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
+if ENABLE_ZMQ
+qt_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
+endif
qt_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) $(LIBMEMENV) \
- $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1)
+ $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
qt_bitcoin_qt_LIBTOOLFLAGS = --tag CXX
diff --git a/src/Makefile.qttest.include b/src/Makefile.qttest.include
index c5392cf307..6554580bea 100644
--- a/src/Makefile.qttest.include
+++ b/src/Makefile.qttest.include
@@ -30,9 +30,13 @@ qt_test_test_bitcoin_qt_LDADD = $(LIBBITCOINQT) $(LIBBITCOIN_SERVER)
if ENABLE_WALLET
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_WALLET)
endif
+if ENABLE_ZMQ
+qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
+endif
qt_test_test_bitcoin_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBBITCOIN_UNIVALUE) $(LIBLEVELDB) \
$(LIBMEMENV) $(BOOST_LIBS) $(QT_DBUS_LIBS) $(QT_TEST_LIBS) $(QT_LIBS) \
- $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1)
+ $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \
+ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
qt_test_test_bitcoin_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)
CLEAN_BITCOIN_QT_TEST = $(TEST_QT_MOC_CPP) qt/test/*.gcda qt/test/*.gcno
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 9aec13ccef..cee35926a5 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -15,6 +15,8 @@ EXTRA_DIST += \
test/data/tx394b54bb.hex \
test/data/txcreate1.hex \
test/data/txcreate2.hex \
+ test/data/txcreatedata1.hex \
+ test/data/txcreatedata2.hex \
test/data/txcreatesign.hex
JSON_TEST_FILES = \
@@ -50,6 +52,7 @@ BITCOIN_TESTS =\
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_tests.cpp \
+ test/limitedmap_tests.cpp \
test/main_tests.cpp \
test/mempool_tests.cpp \
test/miner_tests.cpp \
@@ -57,9 +60,12 @@ BITCOIN_TESTS =\
test/multisig_tests.cpp \
test/netbase_tests.cpp \
test/pmt_tests.cpp \
+ test/policyestimator_tests.cpp \
test/pow_tests.cpp \
+ test/reverselock_tests.cpp \
test/rpc_tests.cpp \
test/sanity_tests.cpp \
+ test/scheduler_tests.cpp \
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
test/scriptnum_tests.cpp \
@@ -71,6 +77,7 @@ BITCOIN_TESTS =\
test/test_bitcoin.h \
test/timedata_tests.cpp \
test/transaction_tests.cpp \
+ test/txvalidationcache_tests.cpp \
test/uint256_tests.cpp \
test/univalue_tests.cpp \
test/util_tests.cpp
@@ -93,6 +100,10 @@ endif
test_test_bitcoin_LDADD += $(LIBBITCOIN_CONSENSUS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS)
test_test_bitcoin_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) -static
+if ENABLE_ZMQ
+test_test_bitcoin_LDADD += $(ZMQ_LIBS)
+endif
+
nodist_test_test_bitcoin_SOURCES = $(GENERATED_TEST_FILES)
$(BITCOIN_TESTS): $(GENERATED_TEST_FILES)
diff --git a/src/addrman.cpp b/src/addrman.cpp
index c41ee3f9fc..ff1f7e9187 100644
--- a/src/addrman.cpp
+++ b/src/addrman.cpp
@@ -8,8 +8,6 @@
#include "serialize.h"
#include "streams.h"
-using namespace std;
-
int CAddrInfo::GetTriedBucket(const uint256& nKey) const
{
uint64_t hash1 = (CHashWriter(SER_GETHASH, 0) << nKey << GetKey()).GetHash().GetCheapHash();
@@ -68,7 +66,7 @@ double CAddrInfo::GetChance(int64_t nNow) const
fChance *= 0.01;
// deprioritize 66% after each failed attempt, but at most 1/28th to avoid the search taking forever or overly penalizing outages.
- fChance *= pow(0.66, min(nAttempts, 8));
+ fChance *= pow(0.66, std::min(nAttempts, 8));
return fChance;
}
@@ -258,7 +256,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
bool fCurrentlyOnline = (GetAdjustedTime() - addr.nTime < 24 * 60 * 60);
int64_t nUpdateInterval = (fCurrentlyOnline ? 60 * 60 : 24 * 60 * 60);
if (addr.nTime && (!pinfo->nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty))
- pinfo->nTime = max((int64_t)0, addr.nTime - nTimePenalty);
+ pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty);
// add services
pinfo->nServices |= addr.nServices;
@@ -283,7 +281,7 @@ bool CAddrMan::Add_(const CAddress& addr, const CNetAddr& source, int64_t nTimeP
return false;
} else {
pinfo = Create(addr, source, &nId);
- pinfo->nTime = max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
+ pinfo->nTime = std::max((int64_t)0, (int64_t)pinfo->nTime - nTimePenalty);
nNew++;
fNew = true;
}
@@ -343,8 +341,10 @@ CAddrInfo CAddrMan::Select_()
while (1) {
int nKBucket = GetRandInt(ADDRMAN_TRIED_BUCKET_COUNT);
int nKBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
- if (vvTried[nKBucket][nKBucketPos] == -1)
- continue;
+ while (vvTried[nKBucket][nKBucketPos] == -1) {
+ nKBucket = (nKBucket + insecure_rand()) % ADDRMAN_TRIED_BUCKET_COUNT;
+ nKBucketPos = (nKBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
+ }
int nId = vvTried[nKBucket][nKBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
@@ -358,8 +358,10 @@ CAddrInfo CAddrMan::Select_()
while (1) {
int nUBucket = GetRandInt(ADDRMAN_NEW_BUCKET_COUNT);
int nUBucketPos = GetRandInt(ADDRMAN_BUCKET_SIZE);
- if (vvNew[nUBucket][nUBucketPos] == -1)
- continue;
+ while (vvNew[nUBucket][nUBucketPos] == -1) {
+ nUBucket = (nUBucket + insecure_rand()) % ADDRMAN_NEW_BUCKET_COUNT;
+ nUBucketPos = (nUBucketPos + insecure_rand()) % ADDRMAN_BUCKET_SIZE;
+ }
int nId = vvNew[nUBucket][nUBucketPos];
assert(mapInfo.count(nId) == 1);
CAddrInfo& info = mapInfo[nId];
diff --git a/src/addrman.h b/src/addrman.h
index b72dda49d1..384b6cfdb9 100644
--- a/src/addrman.h
+++ b/src/addrman.h
@@ -110,10 +110,10 @@ public:
*
* To that end:
* * Addresses are organized into buckets.
- * * Address that have not yet been tried go into 1024 "new" buckets.
- * * Based on the address range (/16 for IPv4) of source of the information, 64 buckets are selected at random
+ * * Addresses that have not yet been tried go into 1024 "new" buckets.
+ * * Based on the address range (/16 for IPv4) of the source of information, 64 buckets are selected at random.
* * The actual bucket is chosen from one of these, based on the range in which the address itself is located.
- * * One single address can occur in up to 8 different buckets, to increase selection chances for addresses that
+ * * One single address can occur in up to 8 different buckets to increase selection chances for addresses that
* are seen frequently. The chance for increasing this multiplicity decreases exponentially.
* * When adding a new address to a full bucket, a randomly chosen entry (with a bias favoring less recently seen
* ones) is removed from it first.
@@ -231,7 +231,6 @@ protected:
void Attempt_(const CService &addr, int64_t nTime);
//! Select an address to connect to.
- //! nUnkBias determines how much to favor new addresses over tried ones (min=0, max=100)
CAddrInfo Select_();
#ifdef DEBUG_ADDRMAN
@@ -266,7 +265,7 @@ public:
* Notice that vvTried, mapAddr and vVector are never encoded explicitly;
* they are instead reconstructed from the other information.
*
- * vvNew is serialized, but only used if ADDRMAN_UNKOWN_BUCKET_COUNT didn't change,
+ * vvNew is serialized, but only used if ADDRMAN_UNKNOWN_BUCKET_COUNT didn't change,
* otherwise it is reconstructed as well.
*
* This format is more complex, but significantly smaller (at most 1.5 MiB), and supports
@@ -459,7 +458,7 @@ public:
}
//! Return the number of (unique) addresses in all tables.
- int size()
+ size_t size() const
{
return vRandom.size();
}
@@ -532,7 +531,6 @@ public:
/**
* Choose an address to connect to.
- * nUnkBias determines how much "new" entries are favored over "tried" ones (0-100).
*/
CAddrInfo Select()
{
diff --git a/src/alert.cpp b/src/alert.cpp
index aa7ac748da..91e54a9178 100644
--- a/src/alert.cpp
+++ b/src/alert.cpp
@@ -11,6 +11,7 @@
#include "timedata.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <stdint.h>
#include <algorithm>
@@ -50,7 +51,7 @@ std::string CUnsignedAlert::ToString() const
BOOST_FOREACH(int n, setCancel)
strSetCancel += strprintf("%d ", n);
std::string strSetSubVer;
- BOOST_FOREACH(std::string str, setSubVer)
+ BOOST_FOREACH(const std::string& str, setSubVer)
strSetSubVer += "\"" + str + "\" ";
return strprintf(
"CAlert(\n"
@@ -110,7 +111,7 @@ bool CAlert::Cancels(const CAlert& alert) const
return (alert.nID <= nCancel || setCancel.count(alert.nID));
}
-bool CAlert::AppliesTo(int nVersion, std::string strSubVerIn) const
+bool CAlert::AppliesTo(int nVersion, const std::string& strSubVerIn) const
{
// TODO: rework for client-version-embedded-in-strSubVer ?
return (IsInEffect() &&
diff --git a/src/alert.h b/src/alert.h
index 746967c4af..4f9fff9181 100644
--- a/src/alert.h
+++ b/src/alert.h
@@ -97,7 +97,7 @@ public:
uint256 GetHash() const;
bool IsInEffect() const;
bool Cancels(const CAlert& alert) const;
- bool AppliesTo(int nVersion, std::string strSubVerIn) const;
+ bool AppliesTo(int nVersion, const std::string& strSubVerIn) const;
bool AppliesToMe() const;
bool RelayTo(CNode* pnode) const;
bool CheckSignature(const std::vector<unsigned char>& alertKey) const;
diff --git a/src/amount.cpp b/src/amount.cpp
index 0a394c96fc..b469181984 100644
--- a/src/amount.cpp
+++ b/src/amount.cpp
@@ -7,6 +7,8 @@
#include "tinyformat.h"
+const std::string CURRENCY_UNIT = "BTC";
+
CFeeRate::CFeeRate(const CAmount& nFeePaid, size_t nSize)
{
if (nSize > 0)
@@ -27,5 +29,5 @@ CAmount CFeeRate::GetFee(size_t nSize) const
std::string CFeeRate::ToString() const
{
- return strprintf("%d.%08d BTC/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN);
+ return strprintf("%d.%08d %s/kB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
}
diff --git a/src/amount.h b/src/amount.h
index 9212244a88..90e6b5aa8e 100644
--- a/src/amount.h
+++ b/src/amount.h
@@ -16,7 +16,17 @@ typedef int64_t CAmount;
static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000;
-/** No amount larger than this (in satoshi) is valid */
+extern const std::string CURRENCY_UNIT;
+
+/** No amount larger than this (in satoshi) is valid.
+ *
+ * Note that this constant is *not* the total money supply, which in Bitcoin
+ * currently happens to be less than 21,000,000 BTC for various reasons, but
+ * rather a sanity check. As this sanity check is used by consensus-critical
+ * validation code, the exact value of the MAX_MONEY constant is consensus
+ * critical; in unusual circumstances like a(nother) overflow bug that allowed
+ * for the creation of coins out of thin air modification could lead to a fork.
+ * */
static const CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
diff --git a/src/base58.h b/src/base58.h
index 787979c827..90014b9496 100644
--- a/src/base58.h
+++ b/src/base58.h
@@ -146,7 +146,10 @@ public:
K GetKey() {
K ret;
- ret.Decode(&vchData[0], &vchData[Size]);
+ if (vchData.size() == Size) {
+ //if base58 encouded data not holds a ext key, return a !IsValid() key
+ ret.Decode(&vchData[0]);
+ }
return ret;
}
@@ -154,6 +157,10 @@ public:
SetKey(key);
}
+ CBitcoinExtKeyBase(const std::string& strBase58c) {
+ SetString(strBase58c.c_str(), Params().Base58Prefix(Type).size());
+ }
+
CBitcoinExtKeyBase() {}
};
diff --git a/src/bitcoin-cli-res.rc b/src/bitcoin-cli-res.rc
index 4ea1f38e47..1e4aa609bb 100644
--- a/src/bitcoin-cli-res.rc
+++ b/src/bitcoin-cli-res.rc
@@ -17,13 +17,13 @@ BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
VALUE "CompanyName", "Bitcoin"
- VALUE "FileDescription", "Bitcoin-cli (OSS RPC client for Bitcoin)"
+ VALUE "FileDescription", "bitcoin-cli (JSON-RPC client for Bitcoin Core)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "bitcoin-cli"
VALUE "LegalCopyright", COPYRIGHT_STR
VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
VALUE "OriginalFilename", "bitcoin-cli.exe"
- VALUE "ProductName", "Bitcoin-cli"
+ VALUE "ProductName", "bitcoin-cli"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp
index 1269d7a119..7839b3b6b4 100644
--- a/src/bitcoin-cli.cpp
+++ b/src/bitcoin-cli.cpp
@@ -11,9 +11,18 @@
#include "utilstrencodings.h"
#include <boost/filesystem/operations.hpp>
+#include <stdio.h>
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <event2/buffer.h>
+#include <event2/keyvalq_struct.h>
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
+
+static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
std::string HelpMessageCli()
{
@@ -30,9 +39,7 @@ std::string HelpMessageCli()
strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
-
- strUsage += HelpMessageGroup(_("SSL options: (see the Bitcoin Wiki for SSL setup instructions)"));
- strUsage += HelpMessageOpt("-rpcssl", _("Use OpenSSL (https) for JSON-RPC connections"));
+ strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
return strUsage;
}
@@ -91,61 +98,119 @@ static bool AppInitRPC(int argc, char* argv[])
fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
return false;
}
+ if (GetBoolArg("-rpcssl", false))
+ {
+ fprintf(stderr, "Error: SSL mode for RPC (-rpcssl) is no longer supported.\n");
+ return false;
+ }
return true;
}
-Object CallRPC(const string& strMethod, const Array& params)
+
+/** Reply structure for request_done to fill in */
+struct HTTPReply
{
- if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
- throw runtime_error(strprintf(
- _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
- "If the file does not exist, create it with owner-readable-only file permissions."),
- GetConfigFile().string().c_str()));
-
- // Connect to localhost
- bool fUseSSL = GetBoolArg("-rpcssl", false);
- boost::asio::io_service io_service;
- boost::asio::ssl::context context(io_service, boost::asio::ssl::context::sslv23);
- context.set_options(boost::asio::ssl::context::no_sslv2 | boost::asio::ssl::context::no_sslv3);
- boost::asio::ssl::stream<boost::asio::ip::tcp::socket> sslStream(io_service, context);
- SSLIOStreamDevice<boost::asio::ip::tcp> d(sslStream, fUseSSL);
- boost::iostreams::stream< SSLIOStreamDevice<boost::asio::ip::tcp> > stream(d);
-
- const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
- if (!fConnected)
- throw CConnectionFailed("couldn't connect to server");
+ int status;
+ std::string body;
+};
- // HTTP basic authentication
- string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
- map<string, string> mapRequestHeaders;
- mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;
+static void http_request_done(struct evhttp_request *req, void *ctx)
+{
+ HTTPReply *reply = static_cast<HTTPReply*>(ctx);
+
+ if (req == NULL) {
+ /* If req is NULL, it means an error occurred while connecting, but
+ * I'm not sure how to find out which one. We also don't really care.
+ */
+ reply->status = 0;
+ return;
+ }
- // Send request
- string strRequest = JSONRPCRequest(strMethod, params, 1);
- string strPost = HTTPPost(strRequest, mapRequestHeaders);
- stream << strPost << std::flush;
+ reply->status = evhttp_request_get_response_code(req);
- // Receive HTTP reply status
- int nProto = 0;
- int nStatus = ReadHTTPStatus(stream, nProto);
+ struct evbuffer *buf = evhttp_request_get_input_buffer(req);
+ if (buf)
+ {
+ size_t size = evbuffer_get_length(buf);
+ const char *data = (const char*)evbuffer_pullup(buf, size);
+ if (data)
+ reply->body = std::string(data, size);
+ evbuffer_drain(buf, size);
+ }
+}
+
+UniValue CallRPC(const string& strMethod, const UniValue& params)
+{
+ std::string host = GetArg("-rpcconnect", "127.0.0.1");
+ int port = GetArg("-rpcport", BaseParams().RPCPort());
+
+ // Create event base
+ struct event_base *base = event_base_new(); // TODO RAII
+ if (!base)
+ throw runtime_error("cannot create event_base");
+
+ // Synchronously look up hostname
+ struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
+ if (evcon == NULL)
+ throw runtime_error("create connection failed");
+ evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
+
+ HTTPReply response;
+ struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
+ if (req == NULL)
+ throw runtime_error("create http request failed");
+
+ // Get credentials
+ std::string strRPCUserColonPass;
+ if (mapArgs["-rpcpassword"] == "") {
+ // Try fall back to cookie-based authentication if no password is provided
+ if (!GetAuthCookie(&strRPCUserColonPass)) {
+ throw runtime_error(strprintf(
+ _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"),
+ GetConfigFile().string().c_str()));
- // Receive HTTP reply message headers and body
- map<string, string> mapHeaders;
- string strReply;
- ReadHTTPMessage(stream, mapHeaders, strReply, nProto, std::numeric_limits<size_t>::max());
+ }
+ } else {
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ }
- if (nStatus == HTTP_UNAUTHORIZED)
+ struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req);
+ assert(output_headers);
+ evhttp_add_header(output_headers, "Host", host.c_str());
+ evhttp_add_header(output_headers, "Connection", "close");
+ evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str());
+
+ // Attach request data
+ std::string strRequest = JSONRPCRequest(strMethod, params, 1);
+ struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req);
+ assert(output_buffer);
+ evbuffer_add(output_buffer, strRequest.data(), strRequest.size());
+
+ int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/");
+ if (r != 0) {
+ evhttp_connection_free(evcon);
+ event_base_free(base);
+ throw CConnectionFailed("send http request failed");
+ }
+
+ event_base_dispatch(base);
+ evhttp_connection_free(evcon);
+ event_base_free(base);
+
+ if (response.status == 0)
+ throw CConnectionFailed("couldn't connect to server");
+ else if (response.status == HTTP_UNAUTHORIZED)
throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
- else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
- throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
- else if (strReply.empty())
+ else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR)
+ throw runtime_error(strprintf("server returned HTTP error %d", response.status));
+ else if (response.body.empty())
throw runtime_error("no response from server");
// Parse reply
- Value valReply;
- if (!read_string(strReply, valReply))
+ UniValue valReply(UniValue::VSTR);
+ if (!valReply.read(response.body))
throw runtime_error("couldn't parse reply from server");
- const Object& reply = valReply.get_obj();
+ const UniValue& reply = valReply.get_obj();
if (reply.empty())
throw runtime_error("expected reply to have result, error and id properties");
@@ -170,35 +235,43 @@ int CommandLineRPC(int argc, char *argv[])
// Parameters default to strings
std::vector<std::string> strParams(&argv[2], &argv[argc]);
- Array params = RPCConvertValues(strMethod, strParams);
+ UniValue params = RPCConvertValues(strMethod, strParams);
// Execute and handle connection failures with -rpcwait
const bool fWait = GetBoolArg("-rpcwait", false);
do {
try {
- const Object reply = CallRPC(strMethod, params);
+ const UniValue reply = CallRPC(strMethod, params);
// Parse reply
- const Value& result = find_value(reply, "result");
- const Value& error = find_value(reply, "error");
+ const UniValue& result = find_value(reply, "result");
+ const UniValue& error = find_value(reply, "error");
- if (error.type() != null_type) {
+ if (!error.isNull()) {
// Error
- const int code = find_value(error.get_obj(), "code").get_int();
+ int code = error["code"].get_int();
if (fWait && code == RPC_IN_WARMUP)
throw CConnectionFailed("server in warmup");
- strPrint = "error: " + write_string(error, false);
+ strPrint = "error: " + error.write();
nRet = abs(code);
+ if (error.isObject())
+ {
+ UniValue errCode = find_value(error, "code");
+ UniValue errMsg = find_value(error, "message");
+ strPrint = errCode.isNull() ? "" : "error code: "+errCode.getValStr()+"\n";
+
+ if (errMsg.isStr())
+ strPrint += "error message:\n"+errMsg.get_str();
+ }
} else {
// Result
- if (result.type() == null_type)
+ if (result.isNull())
strPrint = "";
- else if (result.type() == str_type)
+ else if (result.isStr())
strPrint = result.get_str();
else
- strPrint = write_string(result, true);
+ strPrint = result.write(2);
}
-
// Connection succeeded, no need to retry.
break;
}
@@ -231,6 +304,10 @@ int CommandLineRPC(int argc, char *argv[])
int main(int argc, char* argv[])
{
SetupEnvironment();
+ if (!SetupNetworking()) {
+ fprintf(stderr, "Error: Initializing networking failed\n");
+ exit(1);
+ }
try {
if(!AppInitRPC(argc, argv))
diff --git a/src/bitcoin-tx-res.rc b/src/bitcoin-tx-res.rc
new file mode 100644
index 0000000000..3e49b820bc
--- /dev/null
+++ b/src/bitcoin-tx-res.rc
@@ -0,0 +1,35 @@
+#include <windows.h> // needed for VERSIONINFO
+#include "clientversion.h" // holds the needed client version information
+
+#define VER_PRODUCTVERSION CLIENT_VERSION_MAJOR,CLIENT_VERSION_MINOR,CLIENT_VERSION_REVISION,CLIENT_VERSION_BUILD
+#define VER_PRODUCTVERSION_STR STRINGIZE(CLIENT_VERSION_MAJOR) "." STRINGIZE(CLIENT_VERSION_MINOR) "." STRINGIZE(CLIENT_VERSION_REVISION) "." STRINGIZE(CLIENT_VERSION_BUILD)
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_APP
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4" // U.S. English - multilingual (hex)
+ BEGIN
+ VALUE "CompanyName", "Bitcoin"
+ VALUE "FileDescription", "bitcoin-tx (CLI Bitcoin transaction editor utility)"
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", "bitcoin-tx"
+ VALUE "LegalCopyright", COPYRIGHT_STR
+ VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
+ VALUE "OriginalFilename", "bitcoin-tx.exe"
+ VALUE "ProductName", "bitcoin-tx"
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1252 // language neutral - multilingual (decimal)
+ END
+END
diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp
index c82d4f93a8..97a073174d 100644
--- a/src/bitcoin-tx.cpp
+++ b/src/bitcoin-tx.cpp
@@ -8,6 +8,7 @@
#include "consensus/consensus.h"
#include "core_io.h"
#include "keystore.h"
+#include "policy/policy.h"
#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
@@ -69,6 +70,7 @@ static bool AppInitRawTx(int argc, char* argv[])
strUsage += HelpMessageOpt("locktime=N", _("Set TX lock time to N"));
strUsage += HelpMessageOpt("nversion=N", _("Set TX version to N"));
strUsage += HelpMessageOpt("outaddr=VALUE:ADDRESS", _("Add address-based output to TX"));
+ strUsage += HelpMessageOpt("outdata=[VALUE:]DATA", _("Add data-based output to TX"));
strUsage += HelpMessageOpt("outscript=VALUE:SCRIPT", _("Add raw script output to TX"));
strUsage += HelpMessageOpt("sign=SIGHASH-FLAGS", _("Add zero or more signatures to transaction") + ". " +
_("This command requires JSON registers:") +
@@ -142,13 +144,14 @@ static void RegisterLoad(const string& strInput)
valStr.insert(valStr.size(), buf, bread);
}
- if (ferror(f)) {
+ int error = ferror(f);
+ fclose(f);
+
+ if (error) {
string strErr = "Error reading file " + filename;
throw runtime_error(strErr);
}
- fclose(f);
-
// evaluate as JSON buffer register
RegisterSetJson(key, valStr);
}
@@ -229,6 +232,35 @@ static void MutateTxAddOutAddr(CMutableTransaction& tx, const string& strInput)
tx.vout.push_back(txout);
}
+static void MutateTxAddOutData(CMutableTransaction& tx, const string& strInput)
+{
+ CAmount value = 0;
+
+ // separate [VALUE:]DATA in string
+ size_t pos = strInput.find(':');
+
+ if (pos==0)
+ throw runtime_error("TX output value not specified");
+
+ if (pos != string::npos) {
+ // extract and validate VALUE
+ string strValue = strInput.substr(0, pos);
+ if (!ParseMoney(strValue, value))
+ throw runtime_error("invalid TX output value");
+ }
+
+ // extract and validate DATA
+ string strData = strInput.substr(pos + 1, string::npos);
+
+ if (!IsHex(strData))
+ throw runtime_error("invalid TX output data");
+
+ std::vector<unsigned char> data = ParseHex(strData);
+
+ CTxOut txout(value, CScript() << OP_RETURN << data);
+ tx.vout.push_back(txout);
+}
+
static void MutateTxAddOutScript(CMutableTransaction& tx, const string& strInput)
{
// separate VALUE:SCRIPT in string
@@ -346,7 +378,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
UniValue keysObj = registers["privatekeys"];
fGivenKeys = true;
- for (unsigned int kidx = 0; kidx < keysObj.count(); kidx++) {
+ for (unsigned int kidx = 0; kidx < keysObj.size(); kidx++) {
if (!keysObj[kidx].isStr())
throw runtime_error("privatekey not a string");
CBitcoinSecret vchSecret;
@@ -363,7 +395,7 @@ static void MutateTxSign(CMutableTransaction& tx, const string& flagStr)
throw runtime_error("prevtxs register variable must be set.");
UniValue prevtxsObj = registers["prevtxs"];
{
- for (unsigned int previdx = 0; previdx < prevtxsObj.count(); previdx++) {
+ for (unsigned int previdx = 0; previdx < prevtxsObj.size(); previdx++) {
UniValue prevOut = prevtxsObj[previdx];
if (!prevOut.isObject())
throw runtime_error("expected prevtxs internal object");
@@ -468,6 +500,8 @@ static void MutateTx(CMutableTransaction& tx, const string& command,
MutateTxDelOutput(tx, commandVal);
else if (command == "outaddr")
MutateTxAddOutAddr(tx, commandVal);
+ else if (command == "outdata")
+ MutateTxAddOutData(tx, commandVal);
else if (command == "outscript")
MutateTxAddOutScript(tx, commandVal);
diff --git a/src/bitcoind-res.rc b/src/bitcoind-res.rc
index d183179b17..3a64acd5d1 100644
--- a/src/bitcoind-res.rc
+++ b/src/bitcoind-res.rc
@@ -17,13 +17,13 @@ BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
VALUE "CompanyName", "Bitcoin"
- VALUE "FileDescription", "Bitcoind (OSS daemon/client for Bitcoin)"
+ VALUE "FileDescription", "bitcoind (Bitcoin node with a JSON-RPC server)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "bitcoind"
VALUE "LegalCopyright", COPYRIGHT_STR
VALUE "LegalTrademarks1", "Distributed under the MIT software license, see the accompanying file COPYING or http://www.opensource.org/licenses/mit-license.php."
VALUE "OriginalFilename", "bitcoind.exe"
- VALUE "ProductName", "Bitcoind"
+ VALUE "ProductName", "bitcoind"
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp
index eeca8655c9..b512f74c22 100644
--- a/src/bitcoind.cpp
+++ b/src/bitcoind.cpp
@@ -3,17 +3,23 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chainparams.h"
#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
-#include "main.h"
#include "noui.h"
+#include "scheduler.h"
#include "util.h"
+#include "httpserver.h"
+#include "httprpc.h"
+#include "rpcserver.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
+#include <stdio.h>
+
/* Introduction text for doxygen: */
/*! \mainpage Developer documentation
@@ -43,7 +49,7 @@ void WaitForShutdown(boost::thread_group* threadGroup)
}
if (threadGroup)
{
- threadGroup->interrupt_all();
+ Interrupt(*threadGroup);
threadGroup->join_all();
}
}
@@ -55,6 +61,7 @@ void WaitForShutdown(boost::thread_group* threadGroup)
bool AppInit(int argc, char* argv[])
{
boost::thread_group threadGroup;
+ CScheduler scheduler;
bool fRet = false;
@@ -142,7 +149,7 @@ bool AppInit(int argc, char* argv[])
#endif
SoftSetBoolArg("-server", true);
- fRet = AppInit2(threadGroup);
+ fRet = AppInit2(threadGroup, scheduler);
}
catch (const std::exception& e) {
PrintExceptionContinue(&e, "AppInit()");
@@ -152,7 +159,7 @@ bool AppInit(int argc, char* argv[])
if (!fRet)
{
- threadGroup.interrupt_all();
+ Interrupt(threadGroup);
// threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
// the startup-failure cases to make sure they don't result in a hang due to some
// thread-blocking-waiting-for-another-thread-during-startup case
diff --git a/src/bloom.cpp b/src/bloom.cpp
index 36cba491c4..de87206592 100644
--- a/src/bloom.cpp
+++ b/src/bloom.cpp
@@ -8,6 +8,7 @@
#include "hash.h"
#include "script/script.h"
#include "script/standard.h"
+#include "random.h"
#include "streams.h"
#include <math.h>
@@ -121,6 +122,12 @@ void CBloomFilter::clear()
isEmpty = true;
}
+void CBloomFilter::reset(unsigned int nNewTweak)
+{
+ clear();
+ nTweak = nNewTweak;
+}
+
bool CBloomFilter::IsWithinSizeConstraints() const
{
return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
@@ -209,15 +216,17 @@ void CBloomFilter::UpdateEmptyFull()
isEmpty = empty;
}
-CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate, unsigned int nTweak) :
- b1(nElements * 2, fpRate, nTweak), b2(nElements * 2, fpRate, nTweak)
+CRollingBloomFilter::CRollingBloomFilter(unsigned int nElements, double fpRate) :
+ b1(nElements * 2, fpRate, 0), b2(nElements * 2, fpRate, 0)
{
// Implemented using two bloom filters of 2 * nElements each.
// We fill them up, and clear them, staggered, every nElements
// inserted, so at least one always contains the last nElements
// inserted.
- nBloomSize = nElements * 2;
nInsertions = 0;
+ nBloomSize = nElements * 2;
+
+ reset();
}
void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
@@ -234,6 +243,12 @@ void CRollingBloomFilter::insert(const std::vector<unsigned char>& vKey)
}
}
+void CRollingBloomFilter::insert(const uint256& hash)
+{
+ vector<unsigned char> data(hash.begin(), hash.end());
+ insert(data);
+}
+
bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
{
if (nInsertions < nBloomSize / 2) {
@@ -242,9 +257,16 @@ bool CRollingBloomFilter::contains(const std::vector<unsigned char>& vKey) const
return b1.contains(vKey);
}
-void CRollingBloomFilter::clear()
+bool CRollingBloomFilter::contains(const uint256& hash) const
+{
+ vector<unsigned char> data(hash.begin(), hash.end());
+ return contains(data);
+}
+
+void CRollingBloomFilter::reset()
{
- b1.clear();
- b2.clear();
+ unsigned int nNewTweak = GetRand(std::numeric_limits<unsigned int>::max());
+ b1.reset(nNewTweak);
+ b2.reset(nNewTweak);
nInsertions = 0;
}
diff --git a/src/bloom.h b/src/bloom.h
index bb17f59c86..a4dba8cb4f 100644
--- a/src/bloom.h
+++ b/src/bloom.h
@@ -89,6 +89,7 @@ public:
bool contains(const uint256& hash) const;
void clear();
+ void reset(unsigned int nNewTweak);
//! True if the size is <= MAX_BLOOM_FILTER_SIZE and the number of hash functions is <= MAX_HASH_FUNCS
//! (catch a filter which was just deserialized which was too big)
@@ -103,7 +104,11 @@ public:
/**
* RollingBloomFilter is a probabilistic "keep track of most recently inserted" set.
- * Construct it with the number of items to keep track of, and a false-positive rate.
+ * Construct it with the number of items to keep track of, and a false-positive
+ * rate. Unlike CBloomFilter, by default nTweak is set to a cryptographically
+ * secure random value for you. Similarly rather than clear() the method
+ * reset() is provided, which also changes nTweak to decrease the impact of
+ * false-positives.
*
* contains(item) will always return true if item was one of the last N things
* insert()'ed ... but may also return true for items that were not inserted.
@@ -111,12 +116,17 @@ public:
class CRollingBloomFilter
{
public:
- CRollingBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweak);
+ // A random bloom filter calls GetRand() at creation time.
+ // Don't create global CRollingBloomFilter objects, as they may be
+ // constructed before the randomizer is properly initialized.
+ CRollingBloomFilter(unsigned int nElements, double nFPRate);
void insert(const std::vector<unsigned char>& vKey);
+ void insert(const uint256& hash);
bool contains(const std::vector<unsigned char>& vKey) const;
+ bool contains(const uint256& hash) const;
- void clear();
+ void reset();
private:
unsigned int nBloomSize;
diff --git a/src/chain.cpp b/src/chain.cpp
index 719256106e..5b8ce076c4 100644
--- a/src/chain.cpp
+++ b/src/chain.cpp
@@ -82,9 +82,10 @@ CBlockIndex* CBlockIndex::GetAncestor(int height)
while (heightWalk > height) {
int heightSkip = GetSkipHeight(heightWalk);
int heightSkipPrev = GetSkipHeight(heightWalk - 1);
- if (heightSkip == height ||
- (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
- heightSkipPrev >= height))) {
+ if (pindexWalk->pskip != NULL &&
+ (heightSkip == height ||
+ (heightSkip > height && !(heightSkipPrev < heightSkip - 2 &&
+ heightSkipPrev >= height)))) {
// Only follow pskip if pprev->pskip isn't better than pskip->pprev.
pindexWalk = pindexWalk->pskip;
heightWalk = heightSkip;
diff --git a/src/chainparams.cpp b/src/chainparams.cpp
index 556d0aed4d..9c843f6e7e 100644
--- a/src/chainparams.cpp
+++ b/src/chainparams.cpp
@@ -12,10 +12,47 @@
#include <boost/assign/list_of.hpp>
-using namespace std;
-
#include "chainparamsseeds.h"
+static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ CMutableTransaction txNew;
+ txNew.nVersion = 1;
+ txNew.vin.resize(1);
+ txNew.vout.resize(1);
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
+ txNew.vout[0].nValue = genesisReward;
+ txNew.vout[0].scriptPubKey = genesisOutputScript;
+
+ CBlock genesis;
+ genesis.nTime = nTime;
+ genesis.nBits = nBits;
+ genesis.nNonce = nNonce;
+ genesis.nVersion = nVersion;
+ genesis.vtx.push_back(txNew);
+ genesis.hashPrevBlock.SetNull();
+ genesis.hashMerkleRoot = genesis.BuildMerkleTree();
+ return genesis;
+}
+
+/**
+ * Build the genesis block. Note that the output of its generation
+ * transaction cannot be spent since it did not originally exist in the
+ * database.
+ *
+ * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
+ * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
+ * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
+ * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
+ * vMerkleTree: 4a5e1e
+ */
+static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
+{
+ const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
+ const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
+ return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
+}
+
/**
* Main network
*/
@@ -50,35 +87,9 @@ public:
pchMessageStart[3] = 0xd9;
vAlertPubKey = ParseHex("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
nDefaultPort = 8333;
- nMinerThreads = 0;
nPruneAfterHeight = 100000;
- /**
- * Build the genesis block. Note that the output of its generation
- * transaction cannot be spent since it did not originally exist in the
- * database.
- *
- * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1)
- * CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0)
- * CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73)
- * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
- * vMerkleTree: 4a5e1e
- */
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
- CMutableTransaction txNew;
- txNew.vin.resize(1);
- txNew.vout.resize(1);
- txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
- txNew.vout[0].nValue = 50 * COIN;
- txNew.vout[0].scriptPubKey = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
- genesis.vtx.push_back(txNew);
- genesis.hashPrevBlock.SetNull();
- genesis.hashMerkleRoot = genesis.BuildMerkleTree();
- genesis.nVersion = 1;
- genesis.nTime = 1231006505;
- genesis.nBits = 0x1d00ffff;
- genesis.nNonce = 2083236893;
-
+ genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
@@ -86,7 +97,7 @@ public:
vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be")); // Pieter Wuille
vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me")); // Matt Corallo
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
- vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Addy Yeow
+ vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com")); // Christian Decker
vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org")); // Jeff Garzik
vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch")); // Jonas Schnelli
@@ -98,14 +109,13 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_main, pnSeed6_main + ARRAYLEN(pnSeed6_main));
- fRequireRPCPassword = true;
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = true;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = false;
- checkpointData = (Checkpoints::CCheckpointData) {
+ checkpointData = (CCheckpointData) {
boost::assign::map_list_of
( 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"))
( 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6"))
@@ -132,13 +142,17 @@ static CMainParams mainParams;
/**
* Testnet (v3)
*/
-class CTestNetParams : public CMainParams {
+class CTestNetParams : public CChainParams {
public:
CTestNetParams() {
strNetworkID = "test";
+ consensus.nSubsidyHalvingInterval = 210000;
consensus.nMajorityEnforceBlockUpgrade = 51;
consensus.nMajorityRejectBlockOutdated = 75;
consensus.nMajorityWindow = 100;
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = true;
pchMessageStart[0] = 0x0b;
pchMessageStart[1] = 0x11;
@@ -146,14 +160,12 @@ public:
pchMessageStart[3] = 0x07;
vAlertPubKey = ParseHex("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a");
nDefaultPort = 18333;
- nMinerThreads = 0;
nPruneAfterHeight = 1000;
- //! Modify the testnet genesis block so the timestamp is valid for a later start.
- genesis.nTime = 1296688602;
- genesis.nNonce = 414098458;
+ genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
vFixedSeeds.clear();
vSeeds.clear();
@@ -170,14 +182,13 @@ public:
vFixedSeeds = std::vector<SeedSpec6>(pnSeed6_test, pnSeed6_test + ARRAYLEN(pnSeed6_test));
- fRequireRPCPassword = true;
fMiningRequiresPeers = true;
fDefaultConsistencyChecks = false;
fRequireStandard = false;
fMineBlocksOnDemand = false;
fTestnetToBeDeprecatedFieldRPC = true;
- checkpointData = (Checkpoints::CCheckpointData) {
+ checkpointData = (CCheckpointData) {
boost::assign::map_list_of
( 546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")),
1337966069,
@@ -192,7 +203,7 @@ static CTestNetParams testNetParams;
/**
* Regression test
*/
-class CRegTestParams : public CTestNetParams {
+class CRegTestParams : public CChainParams {
public:
CRegTestParams() {
strNetworkID = "regtest";
@@ -201,36 +212,43 @@ public:
consensus.nMajorityRejectBlockOutdated = 950;
consensus.nMajorityWindow = 1000;
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
+ consensus.nPowTargetSpacing = 10 * 60;
+ consensus.fPowAllowMinDifficultyBlocks = true;
+
pchMessageStart[0] = 0xfa;
pchMessageStart[1] = 0xbf;
pchMessageStart[2] = 0xb5;
pchMessageStart[3] = 0xda;
- nMinerThreads = 1;
- genesis.nTime = 1296688602;
- genesis.nBits = 0x207fffff;
- genesis.nNonce = 2;
- consensus.hashGenesisBlock = genesis.GetHash();
nDefaultPort = 18444;
- assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
nPruneAfterHeight = 1000;
+ genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
+ consensus.hashGenesisBlock = genesis.GetHash();
+ assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
+ assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
+
vFixedSeeds.clear(); //! Regtest mode doesn't have any fixed seeds.
vSeeds.clear(); //! Regtest mode doesn't have any DNS seeds.
- fRequireRPCPassword = false;
fMiningRequiresPeers = false;
fDefaultConsistencyChecks = true;
fRequireStandard = false;
fMineBlocksOnDemand = true;
fTestnetToBeDeprecatedFieldRPC = false;
- checkpointData = (Checkpoints::CCheckpointData){
+ checkpointData = (CCheckpointData){
boost::assign::map_list_of
( 0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")),
0,
0,
0
};
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,239);
+ base58Prefixes[EXT_PUBLIC_KEY] = boost::assign::list_of(0x04)(0x35)(0x87)(0xCF).convert_to_container<std::vector<unsigned char> >();
+ base58Prefixes[EXT_SECRET_KEY] = boost::assign::list_of(0x04)(0x35)(0x83)(0x94).convert_to_container<std::vector<unsigned char> >();
}
};
static CRegTestParams regTestParams;
diff --git a/src/chainparams.h b/src/chainparams.h
index bb95b3aa4a..5db39aa09c 100644
--- a/src/chainparams.h
+++ b/src/chainparams.h
@@ -7,7 +7,6 @@
#define BITCOIN_CHAINPARAMS_H
#include "chainparamsbase.h"
-#include "checkpoints.h"
#include "consensus/params.h"
#include "primitives/block.h"
#include "protocol.h"
@@ -24,6 +23,14 @@ struct SeedSpec6 {
uint16_t port;
};
+typedef std::map<int, uint256> MapCheckpoints;
+
+struct CCheckpointData {
+ MapCheckpoints mapCheckpoints;
+ int64_t nTimeLastCheckpoint;
+ int64_t nTransactionsLastCheckpoint;
+ double fTransactionsPerDay;
+};
/**
* CChainParams defines various tweakable parameters of a given instance of the
@@ -49,15 +56,8 @@ public:
const CMessageHeader::MessageStartChars& MessageStart() const { return pchMessageStart; }
const std::vector<unsigned char>& AlertKey() const { return vAlertPubKey; }
int GetDefaultPort() const { return nDefaultPort; }
- int SubsidyHalvingInterval() const { return consensus.nSubsidyHalvingInterval; }
- int EnforceBlockUpgradeMajority() const { return consensus.nMajorityEnforceBlockUpgrade; }
- int RejectBlockOutdatedMajority() const { return consensus.nMajorityRejectBlockOutdated; }
- int ToCheckBlockUpgradeMajority() const { return consensus.nMajorityWindow; }
- /** Used if GenerateBitcoins is called with a negative number of threads */
- int DefaultMinerThreads() const { return nMinerThreads; }
const CBlock& GenesisBlock() const { return genesis; }
- bool RequireRPCPassword() const { return fRequireRPCPassword; }
/** Make miner wait to have peers to avoid wasting work */
bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
/** Default value for -checkmempool and -checkblockindex argument */
@@ -74,7 +74,7 @@ public:
const std::vector<CDNSSeedData>& DNSSeeds() const { return vSeeds; }
const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; }
const std::vector<SeedSpec6>& FixedSeeds() const { return vFixedSeeds; }
- const Checkpoints::CCheckpointData& Checkpoints() const { return checkpointData; }
+ const CCheckpointData& Checkpoints() const { return checkpointData; }
protected:
CChainParams() {}
@@ -83,20 +83,18 @@ protected:
//! Raw pub key bytes for the broadcast alert signing key.
std::vector<unsigned char> vAlertPubKey;
int nDefaultPort;
- int nMinerThreads;
uint64_t nPruneAfterHeight;
std::vector<CDNSSeedData> vSeeds;
std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
std::string strNetworkID;
CBlock genesis;
std::vector<SeedSpec6> vFixedSeeds;
- bool fRequireRPCPassword;
bool fMiningRequiresPeers;
bool fDefaultConsistencyChecks;
bool fRequireStandard;
bool fMineBlocksOnDemand;
bool fTestnetToBeDeprecatedFieldRPC;
- Checkpoints::CCheckpointData checkpointData;
+ CCheckpointData checkpointData;
};
/**
diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp
index 7d82d689ec..9c87bf2154 100644
--- a/src/chainparamsbase.cpp
+++ b/src/chainparamsbase.cpp
@@ -25,7 +25,7 @@ static CBaseMainParams mainParams;
/**
* Testnet (v3)
*/
-class CBaseTestNetParams : public CBaseMainParams
+class CBaseTestNetParams : public CBaseChainParams
{
public:
CBaseTestNetParams()
@@ -39,11 +39,12 @@ static CBaseTestNetParams testNetParams;
/*
* Regression test
*/
-class CBaseRegTestParams : public CBaseTestNetParams
+class CBaseRegTestParams : public CBaseChainParams
{
public:
CBaseRegTestParams()
{
+ nRPCPort = 18332;
strDataDir = "regtest";
}
};
diff --git a/src/chainparamsseeds.h b/src/chainparamsseeds.h
index 6b6e5103f5..423362859f 100644
--- a/src/chainparamsseeds.h
+++ b/src/chainparamsseeds.h
@@ -2,551 +2,900 @@
#define BITCOIN_CHAINPARAMSSEEDS_H
/**
* List of fixed seed nodes for the bitcoin network
- * AUTOGENERATED by share/seeds/generate-seeds.py
+ * AUTOGENERATED by contrib/seeds/generate-seeds.py
*
* Each line contains a 16-byte IPv6 address and a port.
* IPv4 as well as onion addresses are wrapped inside a IPv6 address accordingly.
*/
static SeedSpec6 pnSeed6_main[] = {
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x21,0xc5,0x6e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x22,0xb4,0xf5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0x22,0xa8,0x80}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x01,0xca,0x80,0xda}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x23,0xc3,0x19}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x64,0x7b,0x13}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xaf,0x91,0xa9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc7,0x85,0xc1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc7,0x97,0x0a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xe4,0x01,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x02,0x1e,0x00,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x09,0x60,0xcb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x2d,0x47,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x2d,0x62,0x8d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x66,0x91,0x44}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x87,0xa0,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xbd,0x86,0xf6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xc7,0xa4,0x84}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0xf9,0x87,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x08,0x13,0x2c,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x08,0x16,0xe6,0x08}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0e,0xc8,0xc8,0x91}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0xe4,0x00,0xbc}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x12,0xe4,0x00,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x1e,0xf3,0x99}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x58,0xe8,0x31}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x63,0x69,0x09}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe2,0x89,0xd0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe3,0xb1,0xa1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe3,0xbf,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x18,0xa8,0x61}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x1c,0x23,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x5c,0x4c,0xaa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0x63,0x40,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe4,0xa6,0x80}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xe5,0x2d,0x20}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xec,0x90,0x45}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xfd,0x94,0x71}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xfd,0xf1,0x16}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x17,0xff,0xe3,0xe7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x14,0xcd,0xde}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x17,0x78,0xfc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x08,0x69,0x80}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x10,0x45,0x89}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x5e,0x62,0x60}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x62,0x5f,0xc9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x6f,0x5a,0x37}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x77,0x77,0x69}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x8a,0x19,0x95}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x03,0xd6,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xba,0x57,0x2e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xba,0x65,0x62}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xba,0xfa,0xba}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xcc,0x99,0x6b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x2c,0x10,0xe7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x2c,0x2c,0x0b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x78,0xa8,0xcc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0x8f,0x56,0x1a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xbb,0x4b,0x18}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xbc,0x44,0xa9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc0,0x5f,0x96}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc9,0xf6,0x74}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xcd,0x0a,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x0a,0xd2,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x13,0x8a,0x9a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0xcc,0x7b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0xcd,0x43}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x66,0x76,0x07}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x76,0xa6,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0x7a,0x85,0x31}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xa6,0x61,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xd5,0xeb,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe2,0x6b,0x40}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x18,0xe4,0xc0,0xab}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1b,0x8c,0x85,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x29,0x28,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0x2b,0x65,0x3b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xb8,0xc3,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x1f,0xc1,0x8b,0x42}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xc8,0x46,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x25,0xcd,0x0a,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2a,0x03,0x6a,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2a,0x3c,0x85,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x38,0x55,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x38,0x66,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2d,0x4f,0x82,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x1c,0xcc,0x3d}, 11101},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x26,0xeb,0xe5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x3b,0x02,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x65,0x84,0x25}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0x65,0xa8,0x32}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa3,0x4c,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa2,0x5b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xad,0xbe,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xa6,0xa1,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xb6,0x84,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xdf,0x24,0x5e}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe3,0x42,0x84}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe5,0xee,0xbb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xec,0x74,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2f,0x37,0x0e,0x41}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x07,0xfc,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x2e,0x9f,0x5b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x4e,0x31,0xb5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x4e,0xe7,0x39}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x4f,0x99,0x41}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x74,0x22,0x2c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x7e,0x56,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x8e,0x29,0x17}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xc7,0x71,0xc1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xc8,0x4e,0x6b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xce,0x8a,0xb1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xfc,0x34,0x31}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xa5,0x19,0x4b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xa9,0x6b,0x28}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xb3,0xbe,0x38}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xbb,0x52,0x79}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xf6,0x55,0xf6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x4a,0x07,0xcd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x60,0xb7,0x79}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x3e,0x3a,0x26}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x3f,0x5b,0x48}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x3f,0x5b,0x70}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x48,0xd3,0xe4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x2b,0x28,0x9a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xe3,0x42,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xef,0x6b,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xf9,0x27,0x64}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2e,0xfa,0x62,0x6c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x07,0x25,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x51,0x35,0x97}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x73,0x2b,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x74,0x14,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x74,0x21,0x5c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x7d,0xa7,0xf5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0x8f,0x09,0x33}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x32,0xbc,0xc0,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0x4d,0xa2,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0x99,0x61,0x6d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0xa5,0xc0,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3a,0x60,0x69,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3b,0xa7,0xc4,0x87}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3c,0x1d,0xe3,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3d,0x23,0xe1,0x13}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x2b,0x82,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x50,0xb9,0xd5}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0x6d,0x31,0x1a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xad,0x8b,0x3a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xb5,0xee,0xba}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0x72,0x7f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0x8d,0xe4,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0x99,0xd5,0x4e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xdf,0x54,0x91}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3f,0xfb,0x58,0x70}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x1f,0x6e,0x32}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x22,0x79,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x72,0x06,0x2a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x8c,0x7d,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xca,0x00,0x61}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0x42,0xe3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x3e,0xd2,0xc0,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x4a,0x62,0xcd}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0x9c,0xc1,0x64}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x1e,0x2f,0x74}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x23,0x84,0xb1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xcb,0x66,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x40,0xe5,0x8e,0x30}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x60,0xc1,0xa5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x41,0x6f,0xbd,0x1a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x44,0x0a,0x1e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x72,0x21,0xfa}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x82,0x2e,0x3f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xaf,0xd7,0x87}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xbe,0xfd,0xa5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xf4,0x62,0x6f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xa2,0xee,0x1e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xa9,0xff,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xb7,0xad,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x1e,0x03,0x07}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x72,0x21,0x31}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x76,0x85,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0x87,0x0a,0x7e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xac,0x0a,0x04}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xc2,0x26,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x42,0xd7,0xc0,0x68}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0x3c,0x62,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xa4,0x23,0x24}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xbf,0xa2,0xf4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xcf,0xc3,0x4d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xdb,0xe9,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xe3,0xf0,0x73}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xf7,0xde,0x47}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x2b,0x72,0x42}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x34,0x21,0x24}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xc6,0xf5,0xf1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x0c,0xe2,0xa5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x0d,0xc6,0xbc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x0f,0xb3,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x27,0xef,0x2f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x2f,0x2d,0x57}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x3e,0xd9,0xce}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x40,0x2a,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x40,0x51,0x3d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x43,0xdb,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x5a,0x84,0x9d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x5e,0x1e,0xb1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x88,0xaf,0xf1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x3d,0x61,0xe4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x7b,0x76,0x84}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x3b,0x98,0xb6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc6,0xf8,0x97}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc8,0xf2,0x59}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xe1,0xb3,0x9d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x0e,0xbb,0x33}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x26,0x22,0xb4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x34,0x48,0xbb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x5b,0x90,0xb6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xa7,0x31,0xd9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xc9,0xf3,0x37}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xdf,0x3c,0xf9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xe4,0x99,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x1a,0x65,0xe4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x32,0x9e,0xc8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xb5,0xcc,0xaa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xdd,0xc1,0x37}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x43,0xe4,0xa2,0xe4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x32,0x43,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x3e,0x03,0xcb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x41,0xcd,0xe2}, 9000},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x6a,0x2a,0xbf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0x96,0xb5,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xc4,0xc4,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x44,0xe0,0xc2,0x51}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x2e,0x05,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x32,0xab,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x40,0x2b,0x98}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x41,0x29,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x5a,0x84,0xc8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x8f,0x01,0xf3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0x92,0x62,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xa5,0xf6,0x26}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xcf,0x06,0x87}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x45,0xfb,0xd0,0x1a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x26,0x01,0x65}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x26,0x09,0x42}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x46,0x5a,0x02,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0x3a,0xe4,0xe2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc7,0x0b,0xbd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xc7,0xc1,0xca}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xcd,0xe8,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x47,0xec,0xc8,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x18,0x49,0xba}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x34,0x82,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0x35,0x6f,0x25}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x48,0xeb,0x26,0x46}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x1f,0xab,0x95}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x20,0x89,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x89,0x85,0xee}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xb5,0xc0,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xbe,0x02,0x3c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xc3,0xc0,0x89}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0xde,0x23,0x75}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x39,0xc7,0xb4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x3f,0xde,0xe2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x51,0xe7,0x15}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xc1,0x7e,0x52}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xcf,0xeb,0xa4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x53,0xc5,0x72}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x90,0x72,0x09}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x70,0x05,0xf7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xae,0x14,0xf7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x25,0xf0,0x8e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x39,0xca,0x6b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xac,0x7b,0x35}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xdd,0x5b,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xeb,0x30,0x30}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf5,0x4e,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x08,0x3a,0xf9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x1b,0xbf,0xb6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x81,0xec,0x8d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x83,0x58,0x2f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x9d,0xcd,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x52,0xe9,0xcd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x55,0x42,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x65,0xe0,0x7f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x71,0x45,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0x7a,0xeb,0x44}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xc1,0x44,0x8d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4a,0xd0,0xa4,0xdb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x64,0x25,0x7a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0x91,0x95,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4b,0xa8,0x22,0x14}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x14,0x2c,0xf0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0x64,0x46,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xa8,0x03,0xef}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4c,0xba,0x8c,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x5c,0x44,0xdd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x6d,0x65,0x8e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0x6e,0x0b,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4d,0xf2,0x6c,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x2e,0x60,0x96}, 9020},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4e,0x54,0x64,0x5f}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x84,0xe6,0x90}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x8f,0xbc,0x9b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa0,0xdd,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa1,0x6f,0x72}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x64,0xbd,0x03}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0x93,0x8c,0x79}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xcb,0x4b,0x85}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xdc,0x63,0xe3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xde,0x14,0xa9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf1,0x01,0x07}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x17,0xbf,0xf3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x26,0x0b,0xca}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0x85,0x2b,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa0,0x4c,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xa9,0x22,0x18}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x4f,0xbc,0x07,0x4e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xd9,0xe2,0x19}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xdf,0x64,0xb3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x50,0xf0,0x81,0xdd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x01,0xad,0xf3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x0b,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x07,0x10,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x42,0x6f,0x03}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x50,0x09,0x47}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x6e,0xd5,0xa5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x85,0x9b,0xed}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0x8c,0x2b,0x8a}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xab,0x22,0x25}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xb5,0x9b,0xb4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x27,0x9c,0x89}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x49,0xa1,0x5f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x82,0x2d,0x28}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xa5,0x99,0x2f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xa8,0x80,0x85}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xb3,0xe1,0x76}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc2,0xf5,0x9e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xae,0xf7,0x32}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xb5,0x9b,0x35}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xb8,0x05,0xfd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xbb,0x45,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x51,0xe6,0x03,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x2a,0x80,0x33}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x4a,0xe2,0x15}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0x8e,0x4b,0x32}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc7,0x66,0x0a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xd3,0x1e,0xf3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xd9,0x85,0x91}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xc8,0xcd,0x1e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x6c,0x15}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x80,0x23}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xdd,0x83,0xb1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xe9,0xe1,0xcd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x00,0xf9,0x92}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x59,0x1f,0xf9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0x1d,0xe7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x80,0xfd,0x8e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x8f,0x82,0x38}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x96,0x02,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xee,0x7c,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x52,0xf2,0x00,0xf5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x4c,0x7b,0x6e}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0x96,0x09,0xc4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa1,0x40,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xd4,0x67,0xd4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xd4,0x6f,0x72}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xf6,0x4b,0x08}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xfe,0x51,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xfe,0x96,0x36}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa2,0xc4,0xc0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xa2,0xea,0xe0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xaa,0x68,0x5b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x53,0xff,0x42,0x76}, 8334},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x02,0x22,0x68}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x0f,0x3d,0x3c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x11,0x19,0x87}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2a,0x90,0x13}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xd2,0x87}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd7,0xa5,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2d,0x62,0x5b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0x2f,0xa1,0x96}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd4,0xc0,0x83}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xd7,0xa9,0x65}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xee,0x8c,0xb0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xf0,0x1f,0xb8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x19,0xd6,0x89}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x8b,0xa3,0x84}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x54,0xf5,0x47,0x1f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x11,0x04,0xd4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x72,0x80,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0x9f,0xed,0xbf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xa6,0x82,0xbd}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xc7,0x04,0xe4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0x3d,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0x6c,0x4d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x7b,0x10,0x11}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0x42,0xa8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xd6,0xc3,0xd2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x55,0xe5,0x00,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x56,0x15,0x60,0x2d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x30,0x2a,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x51,0x8f,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x51,0xfb,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x68,0x18,0xb9}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x68,0xa8,0x68}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xe5,0x49,0xab}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0xec,0xc4,0x4d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x61,0x38,0x62}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x86,0xb2,0x59}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x96,0xe9,0x13}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xa8,0x85,0x03}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x12,0xf6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x21,0xca}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x12,0x1c,0x15}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x55,0xdc,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x75,0xea,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x76,0x60,0xc5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x91,0x0c,0x39}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x57,0x9f,0xaa,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0x96,0xa8,0xa0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x00,0x4f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd0,0x00,0x95}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x58,0xd6,0xc2,0xe2}, 8343},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x01,0x0b,0x20}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x24,0xeb,0x6c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x43,0x60,0x02}, 15321},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x62,0x10,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x6c,0x48,0xc3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0x9c,0x23,0x9d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xa3,0xe3,0x1c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xb8,0x53,0x3c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0x21,0xed}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xd4,0xa0,0xa5}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xe7,0x60,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xec,0x31,0x75}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x5a,0x42,0xd1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x59,0xf8,0xa4,0x40}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5a,0x95,0xc1,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x4d,0xef,0xf5}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x6a,0xc2,0x61}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x86,0x4b,0x73}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x98,0xc1,0x24}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x98,0xdb,0x23}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xc5,0x0a,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x7e,0x4d,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x86,0x26,0xc3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0x9c,0x61,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xcf,0x44,0x90}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd1,0x4d,0x65}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd2,0x6a,0x93}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xd6,0xc8,0xcd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdf,0x73,0x26}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xea,0x30,0xe8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xfa,0x56,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdc,0x83,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xdc,0xa3,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5b,0xe9,0x17,0x23}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x0d,0x60,0x5d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x0e,0x4a,0x72}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0x1b,0x07,0xd1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xdd,0xe4,0x0d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5c,0xff,0xcf,0x49}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x48,0xa7,0x94}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x4a,0xa3,0xea}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x54,0x72,0x6a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x7b,0xae,0x42}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0x98,0xa6,0x1d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xab,0xd8,0xdd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xb9,0xb1,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5d,0xb5,0x2d,0xbc}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x13,0x0c,0xf4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x2a,0x73,0x32}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x4f,0xb1,0xce}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x88,0x93,0x77}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0x8f,0xf5,0x05}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xbc,0x32,0x27}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xbe,0xe3,0x70}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xc6,0x87,0x1d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xe0,0xa2,0x41}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xe2,0x6b,0x56}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf2,0xdb,0x5a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf2,0xe5,0xa8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf4,0xa0,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5e,0xf2,0xc6,0xa1}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x1f,0x0a,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x55,0x19,0x29}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x69,0xa1,0x88}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x9a,0xa5,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x9a,0xc8,0xd8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xa7,0x6d,0x7d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd3,0x7d,0xe7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd3,0xd8,0xeb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x21,0x19,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x2b,0x82,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x76,0x08,0xec}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x66,0x06,0x7d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xca,0x14,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xd9,0x7d,0xe1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xea,0xd2,0x6f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xed,0x14,0x7b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xff,0x90,0xb0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0x71,0x40,0x2b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0xe5,0x16,0x08}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x01,0xd4,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x41,0x48,0xf4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x54,0xa2,0x5f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0x5a,0x8b,0x2e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xb7,0x31,0x1b}, 8005},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x5f,0xd7,0x2f,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x17,0x43,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x60,0x2c,0xa6,0xbe}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x61,0x5d,0xe1,0x4a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x1a,0x00,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0x1b,0xe1,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xe5,0x75,0xe5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xf9,0x44,0x7d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x62,0xff,0x05,0x9b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x63,0x65,0xf0,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0x64,0xae,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x65,0xfb,0xcb,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x03,0x3c,0x3d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0x1e,0x2a,0xbd}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xe0,0xa5,0x30}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x67,0xf3,0x5e,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x83,0x6b,0x6b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x83,0x74,0xb8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x24,0x53,0xe9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x25,0x81,0x16}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x36,0xc0,0xfb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x80,0xe4,0xfc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x80,0xe6,0xb9}, 8334},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x82,0xa1,0x2f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x83,0x21,0x3c}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x8f,0x00,0x9c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdb,0xb8,0x09}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0xb9,0x26,0xae}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0x9c,0x6f,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xa7,0x6f,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc1,0x28,0xf8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc5,0x07,0xae}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xc5,0x08,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xdf,0x01,0x85}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xec,0x61,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xee,0x80,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x68,0xee,0x82,0xb6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0x26,0xea,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6a,0xb9,0x24,0xcc}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x06,0x04,0x91}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x08,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x21,0x14}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xaa,0xe4,0x81}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xaa,0xf0,0xad}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x33,0x14,0x56}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3d,0x95,0xde}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x3d,0x97,0xac}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xa1,0x81,0xf7}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0xaa,0x8c,0x15}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x3c,0xd3,0xd8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x49,0x2a,0x24}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x49,0xac,0x8a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x02,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x96,0x28,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0x9b,0x6c,0x82}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xa1,0xb6,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xaa,0x42,0xe7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xbe,0x80,0xe2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6b,0xbf,0x6a,0x73}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x10,0x02,0x3d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0x46,0x04,0xa8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xa2,0x23,0xc4}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xa3,0xeb,0xef}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xbe,0xc4,0xdc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xc9,0x87,0xd8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe4,0x98,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe4,0x9a,0x51}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xe6,0xdc,0x7d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xea,0x9c,0xda}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xeb,0x31,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xeb,0x45,0x54}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x70,0x7c,0x47,0x00}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x71,0x92,0x44,0xfb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x1d,0x11,0x52}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x46,0xb0,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x75,0x29,0xa2,0xb8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x1b,0x08,0xaa}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xe6,0x07,0xd3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xf6,0x47,0x34}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0xac,0x08,0x64}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7a,0x80,0x6d,0x94}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xe7,0xe0,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xbf,0x27,0x3c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xea,0x6a,0xbf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6d,0xee,0x51,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x72,0x4c,0x93,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x1c,0xe0,0x7f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x73,0x44,0x6e,0x52}, 18333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0x61,0x4f,0xda}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x76,0xbd,0xcf,0xc5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x77,0xe4,0x60,0xe9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x78,0x93,0xb2,0x51}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x29,0x7b,0x05}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x79,0x43,0x05,0xe6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7a,0x6b,0x8f,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0x02,0xaa,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0x6e,0x41,0x5e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7b,0xc1,0x8b,0x13}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x7d,0xef,0xa0,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x65,0xa2,0xc1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x6f,0x49,0x0a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0x8c,0xe5,0x49}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xaf,0xc3,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xc7,0xa4,0x60}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xc7,0xfe,0xf4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0x61,0x45,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xc7,0x6b,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xc7,0xc0,0x99}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x80,0xfd,0x03,0xc1}, 20020},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0x7b,0x07,0x07}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0x7b,0x07,0x27}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x81,0xba,0x11,0x11}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0xf7,0xa9,0xbe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x85,0xf2,0xd1,0x3f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0x66,0x5e,0x26}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0x77,0x11,0x91}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0x74,0xa0,0xb0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x82,0x59,0xa0,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0x48,0x8b,0xa4}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x83,0xbf,0x70,0x62}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x85,0x01,0x86,0xa2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x86,0x13,0x84,0x35}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x89,0xe2,0x22,0x2a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8a,0xd2,0xd9,0xaa}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0xff,0xa6,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0x29,0x02,0xac}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8d,0xff,0x80,0xcc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8e,0xd9,0x0c,0x6a}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x8f,0xd7,0x81,0x7e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x90,0x4c,0xf4,0x13}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0x94,0x34,0xa2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0x94,0x50,0x39}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0xb9,0x13,0x1e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0xb9,0x8e,0x56}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0xb9,0xfd,0x33}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x94,0xfb,0x06,0xd6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0x9a,0x9b,0xeb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x92,0x00,0x20,0x65}, 8337},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x93,0xe5,0x0d,0xc7}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xd2,0x85,0xf4}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x97,0xe0,0xf8,0xfc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x79,0x4b,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x7f,0xfb,0x43}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x95,0xd2,0xa2,0xbb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x96,0x65,0xa3,0xf1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x97,0xec,0x0b,0xbd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x99,0x79,0x42,0xd3}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9a,0x14,0x02,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9d,0x0d,0x3d,0x05}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9e,0x3a,0xad,0x30}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x9f,0xfd,0x17,0x84}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x6e,0xda}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd5,0xfe,0xcd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xef,0xfe,0x64}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf2,0x96,0x27}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0x51,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0xeb,0x38}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf4,0x4f,0x10}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf5,0xd9,0x77}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd1,0x6a,0x7b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xd2,0xc6,0xb8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xda,0x41,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xde,0xa1,0x31}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0x84,0x06}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf3,0x84,0x3a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf8,0x63,0xa4}, 53011},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xf8,0x66,0x75}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xfb,0x6c,0x35}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xfe,0x95,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa2,0xff,0x74,0x4e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0x46,0x5e,0x6a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0x58,0x2d,0x7c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0x58,0x78,0xd2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x1a,0x31,0x2b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x1e,0x0e,0x06}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x50,0x72,0xc5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xa7,0xd6,0xf3}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xd0,0xdb,0x6c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xdc,0x43,0x9c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xec,0x65,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xf6,0x6b,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xff,0xed,0xf1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x02,0xd5,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x33,0x17,0xe0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x33,0x7b,0x9f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x39,0xd4,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa3,0x9e,0x23,0x6e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa4,0x0f,0x0a,0xbd}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa4,0x28,0x86,0xab}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa6,0xe6,0x47,0x43}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa7,0xa0,0xa1,0xc7}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0x67,0xc3,0xfa}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0x90,0x1b,0x70}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xa8,0x9e,0x81,0x1d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaa,0x4b,0xa2,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0x5a,0x63,0xae}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xac,0xf5,0x05,0x9c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x17,0xa6,0x2f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x20,0x0b,0xc2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0x22,0xcb,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xab,0x01,0x34}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xaf,0x88,0x0d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xe6,0xe4,0x8b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xad,0xf7,0xc1,0x46}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x31,0x84,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x34,0xca,0x48}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x35,0x4c,0x57}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xae,0x6d,0x21,0x1c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x7e,0x7c,0x5b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xaf,0x7e,0x7c,0x5c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x0a,0x74,0xf2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x23,0x7e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x63,0xde}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x7c,0x6e,0x2f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xc2,0x21,0x2c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0xdf,0xc9,0xc6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x1a,0x53}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x24,0x30}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xd4,0x8d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0xfe,0x3b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x4e,0xfa,0x03}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x9b,0x56,0xe2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x1c,0x0c,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x23,0xb6,0xd6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x21,0x71}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x24,0x21,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x3a,0x60,0xad}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb0,0x79,0x4c,0x54}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x46,0x10}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x3e,0x6f,0x1a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x4c,0xa9,0x3b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0x4f,0x83,0x20}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xa2,0xc7,0xd8}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xaf,0x86,0x23}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xf8,0x6f,0x04}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x01,0xaa}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb2,0xfe,0x22,0xa1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb3,0x2b,0x72,0x0e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb6,0xd5,0xd0,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb3,0x2b,0x8f,0x78}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb3,0xd0,0x9c,0xc6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb4,0xc8,0x80,0x3a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb7,0x4e,0xa9,0x6c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb7,0x60,0x60,0x98}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x44,0x02,0x2e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x48,0xee,0x2a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5e,0xe2,0x22}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x49,0xa0,0xa0}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x5e,0xe3,0x3a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x6b,0x8b,0x3a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x6b,0xce,0x2d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x0a,0x30,0x75}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x15,0xd8,0x9c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x26,0x2f,0xe0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb8,0x98,0x44,0xa3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x07,0x23,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1c,0x4c,0xb3}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x1f,0xa0,0xca}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x2d,0xc0,0x81}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x35,0x81,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x35,0x83,0x72}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x37,0x35,0x3d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x37,0x35,0x3f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x3d,0x77,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x3d,0x94,0xcb}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xb9,0x42,0x8c,0x0f}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xba,0x02,0xa7,0x17}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x5c,0x4b,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x7a,0x5c,0x86}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x8a,0x09,0xd0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa5,0xd1,0x94}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe2,0xce,0xef}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x0a,0x08,0x7c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x0a,0x0a,0x93}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x00,0x82,0x8e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0x59,0x9f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x49,0xea,0x8a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x4b,0x5f,0x6b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x5f,0x64,0x66}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x9b,0x54,0xb5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xa9,0xe9,0xce}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xc6,0x5d,0x56}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xe3,0x87,0xd8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xba,0xdc,0x65,0x8e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x1a,0x05,0x21}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x4b,0x88,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x78,0xc2,0x8c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x79,0x05,0x96}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x8a,0x00,0x72}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0x8a,0x21,0xef}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xa6,0x00,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xb6,0x6c,0x81}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xbf,0x61,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbc,0xe2,0xc6,0x66}, 8001},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x0a,0x09,0xd9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x4b,0x8f,0x90}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbe,0x8b,0x66,0x92}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xbf,0xed,0x40,0x1c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x03,0x83,0x3d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x63,0xe1,0x03}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x6e,0xa0,0x7a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0x92,0x89,0x01}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xb7,0xc6,0xcc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xcb,0xe4,0x47}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x00,0x6d,0x03}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x4d,0x32,0xd0}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x6d,0x44,0x3e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x96,0x79,0x25}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xe0,0x45,0x62}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x4f,0x08,0x25}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x8d,0x56,0x0a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x0c,0xb4,0x5e}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x38,0x3f,0x0a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x74,0x5d,0x5d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x9a,0xae,0xe2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x0c,0xee,0xcc}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0x5b,0xc8,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc1,0xea,0xe1,0x9c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x06,0xe9,0x26}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x3f,0x8f,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc2,0x7e,0x64,0xf6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x86,0x63,0xc3}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x9f,0x6f,0x62}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xa9,0x8a,0x02}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xbd,0x7e,0x23}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0x9f,0xe2,0x8b}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc3,0xc5,0xaf,0xbe}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc5,0xf2,0x5d,0x52}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x0b,0xd6,0x93}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x31,0x29,0x15}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x21,0x7c,0xba}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xcc,0xba,0x92}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xe9,0xee,0x73}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xf1,0xbd,0x42}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x30,0xc7,0x6c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x39,0xd0,0x86}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x39,0xd2,0x1b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0x3e,0x6d,0xdf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xa7,0x8c,0x08}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc6,0xa7,0x8c,0x12}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x5b,0xad,0xea}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0x7f,0xe2,0xf5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc7,0xb4,0x86,0x74}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc8,0x07,0x60,0x63}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc9,0xa0,0x6a,0x56}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x37,0x57,0x2d}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x3c,0x44,0xf2}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x3c,0x45,0xe8}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0xb7,0x97,0x27}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xca,0x7c,0x6d,0x67}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x1e,0xc5,0x4d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x58,0xa0,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0x97,0x8c,0x0e}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcb,0xdb,0x0e,0xcc}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x2c,0x7b,0x6d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x2c,0x7b,0xa2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcc,0x2d,0x78,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0xbe,0x86,0x2c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xce,0xf8,0xb8,0x7f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcd,0x93,0x28,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xeb,0x27,0xd6}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xcf,0xf4,0x49,0x08}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x42,0x1e,0x1b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x51,0x09,0xdf}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x69,0xf3,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x46,0x9f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x8c,0x1e,0xa9}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xa5,0x80,0xeb}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xbe,0x02,0xf2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0x42,0xfe,0xec}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0x49,0x1b,0x21}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x0c,0x40,0xe1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd0,0x4c,0xc8,0xc8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x28,0x60,0x79}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x7e,0x6b,0xb0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0x8d,0x28,0x95}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xbe,0x4b,0x3b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd1,0xd0,0x6f,0x8e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd2,0x36,0x22,0xa4}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd3,0x48,0x42,0xe5}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x19,0x25,0x7c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x47,0xeb,0x72}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x47,0xfc,0x6d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x72,0x30,0x1f}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0xae,0x97,0x76}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x33,0x90,0x2a}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x70,0x21,0x9d}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x74,0x48,0x3f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd4,0x7e,0x0e,0x7a}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x42,0xcd,0xc2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x81,0xf8,0x8b}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x88,0x57,0x22}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa5,0x52,0x85}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa7,0x11,0x06}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xb3,0x9e,0xfd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xbd,0x35,0x7d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xde,0xd0,0x5d}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x31,0x9e,0xa1}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x6f,0xc4,0x15}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x7a,0x6b,0x66}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x88,0x4b,0xaf}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0x9b,0x07,0x18}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa3,0x40,0x1f}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa3,0x40,0xd0}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xa5,0x56,0x88}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd5,0xb8,0x08,0x16}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x0f,0x4e,0xb6}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x37,0x8f,0x9a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x83,0x5b,0x64}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xf5,0xce,0xb5}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x73,0xeb,0x20}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x7e,0xe2,0xa6}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0x91,0x43,0x57}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xa9,0x8d,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xf9,0x5c,0xe6}, 8333},
{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd8,0xfa,0x8a,0xe6}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x0b,0xe1,0xbd}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x06,0x85}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x4b,0x58,0xb2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xac,0x8f,0x8c}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xc3,0xa9,0xd1}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xc4,0xf8,0x6a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdb,0x8a,0xa1,0xa2}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xde,0xa7,0xf8,0x5a}, 8333},
- {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0x12,0xfe,0x37}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x14,0xab,0x2b}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x02,0x47}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x17,0x02,0xf2}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x19,0x09,0x4c}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x28,0xe2,0xa9}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x7b,0x62,0x09}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0x9b,0x24,0x3e}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xd9,0xac,0x20,0x12}, 20993},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0x3d,0xc4,0xca}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xda,0xe7,0xcd,0x29}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdc,0xe9,0x4d,0xc8}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0x12,0xe2,0x55}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0xc5,0xcb,0x52}, 8333},
+ {{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xdf,0xff,0xa6,0x8e}, 8333},
+ {{0x20,0x01,0x12,0x91,0x02,0xbf,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00}, 8333},
+ {{0x20,0x01,0x14,0x18,0x01,0x00,0x05,0xc2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x16,0xd8,0xdd,0x24,0x00,0x00,0x86,0xc9,0x68,0x1e,0xf9,0x31,0x02,0x56}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x16,0x24,0x00,0xe6,0x00,0x00,0x00,0x00,0x57,0x9d,0x94,0x28}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x03,0x00,0x13,0x40,0x02,0x25,0x90,0xff,0xfe,0xc9,0x2b,0x6d}, 8333},
+ {{0x20,0x01,0x19,0xf0,0x40,0x09,0x14,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64}, 8333},
+ {{0x20,0x01,0x1b,0x40,0x50,0x00,0x00,0x2e,0x00,0x00,0x00,0x00,0x3f,0xb0,0x65,0x71}, 8333},
+ {{0x20,0x01,0x04,0x10,0xa0,0x00,0x40,0x50,0x84,0x63,0x90,0xb0,0xff,0xfb,0x4e,0x58}, 8333},
+ {{0x20,0x01,0x04,0x10,0xa0,0x02,0xca,0xfe,0x84,0x63,0x90,0xb0,0xff,0xfb,0x4e,0x58}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x54,0x1e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x6a,0x34,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x6c,0xd3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0x8b,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xa3,0x3d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xb8,0x55,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xc1,0x39,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xc8,0xd7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xdd,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xe2,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xf5,0x9f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xf7,0xcc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x01,0xff,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x2f,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x37,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8200},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x3e,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x86,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0x9c,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xa2,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xad,0xbf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xb7,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xee,0x52,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xf1,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x02,0xfa,0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x51,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x36}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xa1}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0c,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x06,0xf5}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc0}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x52,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0xf2}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x10,0x87,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x4a,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x7c}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0x67,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xb7,0x79,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xc3,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xd2,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xd5,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x08,0xeb,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x16,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x2b,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x3a,0x9c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x49,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x05,0x7b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x5c,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0x6c,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0a,0xf4,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0b,0x08,0x54,0x0b,0x7c,0x0b,0x7c,0x0b,0x7c,0x0b,0x7c}, 8333},
+ {{0x20,0x01,0x41,0xd0,0x00,0x0d,0x11,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x20,0x01,0x44,0xb8,0x41,0x16,0x78,0x01,0x42,0x16,0x7e,0xff,0xfe,0x78,0x3f,0xe4}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x08,0x08,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x08,0x0c,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x09,0x0b,0xca,0x02,0x18,0x7d,0xff,0xfe,0x10,0xbe,0x33}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x0f,0x02,0x2d,0x00,0x00,0x00,0x00,0x02,0x12,0x00,0x26}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x11,0x12,0xd5,0x00,0x00,0x00,0x00,0x0a,0xe1,0x56,0x11}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x14,0x05,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x14,0x00,0x7d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x15,0x05,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x04,0x70,0x1f,0x15,0x0d,0xda,0x3d,0x9a,0x3f,0x11,0x9a,0x56,0xed,0x64}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x25,0x04,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x25,0x00,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x04,0x02,0x6b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x5f,0x00,0x5f,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x32}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x66,0x01,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x67,0x03,0x9d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x71}, 8333},
+ {{0x20,0x01,0x04,0x70,0x6c,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xca,0xfe}, 8333},
+ {{0x20,0x01,0x04,0x70,0x00,0x08,0x02,0xe1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x43}, 8333},
+ {{0x20,0x01,0x04,0x70,0x90,0xa7,0x00,0x96,0x00,0x00,0x00,0x00,0x0a,0xfe,0x60,0x21}, 8333},
+ {{0x20,0x01,0x04,0x70,0x95,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x04,0x70,0xb1,0xd0,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00}, 8333},
+ {{0x20,0x01,0x04,0x70,0xc1,0xf2,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x01}, 8333},
+ {{0x20,0x01,0x04,0x70,0xd0,0x0d,0x00,0x00,0x36,0x64,0xa9,0xff,0xfe,0x9a,0x51,0x50}, 8333},
+ {{0x20,0x01,0x04,0x70,0xe2,0x50,0x00,0x00,0x02,0x11,0x11,0xff,0xfe,0xb9,0x92,0x4c}, 8333},
+ {{0x20,0x01,0x48,0x00,0x78,0x17,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x04,0xdc,0x52}, 8333},
+ {{0x20,0x01,0x48,0x00,0x78,0x19,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x04,0x78,0x09}, 8333},
+ {{0x20,0x01,0x48,0x00,0x78,0x19,0x01,0x04,0xbe,0x76,0x4e,0xff,0xfe,0x05,0xc8,0x28}, 8333},
+ {{0x20,0x01,0x48,0x02,0x78,0x00,0x00,0x02,0x30,0xd7,0x17,0x75,0xff,0x20,0x18,0x58}, 8333},
+ {{0x20,0x01,0x48,0x02,0x78,0x02,0x01,0x01,0xbe,0x76,0x4e,0xff,0xfe,0x20,0x02,0x56}, 8333},
+ {{0x20,0x01,0x48,0x02,0x78,0x02,0x01,0x03,0xbe,0x76,0x4e,0xff,0xfe,0x20,0x2d,0xe8}, 8333},
+ {{0x20,0x01,0x48,0x30,0x11,0x00,0x02,0xe8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xff,0xf7,0x01,0x81,0xde,0xad,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xff,0xfa,0x00,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93}, 8333},
+ {{0x20,0x01,0x4b,0xa0,0xff,0xff,0x01,0xbe,0x00,0x01,0x10,0x05,0x00,0x00,0x00,0x01}, 8335},
+ {{0x20,0x01,0x4c,0x48,0x01,0x10,0x01,0x01,0x02,0x16,0x3e,0xff,0xfe,0x24,0x11,0x62}, 8333},
+ {{0x20,0x01,0x4d,0xd0,0xf1,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x32}, 8333},
+ {{0x20,0x01,0x4d,0xd0,0xff,0x00,0x86,0x7f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x4d,0xd0,0xff,0x00,0x9a,0x67,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x09}, 8333},
+ {{0x20,0x01,0x4d,0xd0,0xff,0x00,0x9c,0x55,0xc2,0x3f,0xd5,0xff,0xfe,0x6c,0x7e,0xe9}, 8333},
+ {{0x20,0x01,0x05,0xc0,0x14,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0xc7}, 8333},
+ {{0x20,0x01,0x05,0xc0,0x14,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x3d,0x01}, 8333},
+ {{0x20,0x01,0x05,0xc0,0x14,0x00,0x00,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0xdf}, 8333},
+ {{0x20,0x01,0x05,0xc0,0x15,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x06,0x10,0x1b,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x06,0x20,0x05,0x00,0xff,0xf0,0xf2,0x1f,0xaf,0xff,0xfe,0xcf,0x91,0xcc}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x12,0x20,0x08,0x0c,0x00,0xad,0x8d,0xe2,0xf7,0xe2,0xc7,0x84}, 8333},
+ {{0x20,0x01,0x06,0x7c,0x21,0xec,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0b}, 8333},
+ {{0x20,0x01,0x06,0xf8,0x12,0x96,0x00,0x00,0x76,0xd4,0x35,0xff,0xfe,0xba,0x1d,0x26}, 8333},
+ {{0x20,0x01,0x08,0x40,0xf0,0x00,0x42,0x50,0x3e,0x4a,0x92,0xff,0xfe,0x6d,0x14,0x5f}, 8333},
+ {{0x20,0x01,0x08,0xd8,0x08,0x40,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x39,0x01,0xae}, 8333},
+ {{0x20,0x01,0x09,0x80,0xef,0xd8,0x00,0x00,0x00,0x21,0xde,0x4a,0x27,0x09,0x09,0x12}, 8333},
+ {{0x20,0x01,0x09,0x81,0x00,0x46,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x20,0x01,0x09,0x81,0x93,0x19,0x00,0x02,0x00,0xc0,0x00,0xa8,0x00,0xc8,0x00,0x08}, 8333},
+ {{0x20,0x01,0x09,0xd8,0xca,0xfe,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x91}, 8333},
+ {{0x20,0x01,0x0a,0xd0,0x00,0x01,0x00,0x01,0x26,0xbe,0x05,0xff,0xfe,0x25,0x95,0x9d}, 8333},
+ {{0x20,0x01,0x0b,0xa8,0x01,0xf1,0xf3,0x4c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x20,0x01,0x0b,0xc8,0x38,0x1c,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x20,0x02,0x17,0x5c,0x4c,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x17,0x5c,0x4c,0xaa}, 8333},
+ {{0x20,0x02,0x44,0x04,0x82,0xf1,0x00,0x00,0x8d,0x55,0x8f,0xbb,0x15,0xfa,0xf4,0xe0}, 8333},
+ {{0x20,0x02,0x44,0x75,0x22,0x33,0x00,0x00,0x02,0x1f,0x5b,0xff,0xfe,0x33,0x9f,0x70}, 8333},
+ {{0x20,0x02,0x59,0x6c,0x48,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x59,0x6c,0x48,0xc3}, 8333},
+ {{0x20,0x02,0x8c,0x6d,0x65,0x21,0x96,0x17,0x12,0xbf,0x48,0xff,0xfe,0xd8,0x17,0x24}, 8333},
+ {{0x20,0x02,0xa6,0x46,0x5e,0x6a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x02}, 8333},
+ {{0x20,0x02,0xb0,0x09,0x20,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x09,0x20,0xc5}, 8333},
+ {{0x24,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x82,0x3e}, 8333},
+ {{0x24,0x00,0x89,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x70,0xd1,0x64}, 8333},
+ {{0x24,0x00,0x89,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x37,0x97,0x61}, 8333},
+ {{0x24,0x03,0x42,0x00,0x04,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff}, 8333},
+ {{0x24,0x03,0xb8,0x00,0x10,0x00,0x00,0x64,0x04,0x0a,0xe9,0xff,0xfe,0x5f,0x94,0xc1}, 8333},
+ {{0x24,0x03,0xb8,0x00,0x10,0x00,0x00,0x64,0x98,0x79,0x17,0xff,0xfe,0x6a,0xa5,0x9f}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0x59,0xb2}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x37,0xa4,0xb1}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x56,0x29,0x73}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x72,0x97}, 8333},
+ {{0x26,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0x8a,0x6e}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0x6a,0xdf}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0xe2,0x17}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0x1b,0x31}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0x2f,0xe1}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0xa0,0x3f}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x5e,0x06}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x56,0xd6,0x45}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0xa3,0xdc}, 8333},
+ {{0x26,0x00,0x3c,0x01,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0xa6,0x59}, 8333},
+ {{0x26,0x00,0x3c,0x02,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x6f,0x0b}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0xf6,0xfb}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x50,0x5f,0xa7}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x18,0x03}, 8333},
+ {{0x26,0x00,0x3c,0x03,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x4a,0xc0}, 8333},
+ {{0x26,0x01,0x00,0x06,0x48,0x00,0x04,0x7f,0x1e,0x4e,0x1f,0x4d,0x33,0x2c,0x3b,0xf6}, 8333},
+ {{0x26,0x01,0x00,0x0d,0x54,0x00,0x0f,0xed,0x8d,0x54,0xc1,0xe8,0x7e,0xd7,0xd4,0x5e}, 8333},
+ {{0x26,0x02,0x01,0x00,0x4b,0x8f,0x6d,0x2a,0x02,0x0c,0x29,0xff,0xfe,0xaf,0xc4,0xc2}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x2d,0x61}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x1f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1f,0x92,0x11}, 8333},
+ {{0x26,0x02,0xff,0xc5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xc5,0xb8,0x44}, 8333},
+ {{0x26,0x02,0xff,0xe8,0x01,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x04,0x57,0x93,0x6b}, 8333},
+ {{0x26,0x02,0xff,0xea,0x10,0x01,0x01,0x25,0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0xd4}, 8333},
+ {{0x26,0x02,0xff,0xea,0x10,0x01,0x06,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x83,0x7d}, 8333},
+ {{0x26,0x02,0xff,0xea,0x10,0x01,0x07,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x57,0x8b}, 8333},
+ {{0x26,0x02,0xff,0xea,0x10,0x01,0x07,0x7a,0x00,0x00,0x00,0x00,0x00,0x00,0x9c,0xae}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x01,0x02,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x6b,0xc8}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x01,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x79,0x68}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x01,0x07,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x82,0xec}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x01,0x09,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe9,0x57}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x01,0x0a,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x4a,0xcb}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x24,0xc4,0xd9,0xfd}, 8333},
+ {{0x26,0x02,0xff,0xea,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x06,0xae,0x32}, 8333},
+ {{0x26,0x04,0x00,0x00,0x00,0xc1,0x01,0x00,0x1e,0xc1,0xde,0xff,0xfe,0x54,0x22,0x35}, 8333},
+ {{0x26,0x04,0x01,0x80,0x00,0x01,0x01,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0xa9}, 8333},
+ {{0x26,0x04,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xb2,0x08,0x03,0x98}, 8333},
+ {{0x26,0x04,0x28,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x72,0x0a,0xed}, 8333},
+ {{0x26,0x04,0x40,0x80,0x11,0x14,0x00,0x00,0x32,0x85,0xa9,0xff,0xfe,0x93,0x85,0x0c}, 8333},
+ {{0x26,0x04,0x7c,0x00,0x00,0x17,0x03,0xd0,0x00,0x00,0x00,0x00,0x00,0x00,0x5a,0x4d}, 8333},
+ {{0x26,0x04,0x9a,0x00,0x21,0x00,0xa0,0x09,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x00,0x01,0x00,0x20,0x00,0x00,0x00,0x00,0x02,0x2a,0x40,0x01}, 8333},
+ {{0x26,0x04,0xa8,0x80,0x08,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x07,0x52,0xf0,0x01}, 8333},
+ {{0x26,0x04,0x0c,0x00,0x00,0x88,0x00,0x32,0x02,0x16,0x3e,0xff,0xfe,0xe4,0xfc,0xca}, 8333},
+ {{0x26,0x04,0x0c,0x00,0x00,0x88,0x00,0x32,0x02,0x16,0x3e,0xff,0xfe,0xf5,0xbc,0x21}, 8333},
+ {{0x26,0x05,0x79,0x80,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x17,0x61,0x3d,0x4e}, 8333},
+ {{0x26,0x05,0xe0,0x00,0x14,0x17,0x40,0x68,0x02,0x23,0x32,0xff,0xfe,0x96,0x0e,0x2d}, 8333},
+ {{0x26,0x06,0x60,0x00,0xa4,0x41,0x99,0x03,0x50,0x54,0x00,0xff,0xfe,0x78,0x66,0xff}, 8333},
+ {{0x26,0x06,0xdf,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0xae,0x85,0x8f,0xc6}, 8333},
+ {{0x26,0x07,0x53,0x00,0x01,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x7f}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xa1}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x11,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x15,0x35,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x1b,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x23,0x37,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x2b,0x90,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x2d,0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x03,0xcb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x4a,0x85,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x51,0x12,0x00,0x00,0x00,0x02,0x4a,0xf5,0x63,0xfe}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x6d,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, 8333},
+ {{0x26,0x07,0x53,0x00,0x00,0x60,0x0a,0x91,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x26,0x07,0xf1,0xc0,0x08,0x20,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x7f,0x3f,0x44}, 8333},
+ {{0x26,0x07,0xf1,0xc0,0x08,0x48,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x94,0x3c}, 8333},
+ {{0x26,0x07,0xf9,0x48,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x04,0xad,0xe5,0x94}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x65,0x9e,0x9c,0xb3}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0xc7,0x4b,0xa8,0xae}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x23,0x00,0x00,0x00,0x00,0x00,0x0d,0x82,0xd8,0xc2}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0x01,0x00,0x43,0x00,0x00,0x00,0x00,0x00,0x87,0x95,0x2f,0xa8}, 8333},
+ {{0x26,0x07,0xfc,0xd0,0xda,0xaa,0x09,0x01,0x00,0x00,0x00,0x00,0x95,0x61,0xe0,0x43}, 8333},
+ {{0x2a,0x00,0x11,0x78,0x00,0x02,0x00,0x43,0x50,0x54,0x00,0xff,0xfe,0xe7,0x2e,0xb6}, 8333},
+ {{0x2a,0x00,0x13,0x28,0xe1,0x00,0xcc,0x42,0x02,0x30,0x48,0xff,0xfe,0x92,0x05,0x5d}, 8333},
+ {{0x2a,0x00,0x14,0xf0,0xe0,0x00,0x80,0xd2,0xcd,0x1a,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x00,0x16,0xd8,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x5b,0x6a,0xc2,0x61}, 8333},
+ {{0x2a,0x00,0x61,0xe0,0x40,0x83,0x6d,0x01,0x68,0x52,0x13,0x76,0xe9,0x72,0x20,0x91}, 8333},
+ {{0x2a,0x00,0x0c,0x98,0x20,0x30,0xa0,0x2f,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x01,0xb0,0x79,0x99,0x04,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x31}, 8333},
+ {{0x2a,0x01,0x01,0xe8,0xe1,0x00,0x81,0x1c,0x70,0x0f,0x65,0xf0,0xf7,0x2a,0x10,0x84}, 8333},
+ {{0x2a,0x01,0x02,0x38,0x42,0xda,0xc5,0x00,0x65,0x46,0x12,0x93,0x54,0x22,0xab,0x40}, 8333},
+ {{0x2a,0x01,0x03,0x48,0x00,0x06,0x04,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x03,0x68,0xe0,0x10,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0x30,0x00,0x17,0x00,0x01,0x00,0x00,0x00,0x00,0xff,0xff,0x05,0x49}, 8333},
+ {{0x2a,0x01,0x04,0x30,0x00,0x17,0x00,0x01,0x00,0x00,0x00,0x00,0xff,0xff,0x08,0x30}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x53,0xa9,0x0d,0x04,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0x57,0xe6,0x57,0x8c,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x66,0x10,0x00,0xb0,0x1c,0x17,0x8d,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0x05,0x23,0xfd,0xce,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0x88,0x00,0x67,0x10,0x00,0xb0,0x1c,0x30,0xab,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x00,0x24,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x00,0x44,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x00,0x51,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x00,0x84,0xa7,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x51,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x10,0x53,0x6e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x62,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x70,0x2e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x80,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x82,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x20,0x84,0x22,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x21,0x11,0xeb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x21,0x02,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x24,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x24,0x2b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x24,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x63,0x2c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x63,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x64,0x26,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x30,0x93,0x4f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x31,0x54,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x40,0x80,0xad,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x41,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x21,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x22,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x05}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x23,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x61,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x70,0x88,0x50,0x54,0x00,0xff,0xfe,0x45,0xbf,0xf2}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x50,0x83,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9001},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x01,0xd8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x51,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x51,0x63,0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 9001},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x52,0x6d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x61,0x93,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x23,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x43,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x73,0x45,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x73,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x62,0x74,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x60,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x63,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x64,0xc9,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x90,0x91,0xce,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x21,0x94,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x83}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x40,0xa1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x04,0xa7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x63,0xb4,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x71,0x21,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x83,0xa2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x91,0x93,0xc4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x60,0xa9,0x00,0x00,0x00,0x01,0x00,0x05,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x73,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x80,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x01,0x92,0x00,0xdb,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x10,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x22,0xe3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x41,0x4e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x63,0xaf,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x22}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x00,0x71,0xe3,0x78,0xb4,0xf3,0xff,0xfe,0xad,0xe8,0xcf}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x51,0x64,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x60,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x01,0x60,0xd5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x02,0x53,0xc3,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x10,0x24,0xaa,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x10,0x50,0x2f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x14,0xcf,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x1a,0x59,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x2a,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x02,0x11,0x0c,0xca,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x22,0xa5,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x50,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x52,0x43,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x74,0xc8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x82,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x00,0xa0,0x82,0x2d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x04,0xf8,0x0d,0x13,0x21,0x83,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x01,0x06,0x08,0xff,0xff,0xa0,0x09,0x8b,0xf5,0x87,0x9d,0xe5,0x1a,0xf8,0x37}, 8333},
+ {{0x2a,0x01,0x07,0x9d,0x46,0x9e,0xed,0x94,0xc2,0x3f,0xd5,0xff,0xfe,0x65,0x20,0xc5}, 8333},
+ {{0x2a,0x01,0x07,0xc8,0xaa,0xb5,0x03,0xe6,0x50,0x54,0x00,0xff,0xfe,0xd7,0x4e,0x54}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0x30,0x1e}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x18,0x77,0x49}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0x2d,0x67}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0x34,0x7c}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x33,0xae,0x50}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x56,0x6b,0x5c}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x56,0xbe,0xe6}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x69,0x48,0x95}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x69,0x99,0x12}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x6e,0x26,0xee}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x73,0x42,0xf1}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0x43,0x4f}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x84,0xb3,0x6b}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x89,0x1f,0xaa}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0x98,0x08,0x16}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xdb,0x35,0x2e}, 8333},
+ {{0x2a,0x01,0x7e,0x00,0x00,0x00,0x00,0x00,0xf0,0x3c,0x91,0xff,0xfe,0xdb,0x4a,0x1d}, 8333},
+ {{0x2a,0x01,0x0e,0x34,0xed,0xbb,0x67,0x50,0x02,0x24,0x1d,0xff,0xfe,0x89,0x38,0x97}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x2f,0x1d,0x3f,0xb0,0x71,0x87,0xc7,0xba,0xbc,0xfc,0x80,0xce}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x87,0x87,0x96,0xf0,0x90,0x32,0x92,0x97,0x39,0xae,0x49,0x6d}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x8a,0x3f,0x47,0xc0,0xc6,0x17,0xfe,0xff,0xfe,0x3c,0x9f,0xbd}, 8333},
+ {{0x2a,0x01,0x0e,0x35,0x8b,0x66,0x06,0xa0,0x49,0x00,0x9d,0xfd,0xd8,0x41,0xd0,0x25}, 8333},
+ {{0x2a,0x02,0x01,0x68,0x4a,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x39}, 8333},
+ {{0x2a,0x02,0x01,0x68,0x54,0x04,0x00,0x02,0xc2,0x3f,0xd5,0xff,0xfe,0x6a,0x51,0x2e}, 8333},
+ {{0x2a,0x02,0x01,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x5b,0x8f,0x53,0x8c}, 8333},
+ {{0x2a,0x02,0x20,0x28,0x10,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02}, 8333},
+ {{0x2a,0x02,0x25,0x28,0x05,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14}, 8333},
+ {{0x2a,0x02,0x25,0x28,0x05,0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x15}, 8333},
+ {{0x2a,0x02,0x25,0x28,0xff,0x00,0x81,0xa6,0x02,0x1e,0xc5,0xff,0xfe,0x8d,0xf9,0xa5}, 8333},
+ {{0x2a,0x02,0x27,0x70,0x00,0x05,0x00,0x00,0x02,0x1a,0x4a,0xff,0xfe,0xe4,0xc7,0xdb}, 8333},
+ {{0x2a,0x02,0x27,0x70,0x00,0x08,0x00,0x00,0x02,0x1a,0x4a,0xff,0xfe,0x7b,0x3d,0xcd}, 8333},
+ {{0x2a,0x02,0x03,0x48,0x00,0x5e,0x5a,0x29,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0x7a,0xa0,0x16,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x2f,0xc0,0x6a}, 8333},
+ {{0x2a,0x02,0x81,0x09,0x8e,0x40,0x35,0xfc,0xba,0x27,0xeb,0xff,0xfe,0xae,0xcf,0x16}, 8333},
+ {{0x2a,0x02,0x0a,0xf8,0x00,0x06,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x30}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x01,0x00,0x00,0x63,0x14,0x22,0x22}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x02,0x00,0x03,0x32,0x95,0x00,0x01}, 8332},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x00,0x00,0x10,0x00,0x03,0x00,0x00,0x54,0x49,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x02,0x00,0x03,0x58,0x99,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xc2,0x00,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x00,0x27,0x05,0x00,0x01}, 8333},
+ {{0x2a,0x02,0xce,0x80,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}, 8333},
+ {{0x2a,0x02,0x0f,0xe0,0xc3,0x21,0x27,0xe0,0x6e,0xf0,0x49,0xff,0xfe,0x11,0xa6,0x1d}, 8333},
+ {{0x2a,0x03,0x40,0x00,0x00,0x02,0x04,0x96,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08}, 8333},
+ {{0x2a,0x03,0xb0,0xc0,0x00,0x00,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x62,0xf0,0x01}, 8333},
+ {{0x2a,0x03,0x0f,0x80,0xed,0x16,0x0c,0xa7,0xea,0x75,0xb1,0x2d,0x02,0xaf,0x9e,0x2a}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0x4a,0xaf,0xa2,0x8c,0x9d,0xf6,0x22,0x18,0x28}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xd9,0xe4,0x70,0x01,0xb3,0xa7,0x9d,0x3e,0x51,0xf9}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe7,0x45,0xd5,0x8b,0xff,0x81,0x9e,0x85,0x00,0xb8}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xff,0xd9,0x7d,0x26,0x57,0x03,0xb0,0x49,0x67,0x4f}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xf9,0xbe,0x9e,0xf0,0x33,0x40,0x2e,0x79,0xc9,0x18}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0f,0x8b,0x1f,0x8d,0x61,0xa6,0x94,0xf4,0x62,0x45}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x26,0x27,0x21,0xa2,0x2c,0x05,0x29,0x20,0xdd}, 8333},
{{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0x26,0x27,0x21,0xae,0x94,0xd5,0xc2,0x72,0x24}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xea,0xb9,0x5b,0x63,0x1d,0x94,0xe2,0xed,0xec,0xa1}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xce,0x36,0xa1,0xc1,0xd6,0x64,0x43,0xfb,0xb3,0xe7}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x26,0xe6,0xdf,0xeb,0xe5,0xc5,0x9a,0x87,0x5e,0x22}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x52,0x71,0xa2,0x43,0x2a,0xe6,0x6c,0x8e,0xe4,0x7b}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0xf4,0x0b,0x4c,0x52,0xd5,0x16,0xcf,0xf5,0x06}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x98,0xff,0x33,0x38,0xbb,0x43,0x08,0x8d,0x95,0x9e}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x16,0x64,0x1b,0x1f,0x8f,0x87,0x18,0x7d,0xa3,0x2b}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xb8,0xda,0x83,0x67,0x90,0x6f,0x46,0x10,0xdb,0x53}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xc3,0x1b,0x22,0x8c,0x89,0x60,0xbf,0xca,0x88,0xa1}, 7033},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x4d,0xe3,0x5b,0x75,0x10,0x46,0x5e,0xf0,0x99,0x8b}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0a,0xba,0x44,0x94,0x9d,0xf5,0xc0,0xaa,0xcd,0x4a}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x96,0x64,0xce,0x6d,0xd4,0xfb,0xa7,0x6b,0x60,0xb5}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe9,0x8f,0x0b,0x72,0xc9,0xf1,0xde,0x62,0xd4,0x66}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x25,0x5c,0xbc,0x34,0xe8,0x9f,0xe4,0x7c,0x90,0x93}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe0,0xa2,0x72,0xef,0xfa,0x7b,0x88,0x95,0x8b,0x9c}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0x69,0xc5,0x40,0xa7,0x95,0xbb,0x25,0xc1,0xfa}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x46,0xa3,0xd9,0x84,0x08,0xc8,0x7f,0xd3,0xeb,0xc5}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0c,0xc4,0xd2,0x4f,0x74,0x99,0xb3,0x8c,0xe8,0x25}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xac,0x9d,0xb8,0xf8,0x4c,0x4b,0x9c,0xc3,0x9c,0xc6}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x7c,0x1d,0x28,0x9f,0xd6,0x28,0x28,0x22,0x4f,0x7a}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xce,0x36,0xa1,0xc1,0xd6,0x64,0x43,0xfb,0xb3,0xe7}, 8333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x8f,0x06,0x4e,0x64,0xbc,0x5e,0x1a,0x8a,0x71,0x97}, 8444}
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x0b,0x29,0x34,0x96,0x29,0xe8,0x67,0x22,0x0c,0x61}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x1c,0x5f,0xc7,0xd4,0x89,0xc0,0x6f,0xa2,0x24,0x71}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x32,0x2e,0xda,0xf7,0xc3,0xf6,0xc3,0x4c,0x3c,0x0d}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x3e,0xaa,0xb7,0xd0,0x79,0x79,0xf3,0x0b,0xd2,0x63}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x39,0xd1,0x5e,0xbd,0xb7,0x23,0x6a,0x12,0xf0,0x0c}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x5e,0x6e,0xf5,0x37,0xcf,0x9b,0xf6,0xe3,0x9f,0xdb}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x64,0x9e,0x79,0x18,0xa8,0x81,0x61,0xd9,0x4d,0xa4}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x68,0xac,0xad,0xae,0x93,0x23,0x0a,0x51,0x3c,0x5c}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x72,0x87,0x94,0x82,0x36,0x22,0x83,0x23,0xb5,0xc5}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x92,0x46,0xe6,0x23,0x98,0x0e,0x87,0x65,0x24,0x22}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa5,0x6c,0xec,0xda,0xeb,0x41,0xdb,0x34,0x18,0x21}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaf,0xb0,0xbc,0xf3,0xa3,0x6f,0x70,0x17,0xab,0x83}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xaa,0xb7,0x04,0x8c,0x87,0xc6,0x38,0x3b,0x0a,0xf6}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xac,0x1f,0x82,0x69,0x5d,0x88,0xa1,0x54,0xf5,0x90}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xbd,0x06,0xa7,0x66,0x63,0x2c,0x65,0x4c,0x61,0xd4}, 8333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xcf,0x7b,0x5e,0x3a,0x53,0x21,0x5b,0x62,0xe3,0x7a}, 8333}
};
static SeedSpec6 pnSeed6_test[] = {
{{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x99,0xcb,0x26,0x31,0xba,0x48,0x51,0x31,0x39,0x0d}, 18333},
- {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x44,0xf4,0xf4,0xf0,0xbf,0xf7,0x7e,0x6d,0xc4,0xe8}, 18333}
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x44,0xf4,0xf4,0xf0,0xbf,0xf7,0x7e,0x6d,0xc4,0xe8}, 18333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x6a,0x8b,0xd2,0x78,0x3f,0x7a,0xf8,0x92,0x8f,0x80}, 18333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xe6,0x4e,0xa4,0x47,0x4e,0x2a,0xfe,0xe8,0x95,0xcc}, 18333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x9f,0xae,0x9f,0x59,0x0b,0x3f,0x31,0x3a,0x8a,0x5f}, 18333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0x47,0xb1,0xe4,0x55,0xd1,0xb0,0x14,0x3f,0xb6,0xdb}, 18333},
+ {{0xfd,0x87,0xd8,0x7e,0xeb,0x43,0xa0,0x60,0x9e,0x46,0x54,0xdb,0x61,0x3b,0xb2,0x6f}, 18333}
};
#endif // BITCOIN_CHAINPARAMSSEEDS_H
diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp
index 2024486139..a9822eed89 100644
--- a/src/checkpoints.cpp
+++ b/src/checkpoints.cpp
@@ -4,6 +4,7 @@
#include "checkpoints.h"
+#include "chain.h"
#include "chainparams.h"
#include "main.h"
#include "uint256.h"
@@ -24,15 +25,6 @@ namespace Checkpoints {
*/
static const double SIGCHECK_VERIFICATION_FACTOR = 5.0;
- bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash)
- {
- const MapCheckpoints& checkpoints = data.mapCheckpoints;
-
- MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
- if (i == checkpoints.end()) return true;
- return hash == i->second;
- }
-
//! Guess how far we are in the verification process at the given block index
double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) {
if (pindex==NULL)
diff --git a/src/checkpoints.h b/src/checkpoints.h
index a720f096c0..5fce6fa81e 100644
--- a/src/checkpoints.h
+++ b/src/checkpoints.h
@@ -10,6 +10,7 @@
#include <map>
class CBlockIndex;
+struct CCheckpointData;
/**
* Block-chain checkpoints are compiled-in sanity checks.
@@ -17,17 +18,6 @@ class CBlockIndex;
*/
namespace Checkpoints
{
-typedef std::map<int, uint256> MapCheckpoints;
-
-struct CCheckpointData {
- MapCheckpoints mapCheckpoints;
- int64_t nTimeLastCheckpoint;
- int64_t nTransactionsLastCheckpoint;
- double fTransactionsPerDay;
-};
-
-//! Returns true if block passes checkpoint checks
-bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash);
//! Return conservative estimate of total number of blocks, 0 if unknown
int GetTotalBlocksEstimate(const CCheckpointData& data);
diff --git a/src/clientversion.h b/src/clientversion.h
index 3c8c969f9d..5a06b310a3 100644
--- a/src/clientversion.h
+++ b/src/clientversion.h
@@ -15,7 +15,7 @@
//! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 0
-#define CLIENT_VERSION_MINOR 10
+#define CLIENT_VERSION_MINOR 11
#define CLIENT_VERSION_REVISION 99
#define CLIENT_VERSION_BUILD 0
diff --git a/src/coincontrol.h b/src/coincontrol.h
index 92fae9847c..bc965f9e19 100644
--- a/src/coincontrol.h
+++ b/src/coincontrol.h
@@ -12,6 +12,10 @@ class CCoinControl
{
public:
CTxDestination destChange;
+ //! If false, allows unselected inputs, but requires all selected inputs be used
+ bool fAllowOtherInputs;
+ //! Includes watch only addresses which match the ISMINE_WATCH_SOLVABLE criteria
+ bool fAllowWatchOnly;
CCoinControl()
{
@@ -21,6 +25,8 @@ public:
void SetNull()
{
destChange = CNoDestination();
+ fAllowOtherInputs = false;
+ fAllowWatchOnly = false;
setSelected.clear();
}
@@ -50,7 +56,7 @@ public:
setSelected.clear();
}
- void ListSelected(std::vector<COutPoint>& vOutpoints)
+ void ListSelected(std::vector<COutPoint>& vOutpoints) const
{
vOutpoints.assign(setSelected.begin(), setSelected.end());
}
diff --git a/src/coins.cpp b/src/coins.cpp
index d79e29951b..f02949de53 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -4,6 +4,7 @@
#include "coins.h"
+#include "memusage.h"
#include "random.h"
#include <assert.h>
@@ -57,13 +58,17 @@ bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStat
CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {}
-CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false) { }
+CCoinsViewCache::CCoinsViewCache(CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false), cachedCoinsUsage(0) { }
CCoinsViewCache::~CCoinsViewCache()
{
assert(!hasModifier);
}
+size_t CCoinsViewCache::DynamicMemoryUsage() const {
+ return memusage::DynamicUsage(cacheCoins) + cachedCoinsUsage;
+}
+
CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const {
CCoinsMap::iterator it = cacheCoins.find(txid);
if (it != cacheCoins.end())
@@ -78,6 +83,7 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
// version as fresh.
ret->second.flags = CCoinsCacheEntry::FRESH;
}
+ cachedCoinsUsage += ret->second.coins.DynamicMemoryUsage();
return ret;
}
@@ -93,6 +99,7 @@ bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
assert(!hasModifier);
std::pair<CCoinsMap::iterator, bool> ret = cacheCoins.insert(std::make_pair(txid, CCoinsCacheEntry()));
+ size_t cachedCoinUsage = 0;
if (ret.second) {
if (!base->GetCoins(txid, ret.first->second.coins)) {
// The parent view does not have this entry; mark it as fresh.
@@ -102,10 +109,12 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
// The parent view only has a pruned entry for this; mark it as fresh.
ret.first->second.flags = CCoinsCacheEntry::FRESH;
}
+ } else {
+ cachedCoinUsage = ret.first->second.coins.DynamicMemoryUsage();
}
// Assume that whenever ModifyCoins is called, the entry will be modified.
ret.first->second.flags |= CCoinsCacheEntry::DIRTY;
- return CCoinsModifier(*this, ret.first);
+ return CCoinsModifier(*this, ret.first, cachedCoinUsage);
}
const CCoins* CCoinsViewCache::AccessCoins(const uint256 &txid) const {
@@ -150,6 +159,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
assert(it->second.flags & CCoinsCacheEntry::FRESH);
CCoinsCacheEntry& entry = cacheCoins[it->first];
entry.coins.swap(it->second.coins);
+ cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
}
} else {
@@ -157,10 +167,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
// The grandparent does not have an entry, and the child is
// modified and being pruned. This means we can just delete
// it from the parent.
+ cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
cacheCoins.erase(itUs);
} else {
// A normal modification.
+ cachedCoinsUsage -= itUs->second.coins.DynamicMemoryUsage();
itUs->second.coins.swap(it->second.coins);
+ cachedCoinsUsage += itUs->second.coins.DynamicMemoryUsage();
itUs->second.flags |= CCoinsCacheEntry::DIRTY;
}
}
@@ -175,6 +188,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
bool CCoinsViewCache::Flush() {
bool fOk = base->BatchWrite(cacheCoins, hashBlock);
cacheCoins.clear();
+ cachedCoinsUsage = 0;
return fOk;
}
@@ -232,7 +246,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
return tx.ComputePriority(dResult);
}
-CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {
+CCoinsModifier::CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage) : cache(cache_), it(it_), cachedCoinUsage(usage) {
assert(!cache.hasModifier);
cache.hasModifier = true;
}
@@ -242,7 +256,11 @@ CCoinsModifier::~CCoinsModifier()
assert(cache.hasModifier);
cache.hasModifier = false;
it->second.coins.Cleanup();
+ cache.cachedCoinsUsage -= cachedCoinUsage; // Subtract the old usage
if ((it->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
cache.cacheCoins.erase(it);
+ } else {
+ // If the coin still exists after the modification, add the new usage
+ cache.cachedCoinsUsage += it->second.coins.DynamicMemoryUsage();
}
}
diff --git a/src/coins.h b/src/coins.h
index fe2eaa08e5..bf4a777b8a 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -7,6 +7,8 @@
#define BITCOIN_COINS_H
#include "compressor.h"
+#include "core_memusage.h"
+#include "memusage.h"
#include "serialize.h"
#include "uint256.h"
@@ -252,6 +254,14 @@ public:
return false;
return true;
}
+
+ size_t DynamicMemoryUsage() const {
+ size_t ret = memusage::DynamicUsage(vout);
+ BOOST_FOREACH(const CTxOut &out, vout) {
+ ret += RecursiveDynamicUsage(out.scriptPubKey);
+ }
+ return ret;
+ }
};
class CCoinsKeyHasher
@@ -356,7 +366,8 @@ class CCoinsModifier
private:
CCoinsViewCache& cache;
CCoinsMap::iterator it;
- CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_);
+ size_t cachedCoinUsage; // Cached memory usage of the CCoins object before modification
+ CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage);
public:
CCoins* operator->() { return &it->second.coins; }
@@ -372,6 +383,7 @@ protected:
/* Whether this cache has an active modifier. */
bool hasModifier;
+
/**
* Make mutable so that we can "fill the cache" even from Get-methods
* declared as "const".
@@ -379,6 +391,9 @@ protected:
mutable uint256 hashBlock;
mutable CCoinsMap cacheCoins;
+ /* Cached dynamic memory usage for the inner CCoins objects. */
+ mutable size_t cachedCoinsUsage;
+
public:
CCoinsViewCache(CCoinsView *baseIn);
~CCoinsViewCache();
@@ -414,6 +429,9 @@ public:
//! Calculate the size of the cache (in number of transactions)
unsigned int GetCacheSize() const;
+ //! Calculate the size of the cache (in bytes)
+ size_t DynamicMemoryUsage() const;
+
/**
* Amount of bitcoins coming in to a transaction
* Note that lightweight clients may not know anything besides the hash of previous transactions,
diff --git a/src/compat.h b/src/compat.h
index 7a5438a11e..5378c2c761 100644
--- a/src/compat.h
+++ b/src/compat.h
@@ -92,4 +92,12 @@ typedef u_int SOCKET;
size_t strnlen( const char *start, size_t max_len);
#endif // HAVE_DECL_STRNLEN
+bool static inline IsSelectableSocket(SOCKET s) {
+#ifdef WIN32
+ return true;
+#else
+ return (s < FD_SETSIZE);
+#endif
+}
+
#endif // BITCOIN_COMPAT_H
diff --git a/src/compat/endian.h b/src/compat/endian.h
index 4d041d6554..9fec2a07fa 100644
--- a/src/compat/endian.h
+++ b/src/compat/endian.h
@@ -15,6 +15,8 @@
#if defined(HAVE_ENDIAN_H)
#include <endian.h>
+#elif defined(HAVE_SYS_ENDIAN_H)
+#include <sys/endian.h>
#endif
#if defined(WORDS_BIGENDIAN)
diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h
index 9c5b7d4ffb..f937844e9f 100644
--- a/src/consensus/consensus.h
+++ b/src/consensus/consensus.h
@@ -12,7 +12,5 @@ static const unsigned int MAX_BLOCK_SIZE = 1000000;
static const unsigned int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE/50;
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 100;
-/** Threshold for nLockTime: below this value it is interpreted as block number, otherwise as UNIX timestamp. */
-static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
#endif // BITCOIN_CONSENSUS_CONSENSUS_H
diff --git a/src/consensus/validation.h b/src/consensus/validation.h
new file mode 100644
index 0000000000..d6051edc38
--- /dev/null
+++ b/src/consensus/validation.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_CONSENSUS_VALIDATION_H
+#define BITCOIN_CONSENSUS_VALIDATION_H
+
+#include <string>
+
+/** "reject" message codes */
+static const unsigned char REJECT_MALFORMED = 0x01;
+static const unsigned char REJECT_INVALID = 0x10;
+static const unsigned char REJECT_OBSOLETE = 0x11;
+static const unsigned char REJECT_DUPLICATE = 0x12;
+static const unsigned char REJECT_NONSTANDARD = 0x40;
+static const unsigned char REJECT_DUST = 0x41;
+static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
+static const unsigned char REJECT_CHECKPOINT = 0x43;
+
+/** Capture information about block/transaction validation */
+class CValidationState {
+private:
+ enum mode_state {
+ MODE_VALID, //! everything ok
+ MODE_INVALID, //! network rule violation (DoS value may be set)
+ MODE_ERROR, //! run-time error
+ } mode;
+ int nDoS;
+ std::string strRejectReason;
+ unsigned int chRejectCode;
+ bool corruptionPossible;
+ std::string strDebugMessage;
+public:
+ CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
+ bool DoS(int level, bool ret = false,
+ unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="",
+ bool corruptionIn=false,
+ const std::string &strDebugMessageIn="") {
+ chRejectCode = chRejectCodeIn;
+ strRejectReason = strRejectReasonIn;
+ corruptionPossible = corruptionIn;
+ strDebugMessage = strDebugMessageIn;
+ if (mode == MODE_ERROR)
+ return ret;
+ nDoS += level;
+ mode = MODE_INVALID;
+ return ret;
+ }
+ bool Invalid(bool ret = false,
+ unsigned int _chRejectCode=0, const std::string &_strRejectReason="",
+ const std::string &_strDebugMessage="") {
+ return DoS(0, ret, _chRejectCode, _strRejectReason, false, _strDebugMessage);
+ }
+ bool Error(const std::string& strRejectReasonIn) {
+ if (mode == MODE_VALID)
+ strRejectReason = strRejectReasonIn;
+ mode = MODE_ERROR;
+ return false;
+ }
+ bool IsValid() const {
+ return mode == MODE_VALID;
+ }
+ bool IsInvalid() const {
+ return mode == MODE_INVALID;
+ }
+ bool IsError() const {
+ return mode == MODE_ERROR;
+ }
+ bool IsInvalid(int &nDoSOut) const {
+ if (IsInvalid()) {
+ nDoSOut = nDoS;
+ return true;
+ }
+ return false;
+ }
+ bool CorruptionPossible() const {
+ return corruptionPossible;
+ }
+ unsigned int GetRejectCode() const { return chRejectCode; }
+ std::string GetRejectReason() const { return strRejectReason; }
+ std::string GetDebugMessage() const { return strDebugMessage; }
+};
+
+#endif // BITCOIN_CONSENSUS_VALIDATION_H
diff --git a/src/core_io.h b/src/core_io.h
index 0989cf7437..115e3199dc 100644
--- a/src/core_io.h
+++ b/src/core_io.h
@@ -15,7 +15,7 @@ class uint256;
class UniValue;
// core_read.cpp
-extern CScript ParseScript(std::string s);
+extern CScript ParseScript(const std::string& s);
extern bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
extern bool DecodeHexBlk(CBlock&, const std::string& strHexBlk);
extern uint256 ParseHashUV(const UniValue& v, const std::string& strName);
diff --git a/src/core_memusage.h b/src/core_memusage.h
new file mode 100644
index 0000000000..711135bb44
--- /dev/null
+++ b/src/core_memusage.h
@@ -0,0 +1,62 @@
+// 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.
+
+#ifndef BITCOIN_CORE_MEMUSAGE_H
+#define BITCOIN_CORE_MEMUSAGE_H
+
+#include "primitives/transaction.h"
+#include "primitives/block.h"
+#include "memusage.h"
+
+static inline size_t RecursiveDynamicUsage(const CScript& script) {
+ return memusage::DynamicUsage(*static_cast<const std::vector<unsigned char>*>(&script));
+}
+
+static inline size_t RecursiveDynamicUsage(const COutPoint& out) {
+ return 0;
+}
+
+static inline size_t RecursiveDynamicUsage(const CTxIn& in) {
+ return RecursiveDynamicUsage(in.scriptSig) + RecursiveDynamicUsage(in.prevout);
+}
+
+static inline size_t RecursiveDynamicUsage(const CTxOut& out) {
+ return RecursiveDynamicUsage(out.scriptPubKey);
+}
+
+static inline size_t RecursiveDynamicUsage(const CTransaction& tx) {
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
+ for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CMutableTransaction& tx) {
+ size_t mem = memusage::DynamicUsage(tx.vin) + memusage::DynamicUsage(tx.vout);
+ for (std::vector<CTxIn>::const_iterator it = tx.vin.begin(); it != tx.vin.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ for (std::vector<CTxOut>::const_iterator it = tx.vout.begin(); it != tx.vout.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CBlock& block) {
+ size_t mem = memusage::DynamicUsage(block.vtx) + memusage::DynamicUsage(block.vMerkleTree);
+ for (std::vector<CTransaction>::const_iterator it = block.vtx.begin(); it != block.vtx.end(); it++) {
+ mem += RecursiveDynamicUsage(*it);
+ }
+ return mem;
+}
+
+static inline size_t RecursiveDynamicUsage(const CBlockLocator& locator) {
+ return memusage::DynamicUsage(locator.vHave);
+}
+
+#endif // BITCOIN_CORE_MEMUSAGE_H
diff --git a/src/core_read.cpp b/src/core_read.cpp
index e064955ff0..f762f2c3b7 100644
--- a/src/core_read.cpp
+++ b/src/core_read.cpp
@@ -22,7 +22,7 @@
using namespace std;
-CScript ParseScript(std::string s)
+CScript ParseScript(const std::string& s)
{
CScript result;
diff --git a/src/ecwrapper.cpp b/src/ecwrapper.cpp
index 5e3aec25ba..f94bc954fd 100644
--- a/src/ecwrapper.cpp
+++ b/src/ecwrapper.cpp
@@ -13,6 +13,29 @@
namespace {
+class ecgroup_order
+{
+public:
+ static const EC_GROUP* get()
+ {
+ static const ecgroup_order wrapper;
+ return wrapper.pgroup;
+ }
+
+private:
+ ecgroup_order()
+ : pgroup(EC_GROUP_new_by_curve_name(NID_secp256k1))
+ {
+ }
+
+ ~ecgroup_order()
+ {
+ EC_GROUP_free(pgroup);
+ }
+
+ EC_GROUP* pgroup;
+};
+
/**
* Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields
* recid selects which key is recovered
@@ -92,8 +115,10 @@ err:
} // anon namespace
CECKey::CECKey() {
- pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
+ pkey = EC_KEY_new();
assert(pkey != NULL);
+ int result = EC_KEY_set_group(pkey, ecgroup_order::get());
+ assert(result);
}
CECKey::~CECKey() {
@@ -185,11 +210,9 @@ bool CECKey::TweakPublic(const unsigned char vchTweak[32]) {
bool CECKey::SanityCheck()
{
- EC_KEY *pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
- if(pkey == NULL)
+ const EC_GROUP *pgroup = ecgroup_order::get();
+ if(pgroup == NULL)
return false;
- EC_KEY_free(pkey);
-
// TODO Is there more EC functionality that could be missing?
return true;
}
diff --git a/src/httprpc.cpp b/src/httprpc.cpp
new file mode 100644
index 0000000000..98ac750bb1
--- /dev/null
+++ b/src/httprpc.cpp
@@ -0,0 +1,193 @@
+#include "httprpc.h"
+
+#include "base58.h"
+#include "chainparams.h"
+#include "httpserver.h"
+#include "rpcprotocol.h"
+#include "rpcserver.h"
+#include "random.h"
+#include "sync.h"
+#include "util.h"
+#include "utilstrencodings.h"
+#include "ui_interface.h"
+
+#include <boost/algorithm/string.hpp> // boost::trim
+
+/** Simple one-shot callback timer to be used by the RPC mechanism to e.g.
+ * re-lock the wellet.
+ */
+class HTTPRPCTimer : public RPCTimerBase
+{
+public:
+ HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
+ ev(eventBase, false, func)
+ {
+ struct timeval tv;
+ tv.tv_sec = millis/1000;
+ tv.tv_usec = (millis%1000)*1000;
+ ev.trigger(&tv);
+ }
+private:
+ HTTPEvent ev;
+};
+
+class HTTPRPCTimerInterface : public RPCTimerInterface
+{
+public:
+ HTTPRPCTimerInterface(struct event_base* base) : base(base)
+ {
+ }
+ const char* Name()
+ {
+ return "HTTP";
+ }
+ RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
+ {
+ return new HTTPRPCTimer(base, func, millis);
+ }
+private:
+ struct event_base* base;
+};
+
+
+/* Pre-base64-encoded authentication token */
+static std::string strRPCUserColonPass;
+/* Stored RPC timer interface (for unregistration) */
+static HTTPRPCTimerInterface* httpRPCTimerInterface = 0;
+
+static void JSONErrorReply(HTTPRequest* req, const UniValue& objError, const UniValue& id)
+{
+ // Send error reply from json-rpc error object
+ int nStatus = HTTP_INTERNAL_SERVER_ERROR;
+ int code = find_value(objError, "code").get_int();
+
+ if (code == RPC_INVALID_REQUEST)
+ nStatus = HTTP_BAD_REQUEST;
+ else if (code == RPC_METHOD_NOT_FOUND)
+ nStatus = HTTP_NOT_FOUND;
+
+ std::string strReply = JSONRPCReply(NullUniValue, objError, id);
+
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(nStatus, strReply);
+}
+
+static bool RPCAuthorized(const std::string& strAuth)
+{
+ if (strRPCUserColonPass.empty()) // Belt-and-suspenders measure if InitRPCAuthentication was not called
+ return false;
+ if (strAuth.substr(0, 6) != "Basic ")
+ return false;
+ std::string strUserPass64 = strAuth.substr(6);
+ boost::trim(strUserPass64);
+ std::string strUserPass = DecodeBase64(strUserPass64);
+ return TimingResistantEqual(strUserPass, strRPCUserColonPass);
+}
+
+static bool HTTPReq_JSONRPC(HTTPRequest* req, const std::string &)
+{
+ // JSONRPC handles only POST
+ if (req->GetRequestMethod() != HTTPRequest::POST) {
+ req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests");
+ return false;
+ }
+ // Check authorization
+ std::pair<bool, std::string> authHeader = req->GetHeader("authorization");
+ if (!authHeader.first) {
+ req->WriteReply(HTTP_UNAUTHORIZED);
+ return false;
+ }
+
+ if (!RPCAuthorized(authHeader.second)) {
+ LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", req->GetPeer().ToString());
+
+ /* Deter brute-forcing
+ If this results in a DoS the user really
+ shouldn't have their RPC port exposed. */
+ MilliSleep(250);
+
+ req->WriteReply(HTTP_UNAUTHORIZED);
+ return false;
+ }
+
+ JSONRequest jreq;
+ try {
+ // Parse request
+ UniValue valRequest;
+ if (!valRequest.read(req->ReadBody()))
+ throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
+
+ std::string strReply;
+ // singleton request
+ if (valRequest.isObject()) {
+ jreq.parse(valRequest);
+
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+
+ // Send reply
+ strReply = JSONRPCReply(result, NullUniValue, jreq.id);
+
+ // array of requests
+ } else if (valRequest.isArray())
+ strReply = JSONRPCExecBatch(valRequest.get_array());
+ else
+ throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
+
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strReply);
+ } catch (const UniValue& objError) {
+ JSONErrorReply(req, objError, jreq.id);
+ return false;
+ } catch (const std::exception& e) {
+ JSONErrorReply(req, JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
+ return false;
+ }
+ return true;
+}
+
+static bool InitRPCAuthentication()
+{
+ if (mapArgs["-rpcpassword"] == "")
+ {
+ LogPrintf("No rpcpassword set - using random cookie authentication\n");
+ if (!GenerateAuthCookie(&strRPCUserColonPass)) {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode
+ "", CClientUIInterface::MSG_ERROR);
+ return false;
+ }
+ } else {
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+ }
+ return true;
+}
+
+bool StartHTTPRPC()
+{
+ LogPrint("rpc", "Starting HTTP RPC server\n");
+ if (!InitRPCAuthentication())
+ return false;
+
+ RegisterHTTPHandler("/", true, HTTPReq_JSONRPC);
+
+ assert(EventBase());
+ httpRPCTimerInterface = new HTTPRPCTimerInterface(EventBase());
+ RPCRegisterTimerInterface(httpRPCTimerInterface);
+ return true;
+}
+
+void InterruptHTTPRPC()
+{
+ LogPrint("rpc", "Interrupting HTTP RPC server\n");
+}
+
+void StopHTTPRPC()
+{
+ LogPrint("rpc", "Stopping HTTP RPC server\n");
+ UnregisterHTTPHandler("/", true);
+ if (httpRPCTimerInterface) {
+ RPCUnregisterTimerInterface(httpRPCTimerInterface);
+ delete httpRPCTimerInterface;
+ httpRPCTimerInterface = 0;
+ }
+}
diff --git a/src/httprpc.h b/src/httprpc.h
new file mode 100644
index 0000000000..d354457188
--- /dev/null
+++ b/src/httprpc.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef BITCOIN_HTTPRPC_H
+#define BITCOIN_HTTPRPC_H
+
+#include <string>
+#include <map>
+
+class HTTPRequest;
+
+/** Start HTTP RPC subsystem.
+ * Precondition; HTTP and RPC has been started.
+ */
+bool StartHTTPRPC();
+/** Interrupt HTTP RPC subsystem.
+ */
+void InterruptHTTPRPC();
+/** Stop HTTP RPC subsystem.
+ * Precondition; HTTP and RPC has been stopped.
+ */
+void StopHTTPRPC();
+
+/** Start HTTP REST subsystem.
+ * Precondition; HTTP and RPC has been started.
+ */
+bool StartREST();
+/** Interrupt RPC REST subsystem.
+ */
+void InterruptREST();
+/** Stop HTTP REST subsystem.
+ * Precondition; HTTP and RPC has been stopped.
+ */
+void StopREST();
+
+#endif
diff --git a/src/httpserver.cpp b/src/httpserver.cpp
new file mode 100644
index 0000000000..600e57b7cc
--- /dev/null
+++ b/src/httpserver.cpp
@@ -0,0 +1,594 @@
+// 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.
+
+#include "httpserver.h"
+
+#include "chainparamsbase.h"
+#include "compat.h"
+#include "util.h"
+#include "netbase.h"
+#include "rpcprotocol.h" // For HTTP status codes
+#include "sync.h"
+#include "ui_interface.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+
+#include <event2/event.h>
+#include <event2/http.h>
+#include <event2/thread.h>
+#include <event2/buffer.h>
+#include <event2/util.h>
+#include <event2/keyvalq_struct.h>
+
+#ifdef EVENT__HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#ifdef _XOPEN_SOURCE_EXTENDED
+#include <arpa/inet.h>
+#endif
+#endif
+
+#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
+#include <boost/foreach.hpp>
+#include <boost/scoped_ptr.hpp>
+
+/** HTTP request work item */
+class HTTPWorkItem : public HTTPClosure
+{
+public:
+ HTTPWorkItem(HTTPRequest* req, const std::string &path, const HTTPRequestHandler& func):
+ req(req), path(path), func(func)
+ {
+ }
+ void operator()()
+ {
+ func(req.get(), path);
+ }
+
+ boost::scoped_ptr<HTTPRequest> req;
+
+private:
+ std::string path;
+ HTTPRequestHandler func;
+};
+
+/** Simple work queue for distributing work over multiple threads.
+ * Work items are simply callable objects.
+ */
+template <typename WorkItem>
+class WorkQueue
+{
+private:
+ /** Mutex protects entire object */
+ CWaitableCriticalSection cs;
+ CConditionVariable cond;
+ /* XXX in C++11 we can use std::unique_ptr here and avoid manual cleanup */
+ std::deque<WorkItem*> queue;
+ bool running;
+ size_t maxDepth;
+
+public:
+ WorkQueue(size_t maxDepth) : running(true),
+ maxDepth(maxDepth)
+ {
+ }
+ /* Precondition: worker threads have all stopped */
+ ~WorkQueue()
+ {
+ while (!queue.empty()) {
+ delete queue.front();
+ queue.pop_front();
+ }
+ }
+ /** Enqueue a work item */
+ bool Enqueue(WorkItem* item)
+ {
+ boost::unique_lock<boost::mutex> lock(cs);
+ if (queue.size() >= maxDepth) {
+ return false;
+ }
+ queue.push_back(item);
+ cond.notify_one();
+ return true;
+ }
+ /** Thread function */
+ void Run()
+ {
+ while (running) {
+ WorkItem* i = 0;
+ {
+ boost::unique_lock<boost::mutex> lock(cs);
+ while (running && queue.empty())
+ cond.wait(lock);
+ if (!running)
+ break;
+ i = queue.front();
+ queue.pop_front();
+ }
+ (*i)();
+ delete i;
+ }
+ }
+ /** Interrupt and exit loops */
+ void Interrupt()
+ {
+ boost::unique_lock<boost::mutex> lock(cs);
+ running = false;
+ cond.notify_all();
+ }
+
+ /** Return current depth of queue */
+ size_t Depth()
+ {
+ boost::unique_lock<boost::mutex> lock(cs);
+ return queue.size();
+ }
+};
+
+struct HTTPPathHandler
+{
+ HTTPPathHandler() {}
+ HTTPPathHandler(std::string prefix, bool exactMatch, HTTPRequestHandler handler):
+ prefix(prefix), exactMatch(exactMatch), handler(handler)
+ {
+ }
+ std::string prefix;
+ bool exactMatch;
+ HTTPRequestHandler handler;
+};
+
+/** HTTP module state */
+
+//! libevent event loop
+static struct event_base* eventBase = 0;
+//! HTTP server
+struct evhttp* eventHTTP = 0;
+//! List of subnets to allow RPC connections from
+static std::vector<CSubNet> rpc_allow_subnets;
+//! Work queue for handling longer requests off the event loop thread
+static WorkQueue<HTTPClosure>* workQueue = 0;
+//! Handlers for (sub)paths
+std::vector<HTTPPathHandler> pathHandlers;
+
+/** Check if a network address is allowed to access the HTTP server */
+static bool ClientAllowed(const CNetAddr& netaddr)
+{
+ if (!netaddr.IsValid())
+ return false;
+ BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ if (subnet.Match(netaddr))
+ return true;
+ return false;
+}
+
+/** Initialize ACL list for HTTP server */
+static bool InitHTTPAllowList()
+{
+ rpc_allow_subnets.clear();
+ rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
+ rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
+ if (mapMultiArgs.count("-rpcallowip")) {
+ const std::vector<std::string>& vAllow = mapMultiArgs["-rpcallowip"];
+ BOOST_FOREACH (std::string strAllow, vAllow) {
+ CSubNet subnet(strAllow);
+ if (!subnet.IsValid()) {
+ uiInterface.ThreadSafeMessageBox(
+ strprintf("Invalid -rpcallowip subnet specification: %s. Valid 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).", strAllow),
+ "", CClientUIInterface::MSG_ERROR);
+ return false;
+ }
+ rpc_allow_subnets.push_back(subnet);
+ }
+ }
+ std::string strAllowed;
+ BOOST_FOREACH (const CSubNet& subnet, rpc_allow_subnets)
+ strAllowed += subnet.ToString() + " ";
+ LogPrint("http", "Allowing HTTP connections from: %s\n", strAllowed);
+ return true;
+}
+
+/** HTTP request method as string - use for logging only */
+static std::string RequestMethodString(HTTPRequest::RequestMethod m)
+{
+ switch (m) {
+ case HTTPRequest::GET:
+ return "GET";
+ break;
+ case HTTPRequest::POST:
+ return "POST";
+ break;
+ case HTTPRequest::HEAD:
+ return "HEAD";
+ break;
+ case HTTPRequest::PUT:
+ return "PUT";
+ break;
+ default:
+ return "unknown";
+ }
+}
+
+/** HTTP request callback */
+static void http_request_cb(struct evhttp_request* req, void* arg)
+{
+ std::auto_ptr<HTTPRequest> hreq(new HTTPRequest(req));
+
+ LogPrint("http", "Received a %s request for %s from %s\n",
+ RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString());
+
+ // Early address-based allow check
+ if (!ClientAllowed(hreq->GetPeer())) {
+ hreq->WriteReply(HTTP_FORBIDDEN);
+ return;
+ }
+
+ // Early reject unknown HTTP methods
+ if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) {
+ hreq->WriteReply(HTTP_BADMETHOD);
+ return;
+ }
+
+ // Find registered handler for prefix
+ std::string strURI = hreq->GetURI();
+ std::string path;
+ std::vector<HTTPPathHandler>::const_iterator i = pathHandlers.begin();
+ std::vector<HTTPPathHandler>::const_iterator iend = pathHandlers.end();
+ for (; i != iend; ++i) {
+ bool match = false;
+ if (i->exactMatch)
+ match = (strURI == i->prefix);
+ else
+ match = (strURI.substr(0, i->prefix.size()) == i->prefix);
+ if (match) {
+ path = strURI.substr(i->prefix.size());
+ break;
+ }
+ }
+
+ // Dispatch to worker thread
+ if (i != iend) {
+ std::auto_ptr<HTTPWorkItem> item(new HTTPWorkItem(hreq.release(), path, i->handler));
+ assert(workQueue);
+ if (workQueue->Enqueue(item.get()))
+ item.release(); /* if true, queue took ownership */
+ else
+ item->req->WriteReply(HTTP_INTERNAL, "Work queue depth exceeded");
+ } else {
+ hreq->WriteReply(HTTP_NOTFOUND);
+ }
+}
+
+/** Event dispatcher thread */
+static void ThreadHTTP(struct event_base* base, struct evhttp* http)
+{
+ RenameThread("bitcoin-http");
+ LogPrint("http", "Entering http event loop\n");
+ event_base_dispatch(base);
+ // Event loop will be interrupted by InterruptHTTPServer()
+ LogPrint("http", "Exited http event loop\n");
+}
+
+/** Bind HTTP server to specified addresses */
+static bool HTTPBindAddresses(struct evhttp* http)
+{
+ int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
+ int nBound = 0;
+ std::vector<std::pair<std::string, uint16_t> > endpoints;
+
+ // Determine what addresses to bind to
+ if (!mapArgs.count("-rpcallowip")) { // Default to loopback if not allowing external IPs
+ endpoints.push_back(std::make_pair("::1", defaultPort));
+ endpoints.push_back(std::make_pair("127.0.0.1", defaultPort));
+ if (mapArgs.count("-rpcbind")) {
+ LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
+ }
+ } else if (mapArgs.count("-rpcbind")) { // Specific bind address
+ const std::vector<std::string>& vbind = mapMultiArgs["-rpcbind"];
+ for (std::vector<std::string>::const_iterator i = vbind.begin(); i != vbind.end(); ++i) {
+ int port = defaultPort;
+ std::string host;
+ SplitHostPort(*i, port, host);
+ endpoints.push_back(std::make_pair(host, port));
+ }
+ } else { // No specific bind address specified, bind to any
+ endpoints.push_back(std::make_pair("::", defaultPort));
+ endpoints.push_back(std::make_pair("0.0.0.0", defaultPort));
+ }
+
+ // Bind addresses
+ for (std::vector<std::pair<std::string, uint16_t> >::iterator i = endpoints.begin(); i != endpoints.end(); ++i) {
+ LogPrint("http", "Binding RPC on address %s port %i\n", i->first, i->second);
+ if (evhttp_bind_socket(http, i->first.empty() ? NULL : i->first.c_str(), i->second) == 0) {
+ nBound += 1;
+ } else {
+ LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second);
+ }
+ }
+ return nBound > 0;
+}
+
+/** Simple wrapper to set thread name and run work queue */
+static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
+{
+ RenameThread("bitcoin-httpworker");
+ queue->Run();
+}
+
+/** libevent event log callback */
+static void libevent_log_cb(int severity, const char *msg)
+{
+ if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
+ LogPrintf("libevent: %s\n", msg);
+ else
+ LogPrint("libevent", "libevent: %s\n", msg);
+}
+
+bool InitHTTPServer()
+{
+ struct evhttp* http = 0;
+ struct event_base* base = 0;
+
+ if (!InitHTTPAllowList())
+ return false;
+
+ if (GetBoolArg("-rpcssl", false)) {
+ uiInterface.ThreadSafeMessageBox(
+ "SSL mode for RPC (-rpcssl) is no longer supported.",
+ "", CClientUIInterface::MSG_ERROR);
+ return false;
+ }
+
+ // Redirect libevent's logging to our own log
+ event_set_log_callback(&libevent_log_cb);
+#if LIBEVENT_VERSION_NUMBER >= 0x02010100
+ // If -debug=libevent, set full libevent debugging.
+ // Otherwise, disable all libevent debugging.
+ if (LogAcceptCategory("libevent"))
+ event_enable_debug_logging(EVENT_DBG_ALL);
+ else
+ event_enable_debug_logging(EVENT_DBG_NONE);
+#endif
+#ifdef WIN32
+ evthread_use_windows_threads();
+#else
+ evthread_use_pthreads();
+#endif
+
+ base = event_base_new(); // XXX RAII
+ if (!base) {
+ LogPrintf("Couldn't create an event_base: exiting\n");
+ return false;
+ }
+
+ /* Create a new evhttp object to handle requests. */
+ http = evhttp_new(base); // XXX RAII
+ if (!http) {
+ LogPrintf("couldn't create evhttp. Exiting.\n");
+ event_base_free(base);
+ return false;
+ }
+
+ evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
+ evhttp_set_max_body_size(http, MAX_SIZE);
+ evhttp_set_gencb(http, http_request_cb, NULL);
+
+ if (!HTTPBindAddresses(http)) {
+ LogPrintf("Unable to bind any endpoint for RPC server\n");
+ evhttp_free(http);
+ event_base_free(base);
+ return false;
+ }
+
+ LogPrint("http", "Initialized HTTP server\n");
+ int workQueueDepth = std::max((long)GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
+ LogPrintf("HTTP: creating work queue of depth %d\n", workQueueDepth);
+
+ workQueue = new WorkQueue<HTTPClosure>(workQueueDepth);
+ eventBase = base;
+ eventHTTP = http;
+ return true;
+}
+
+bool StartHTTPServer(boost::thread_group& threadGroup)
+{
+ LogPrint("http", "Starting HTTP server\n");
+ int rpcThreads = std::max((long)GetArg("-rpcthreads", DEFAULT_HTTP_THREADS), 1L);
+ LogPrintf("HTTP: starting %d worker threads\n", rpcThreads);
+ threadGroup.create_thread(boost::bind(&ThreadHTTP, eventBase, eventHTTP));
+
+ for (int i = 0; i < rpcThreads; i++)
+ threadGroup.create_thread(boost::bind(&HTTPWorkQueueRun, workQueue));
+ return true;
+}
+
+void InterruptHTTPServer()
+{
+ LogPrint("http", "Interrupting HTTP server\n");
+ if (eventBase)
+ event_base_loopbreak(eventBase);
+ if (workQueue)
+ workQueue->Interrupt();
+}
+
+void StopHTTPServer()
+{
+ LogPrint("http", "Stopping HTTP server\n");
+ delete workQueue;
+ if (eventHTTP) {
+ evhttp_free(eventHTTP);
+ eventHTTP = 0;
+ }
+ if (eventBase) {
+ event_base_free(eventBase);
+ eventBase = 0;
+ }
+}
+
+struct event_base* EventBase()
+{
+ return eventBase;
+}
+
+static void httpevent_callback_fn(evutil_socket_t, short, void* data)
+{
+ // Static handler: simply call inner handler
+ HTTPEvent *self = ((HTTPEvent*)data);
+ self->handler();
+ if (self->deleteWhenTriggered)
+ delete self;
+}
+
+HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
+ deleteWhenTriggered(deleteWhenTriggered), handler(handler)
+{
+ ev = event_new(base, -1, 0, httpevent_callback_fn, this);
+ assert(ev);
+}
+HTTPEvent::~HTTPEvent()
+{
+ event_free(ev);
+}
+void HTTPEvent::trigger(struct timeval* tv)
+{
+ if (tv == NULL)
+ event_active(ev, 0, 0); // immediately trigger event in main thread
+ else
+ evtimer_add(ev, tv); // trigger after timeval passed
+}
+HTTPRequest::HTTPRequest(struct evhttp_request* req) : req(req),
+ replySent(false)
+{
+}
+HTTPRequest::~HTTPRequest()
+{
+ if (!replySent) {
+ // Keep track of whether reply was sent to avoid request leaks
+ LogPrintf("%s: Unhandled request\n", __func__);
+ WriteReply(HTTP_INTERNAL, "Unhandled request");
+ }
+ // evhttpd cleans up the request, as long as a reply was sent.
+}
+
+std::pair<bool, std::string> HTTPRequest::GetHeader(const std::string& hdr)
+{
+ const struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
+ assert(headers);
+ const char* val = evhttp_find_header(headers, hdr.c_str());
+ if (val)
+ return std::make_pair(true, val);
+ else
+ return std::make_pair(false, "");
+}
+
+std::string HTTPRequest::ReadBody()
+{
+ struct evbuffer* buf = evhttp_request_get_input_buffer(req);
+ if (!buf)
+ return "";
+ size_t size = evbuffer_get_length(buf);
+ /** Trivial implementation: if this is ever a performance bottleneck,
+ * internal copying can be avoided in multi-segment buffers by using
+ * evbuffer_peek and an awkward loop. Though in that case, it'd be even
+ * better to not copy into an intermediate string but use a stream
+ * abstraction to consume the evbuffer on the fly in the parsing algorithm.
+ */
+ const char* data = (const char*)evbuffer_pullup(buf, size);
+ if (!data) // returns NULL in case of empty buffer
+ return "";
+ std::string rv(data, size);
+ evbuffer_drain(buf, size);
+ return rv;
+}
+
+void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
+{
+ struct evkeyvalq* headers = evhttp_request_get_output_headers(req);
+ assert(headers);
+ evhttp_add_header(headers, hdr.c_str(), value.c_str());
+}
+
+/** Closure sent to main thread to request a reply to be sent to
+ * a HTTP request.
+ * Replies must be sent in the main loop in the main http thread,
+ * this cannot be done from worker threads.
+ */
+void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
+{
+ assert(!replySent && req);
+ // Send event to main http thread to send reply message
+ struct evbuffer* evb = evhttp_request_get_output_buffer(req);
+ assert(evb);
+ evbuffer_add(evb, strReply.data(), strReply.size());
+ HTTPEvent* ev = new HTTPEvent(eventBase, true,
+ boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
+ ev->trigger(0);
+ replySent = true;
+ req = 0; // transferred back to main thread
+}
+
+CService HTTPRequest::GetPeer()
+{
+ evhttp_connection* con = evhttp_request_get_connection(req);
+ CService peer;
+ if (con) {
+ // evhttp retains ownership over returned address string
+ const char* address = "";
+ uint16_t port = 0;
+ evhttp_connection_get_peer(con, (char**)&address, &port);
+ peer = CService(address, port);
+ }
+ return peer;
+}
+
+std::string HTTPRequest::GetURI()
+{
+ return evhttp_request_get_uri(req);
+}
+
+HTTPRequest::RequestMethod HTTPRequest::GetRequestMethod()
+{
+ switch (evhttp_request_get_command(req)) {
+ case EVHTTP_REQ_GET:
+ return GET;
+ break;
+ case EVHTTP_REQ_POST:
+ return POST;
+ break;
+ case EVHTTP_REQ_HEAD:
+ return HEAD;
+ break;
+ case EVHTTP_REQ_PUT:
+ return PUT;
+ break;
+ default:
+ return UNKNOWN;
+ break;
+ }
+}
+
+void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler)
+{
+ LogPrint("http", "Registering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
+ pathHandlers.push_back(HTTPPathHandler(prefix, exactMatch, handler));
+}
+
+void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch)
+{
+ std::vector<HTTPPathHandler>::iterator i = pathHandlers.begin();
+ std::vector<HTTPPathHandler>::iterator iend = pathHandlers.end();
+ for (; i != iend; ++i)
+ if (i->prefix == prefix && i->exactMatch == exactMatch)
+ break;
+ if (i != iend)
+ {
+ LogPrint("http", "Unregistering HTTP handler for %s (exactmatch %d)\n", prefix, exactMatch);
+ pathHandlers.erase(i);
+ }
+}
+
diff --git a/src/httpserver.h b/src/httpserver.h
new file mode 100644
index 0000000000..b377dc19fc
--- /dev/null
+++ b/src/httpserver.h
@@ -0,0 +1,149 @@
+// 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.
+
+#ifndef BITCOIN_HTTPSERVER_H
+#define BITCOIN_HTTPSERVER_H
+
+#include <string>
+#include <stdint.h>
+#include <boost/thread.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/function.hpp>
+
+static const int DEFAULT_HTTP_THREADS=4;
+static const int DEFAULT_HTTP_WORKQUEUE=16;
+static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;
+
+struct evhttp_request;
+struct event_base;
+class CService;
+class HTTPRequest;
+
+/** Initialize HTTP server.
+ * Call this before RegisterHTTPHandler or EventBase().
+ */
+bool InitHTTPServer();
+/** Start HTTP server.
+ * This is separate from InitHTTPServer to give users race-condition-free time
+ * to register their handlers between InitHTTPServer and StartHTTPServer.
+ */
+bool StartHTTPServer(boost::thread_group& threadGroup);
+/** Interrupt HTTP server threads */
+void InterruptHTTPServer();
+/** Stop HTTP server */
+void StopHTTPServer();
+
+/** Handler for requests to a certain HTTP path */
+typedef boost::function<void(HTTPRequest* req, const std::string &)> HTTPRequestHandler;
+/** Register handler for prefix.
+ * If multiple handlers match a prefix, the first-registered one will
+ * be invoked.
+ */
+void RegisterHTTPHandler(const std::string &prefix, bool exactMatch, const HTTPRequestHandler &handler);
+/** Unregister handler for prefix */
+void UnregisterHTTPHandler(const std::string &prefix, bool exactMatch);
+
+/** Return evhttp event base. This can be used by submodules to
+ * queue timers or custom events.
+ */
+struct event_base* EventBase();
+
+/** In-flight HTTP request.
+ * Thin C++ wrapper around evhttp_request.
+ */
+class HTTPRequest
+{
+private:
+ struct evhttp_request* req;
+ bool replySent;
+
+public:
+ HTTPRequest(struct evhttp_request* req);
+ ~HTTPRequest();
+
+ enum RequestMethod {
+ UNKNOWN,
+ GET,
+ POST,
+ HEAD,
+ PUT
+ };
+
+ /** Get requested URI.
+ */
+ std::string GetURI();
+
+ /** Get CService (address:ip) for the origin of the http request.
+ */
+ CService GetPeer();
+
+ /** Get request method.
+ */
+ RequestMethod GetRequestMethod();
+
+ /**
+ * Get the request header specified by hdr, or an empty string.
+ * Return an pair (isPresent,string).
+ */
+ std::pair<bool, std::string> GetHeader(const std::string& hdr);
+
+ /**
+ * Read request body.
+ *
+ * @note As this consumes the underlying buffer, call this only once.
+ * Repeated calls will return an empty string.
+ */
+ std::string ReadBody();
+
+ /**
+ * Write output header.
+ *
+ * @note call this before calling WriteErrorReply or Reply.
+ */
+ void WriteHeader(const std::string& hdr, const std::string& value);
+
+ /**
+ * Write HTTP reply.
+ * nStatus is the HTTP status code to send.
+ * strReply is the body of the reply. Keep it empty to send a standard message.
+ *
+ * @note Can be called only once. As this will give the request back to the
+ * main thread, do not call any other HTTPRequest methods after calling this.
+ */
+ void WriteReply(int nStatus, const std::string& strReply = "");
+};
+
+/** Event handler closure.
+ */
+class HTTPClosure
+{
+public:
+ virtual void operator()() = 0;
+ virtual ~HTTPClosure() {}
+};
+
+/** Event class. This can be used either as an cross-thread trigger or as a timer.
+ */
+class HTTPEvent
+{
+public:
+ /** Create a new event.
+ * deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)
+ * handler is the handler to call when the event is triggered.
+ */
+ HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler);
+ ~HTTPEvent();
+
+ /** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
+ * the given time has elapsed.
+ */
+ void trigger(struct timeval* tv);
+
+ bool deleteWhenTriggered;
+ boost::function<void(void)> handler;
+private:
+ struct event* ev;
+};
+
+#endif // BITCOIN_HTTPSERVER_H
diff --git a/src/init.cpp b/src/init.cpp
index 47cbda32f5..7c3c18acd2 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -11,24 +11,33 @@
#include "addrman.h"
#include "amount.h"
+#include "chain.h"
+#include "chainparams.h"
#include "checkpoints.h"
#include "compat/sanity.h"
+#include "consensus/validation.h"
+#include "httpserver.h"
+#include "httprpc.h"
#include "key.h"
#include "main.h"
#include "miner.h"
#include "net.h"
+#include "policy/policy.h"
#include "rpcserver.h"
#include "script/standard.h"
+#include "scheduler.h"
#include "txdb.h"
+#include "txmempool.h"
#include "ui_interface.h"
#include "util.h"
#include "utilmoneystr.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
+#include "wallet/db.h"
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
-
#include <stdint.h>
#include <stdio.h>
@@ -38,11 +47,17 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
+#include <boost/function.hpp>
#include <boost/interprocess/sync/file_lock.hpp>
#include <boost/thread.hpp>
#include <openssl/crypto.h>
+#if ENABLE_ZMQ
+#include "zmq/zmqnotificationinterface.h"
+#endif
+
using namespace std;
#ifdef ENABLE_WALLET
@@ -50,6 +65,10 @@ CWallet* pwalletMain = NULL;
#endif
bool fFeeEstimatesInitialized = false;
+#if ENABLE_ZMQ
+static CZMQNotificationInterface* pzmqNotificationInterface = NULL;
+#endif
+
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
// accessing block files don't count towards the fd_set size limit
@@ -134,6 +153,15 @@ public:
static CCoinsViewDB *pcoinsdbview = NULL;
static CCoinsViewErrorCatcher *pcoinscatcher = NULL;
+void Interrupt(boost::thread_group& threadGroup)
+{
+ InterruptHTTPServer();
+ InterruptHTTPRPC();
+ InterruptRPC();
+ InterruptREST();
+ threadGroup.interrupt_all();
+}
+
void Shutdown()
{
LogPrintf("%s: In progress...\n", __func__);
@@ -148,12 +176,16 @@ void Shutdown()
/// module was initialized.
RenameThread("bitcoin-shutoff");
mempool.AddTransactionsUpdated(1);
- StopRPCThreads();
+
+ StopHTTPRPC();
+ StopREST();
+ StopRPC();
+ StopHTTPServer();
#ifdef ENABLE_WALLET
if (pwalletMain)
pwalletMain->Flush(false);
- GenerateBitcoins(false, NULL, 0);
#endif
+ GenerateBitcoins(false, 0, Params());
StopNode();
UnregisterNodeSignals(GetNodeSignals());
@@ -186,8 +218,22 @@ void Shutdown()
if (pwalletMain)
pwalletMain->Flush(true);
#endif
+
+#if ENABLE_ZMQ
+ if (pzmqNotificationInterface) {
+ UnregisterValidationInterface(pzmqNotificationInterface);
+ pzmqNotificationInterface->Shutdown();
+ delete pzmqNotificationInterface;
+ pzmqNotificationInterface = NULL;
+ }
+#endif
+
#ifndef WIN32
- boost::filesystem::remove(GetPidFile());
+ try {
+ boost::filesystem::remove(GetPidFile());
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("%s: Unable to remove pidfile: %s\n", __func__, e.what());
+ }
#endif
UnregisterAllValidationInterfaces();
#ifdef ENABLE_WALLET
@@ -252,10 +298,13 @@ void OnRPCPreCommand(const CRPCCommand& cmd)
std::string HelpMessage(HelpMessageMode mode)
{
+ const bool showDebug = GetBoolArg("-help-debug", false);
// When adding new options to the categories, please keep and ensure alphabetical ordering.
+ // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators.
string strUsage = HelpMessageGroup(_("Options:"));
strUsage += HelpMessageOpt("-?", _("This help message"));
+ strUsage += HelpMessageOpt("-alerts", strprintf(_("Receive and display P2P network alerts (default: %u)"), DEFAULT_ALERTS));
strUsage += HelpMessageOpt("-alertnotify=<cmd>", _("Execute command when a relevant alert is received or we see a really long fork (%s in cmd is replaced by message)"));
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288));
@@ -272,11 +321,11 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-loadblock=<file>", _("Imports blocks from external blk000??.dat file") + " " + _("on startup"));
strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS));
strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"),
- -(int)boost::thread::hardware_concurrency(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
+ -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS));
#ifndef WIN32
strUsage += HelpMessageOpt("-pid=<file>", strprintf(_("Specify pid file (default: %s)"), "bitcoind.pid"));
#endif
- strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. "
+ strUsage += HelpMessageOpt("-prune=<n>", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode is incompatible with -txindex and -rescan. "
"Warning: Reverting this setting requires re-downloading the entire blockchain. "
"(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files on startup"));
@@ -297,7 +346,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-externalip=<ip>", _("Specify your own public address"));
strUsage += HelpMessageOpt("-forcednsseed", strprintf(_("Always query for peer addresses via DNS lookup (default: %u)"), 0));
strUsage += HelpMessageOpt("-listen", _("Accept connections from outside (default: 1 if no -proxy or -connect)"));
- strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), 125));
+ strUsage += HelpMessageOpt("-maxconnections=<n>", strprintf(_("Maintain at most <n> connections to peers (default: %u)"), DEFAULT_MAX_PEER_CONNECTIONS));
strUsage += HelpMessageOpt("-maxreceivebuffer=<n>", strprintf(_("Maximum per-connection receive buffer, <n>*1000 bytes (default: %u)"), 5000));
strUsage += HelpMessageOpt("-maxsendbuffer=<n>", strprintf(_("Maximum per-connection send buffer, <n>*1000 bytes (default: %u)"), 1000));
strUsage += HelpMessageOpt("-onion=<ip:port>", strprintf(_("Use separate SOCKS5 proxy to reach peers via Tor hidden services (default: %s)"), "-proxy"));
@@ -310,7 +359,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-timeout=<n>", strprintf(_("Specify connection timeout in milliseconds (minimum: 1, default: %d)"), DEFAULT_CONNECT_TIMEOUT));
#ifdef USE_UPNP
#if USE_UPNP
- strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening)"));
+ strUsage += HelpMessageOpt("-upnp", _("Use UPnP to map the listening port (default: 1 when listening and no -proxy)"));
#else
strUsage += HelpMessageOpt("-upnp", strprintf(_("Use UPnP to map the listening port (default: %u)"), 0));
#endif
@@ -318,76 +367,87 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-whitebind=<addr>", _("Bind to given address and whitelist peers connecting to it. Use [host]:port notation for IPv6"));
strUsage += HelpMessageOpt("-whitelist=<netmask>", _("Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.") +
" " + _("Whitelisted peers cannot be DoS banned and their transactions are always relayed, even if they are already in the mempool, useful e.g. for a gateway"));
-
#ifdef ENABLE_WALLET
strUsage += HelpMessageGroup(_("Wallet options:"));
strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls"));
strUsage += HelpMessageOpt("-keypool=<n>", strprintf(_("Set key pool size to <n> (default: %u)"), 100));
- if (GetBoolArg("-help-debug", false))
- strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for transaction creation (default: %s)"),
- FormatMoney(CWallet::minTxFee.GetFeePerK())));
- strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in BTC/kB) to add to transactions you send (default: %s)"), FormatMoney(payTxFee.GetFeePerK())));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-mintxfee=<amt>", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)",
+ CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-paytxfee=<amt>", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup"));
strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup"));
strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0));
strUsage += HelpMessageOpt("-spendzeroconfchange", strprintf(_("Spend unconfirmed change when sending transactions (default: %u)"), 1));
- strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), 1));
- strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
- FormatMoney(maxTxFee)));
+ strUsage += HelpMessageOpt("-txconfirmtarget=<n>", strprintf(_("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)"), DEFAULT_TX_CONFIRM_TARGET));
+ strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(maxTxFee)));
strUsage += HelpMessageOpt("-upgradewallet", _("Upgrade wallet to latest format") + " " + _("on startup"));
strUsage += HelpMessageOpt("-wallet=<file>", _("Specify wallet file (within data directory)") + " " + strprintf(_("(default: %s)"), "wallet.dat"));
strUsage += HelpMessageOpt("-walletbroadcast", _("Make the wallet broadcast transactions") + " " + strprintf(_("(default: %u)"), true));
strUsage += HelpMessageOpt("-walletnotify=<cmd>", _("Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)"));
strUsage += HelpMessageOpt("-zapwallettxes=<mode>", _("Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup") +
" " + _("(1 = keep tx meta data e.g. account owner and payment request information, 2 = drop tx meta data)"));
-
+#endif
+
+#if ENABLE_ZMQ
+ strUsage += HelpMessageGroup(_("ZeroMQ notification options:"));
+ strUsage += HelpMessageOpt("-zmqpubhashblock=<address>", _("Enable publish hash block in <address>"));
+ strUsage += HelpMessageOpt("-zmqpubhashtransaction=<address>", _("Enable publish hash transaction in <address>"));
+ strUsage += HelpMessageOpt("-zmqpubrawblock=<address>", _("Enable publish raw block in <address>"));
+ strUsage += HelpMessageOpt("-zmqpubrawtransaction=<address>", _("Enable publish raw transaction in <address>"));
#endif
strUsage += HelpMessageGroup(_("Debugging/Testing options:"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-checkpoints", strprintf(_("Only accept block chain matching built-in checkpoints (default: %u)"), 1));
- strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf(_("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)"), 100));
- strUsage += HelpMessageOpt("-disablesafemode", strprintf(_("Disable safemode, override a real safe mode event (default: %u)"), 0));
- strUsage += HelpMessageOpt("-testsafemode", strprintf(_("Force safe mode (default: %u)"), 0));
- strUsage += HelpMessageOpt("-dropmessagestest=<n>", _("Randomly drop 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", _("Randomly fuzz 1 of every <n> network messages"));
- strUsage += HelpMessageOpt("-flushwallet", strprintf(_("Run a thread to flush wallet periodically (default: %u)"), 1));
- strUsage += HelpMessageOpt("-stopafterblockimport", strprintf(_("Stop running after importing blocks from disk (default: %u)"), 0));
+ strUsage += HelpMessageOpt("-checkpoints", strprintf("Disable expensive verification for known chain history (default: %u)", 1));
+ strUsage += HelpMessageOpt("-dblogsize=<n>", strprintf("Flush database activity from memory pool to disk log every <n> megabytes (default: %u)", 100));
+ strUsage += HelpMessageOpt("-disablesafemode", strprintf("Disable safemode, override a real safe mode event (default: %u)", 0));
+ strUsage += HelpMessageOpt("-testsafemode", strprintf("Force safe mode (default: %u)", 0));
+ strUsage += HelpMessageOpt("-dropmessagestest=<n>", "Randomly drop 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-fuzzmessagestest=<n>", "Randomly fuzz 1 of every <n> network messages");
+ strUsage += HelpMessageOpt("-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %u)", 1));
+ strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0));
+ strUsage += HelpMessageOpt("-limitancestorcount=<n>", strprintf("Do not accept transactions if number of in-mempool ancestors is <n> or more (default: %u)", DEFAULT_ANCESTOR_LIMIT));
+ strUsage += HelpMessageOpt("-limitancestorsize=<n>", strprintf("Do not accept transactions whose size with all in-mempool ancestors exceeds <n> kilobytes (default: %u)", DEFAULT_ANCESTOR_SIZE_LIMIT));
+ 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, net, proxy, prune"; // 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"; // 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) + ". " +
- _("If <category> is not supplied, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
-#ifdef ENABLE_WALLET
+ _("If <category> is not supplied or if <category> = 1, output all debugging information.") + _("<category> can be:") + " " + debugCategories + ".");
strUsage += HelpMessageOpt("-gen", strprintf(_("Generate coins (default: %u)"), 0));
strUsage += HelpMessageOpt("-genproclimit=<n>", strprintf(_("Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)"), 1));
-#endif
strUsage += HelpMessageOpt("-help-debug", _("Show all debugging options (usage: --help -help-debug)"));
strUsage += HelpMessageOpt("-logips", strprintf(_("Include IP addresses in debug output (default: %u)"), 0));
strUsage += HelpMessageOpt("-logtimestamps", strprintf(_("Prepend debug output with timestamp (default: %u)"), 1));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf(_("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)"), 15));
- strUsage += HelpMessageOpt("-relaypriority", strprintf(_("Require high priority for relaying free or low-fee transactions (default: %u)"), 1));
- strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf(_("Limit size of signature cache to <n> entries (default: %u)"), 50000));
+ strUsage += HelpMessageOpt("-limitfreerelay=<n>", strprintf("Continuously rate-limit free transactions to <n>*1000 bytes per minute (default: %u)", 15));
+ strUsage += HelpMessageOpt("-relaypriority", strprintf("Require high priority for relaying free or low-fee transactions (default: %u)", 1));
+ strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> entries (default: %u)", 50000));
}
- strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in BTC/Kb) smaller than this are considered zero fee for relaying (default: %s)"), FormatMoney(::minRelayTxFee.GetFeePerK())));
+ strUsage += HelpMessageOpt("-minrelaytxfee=<amt>", strprintf(_("Fees (in %s/kB) smaller than this are considered zero fee for relaying (default: %s)"),
+ CURRENCY_UNIT, FormatMoney(::minRelayTxFee.GetFeePerK())));
strUsage += HelpMessageOpt("-printtoconsole", _("Send trace/debug info to console instead of debug.log file"));
- if (GetBoolArg("-help-debug", false))
+ if (showDebug)
{
- strUsage += HelpMessageOpt("-printpriority", strprintf(_("Log transaction priority and fee per kB when mining blocks (default: %u)"), 0));
- strUsage += HelpMessageOpt("-privdb", strprintf(_("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)"), 1));
- strUsage += HelpMessageOpt("-regtest", _("Enter regression test mode, which uses a special chain in which blocks can be solved instantly.") + " " +
- _("This is intended for regression testing tools and app development.") + " " +
- _("In this mode -genproclimit controls how many blocks are generated immediately."));
+ strUsage += HelpMessageOpt("-printpriority", strprintf("Log transaction priority and fee per kB when mining blocks (default: %u)", 0));
+ strUsage += HelpMessageOpt("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db environment (default: %u)", 1));
+ strUsage += HelpMessageOpt("-regtest", "Enter regression test mode, which uses a special chain in which blocks can be solved instantly. "
+ "This is intended for regression testing tools and app development.");
}
strUsage += HelpMessageOpt("-shrinkdebugfile", _("Shrink debug.log file on client startup (default: 1 when no -debug)"));
strUsage += HelpMessageOpt("-testnet", _("Use the test network"));
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("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), 1));
strUsage += HelpMessageOpt("-datacarriersize", strprintf(_("Maximum size of data in data carrier transactions we relay and mine (default: %u)"), MAX_OP_RETURN_RELAY));
@@ -395,6 +455,8 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-blockminsize=<n>", strprintf(_("Set minimum block size in bytes (default: %u)"), 0));
strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE));
strUsage += HelpMessageOpt("-blockprioritysize=<n>", strprintf(_("Set maximum size of high-priority/low-fee transactions in bytes (default: %d)"), DEFAULT_BLOCK_PRIORITY_SIZE));
+ if (showDebug)
+ strUsage += HelpMessageOpt("-blockversion=<n>", strprintf("Override block version to test forking scenarios (default: %d)", (int)CBlock::CURRENT_VERSION));
strUsage += HelpMessageGroup(_("RPC server options:"));
strUsage += HelpMessageOpt("-server", _("Accept command line and JSON-RPC commands"));
@@ -404,26 +466,26 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
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)"), 4));
- strUsage += HelpMessageOpt("-rpckeepalive", strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 1));
-
- strUsage += HelpMessageGroup(_("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)"));
- strUsage += HelpMessageOpt("-rpcssl", _("Use OpenSSL (https) for JSON-RPC connections"));
- strUsage += HelpMessageOpt("-rpcsslcertificatechainfile=<file.cert>", strprintf(_("Server certificate file (default: %s)"), "server.cert"));
- strUsage += HelpMessageOpt("-rpcsslprivatekeyfile=<file.pem>", strprintf(_("Server private key (default: %s)"), "server.pem"));
- strUsage += HelpMessageOpt("-rpcsslciphers=<ciphers>", strprintf(_("Acceptable ciphers (default: %s)"), "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH"));
+ strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
+ strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT));
+ }
if (mode == HMM_BITCOIN_QT)
{
strUsage += HelpMessageGroup(_("UI Options:"));
- if (GetBoolArg("-help-debug", false)) {
- strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", _("Allow self signed root certificates (default: 0)"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-allowselfsignedrootcertificates", "Allow self signed root certificates (default: 0)");
}
strUsage += HelpMessageOpt("-choosedatadir", _("Choose data directory on startup (default: 0)"));
strUsage += HelpMessageOpt("-lang=<lang>", _("Set language, for example \"de_DE\" (default: system locale)"));
strUsage += HelpMessageOpt("-min", _("Start minimized"));
strUsage += HelpMessageOpt("-rootcertificates=<file>", _("Set SSL root certificates for payment request (default: -system-)"));
strUsage += HelpMessageOpt("-splash", _("Show splash screen on startup (default: 1)"));
+ if (showDebug) {
+ strUsage += HelpMessageOpt("-uiplatform", "Select platform to customize UI for (one of windows, macosx, other; default: platform compiled on)");
+ }
}
return strUsage;
@@ -465,24 +527,43 @@ struct CImportingNow
// If we're using -prune with -reindex, then delete block files that will be ignored by the
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
-// is missing, and since pruning works by deleting the oldest block file first, just check
-// for block file 0, and if it doesn't exist, delete all the block files in the
-// directory (since they won't be read by the reindex but will take up disk space).
-void DeleteAllBlockFiles()
+// is missing, do the same here to delete any later block files after a gap. Also delete all
+// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile
+// is in sync with what's actually on disk by the time we start downloading, so that pruning
+// works correctly.
+void CleanupBlockRevFiles()
{
- if (boost::filesystem::exists(GetBlockPosFilename(CDiskBlockPos(0, 0), "blk")))
- return;
+ using namespace boost::filesystem;
+ map<string, path> mapBlockFiles;
+
+ // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
+ // Remove the rev files immediately and insert the blk file paths into an
+ // ordered map keyed by block file index.
+ LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
+ path blocksdir = GetDataDir() / "blocks";
+ for (directory_iterator it(blocksdir); it != directory_iterator(); it++) {
+ if (is_regular_file(*it) &&
+ it->path().filename().string().length() == 12 &&
+ it->path().filename().string().substr(8,4) == ".dat")
+ {
+ if (it->path().filename().string().substr(0,3) == "blk")
+ mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();
+ else if (it->path().filename().string().substr(0,3) == "rev")
+ remove(it->path());
+ }
+ }
- LogPrintf("Removing all blk?????.dat and rev?????.dat files for -reindex with -prune\n");
- boost::filesystem::path blocksdir = GetDataDir() / "blocks";
- for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) {
- if (is_regular_file(*it)) {
- if ((it->path().filename().string().length() == 12) &&
- (it->path().filename().string().substr(8,4) == ".dat") &&
- ((it->path().filename().string().substr(0,3) == "blk") ||
- (it->path().filename().string().substr(0,3) == "rev")))
- boost::filesystem::remove(it->path());
+ // Remove all block files that aren't part of a contiguous set starting at
+ // zero by walking the ordered map (keys are block file indices) by
+ // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
+ // start removing block files.
+ int nContigCounter = 0;
+ BOOST_FOREACH(const PAIRTYPE(string, path)& item, mapBlockFiles) {
+ if (atoi(item.first) == nContigCounter) {
+ nContigCounter++;
+ continue;
}
+ remove(item.second);
}
}
@@ -527,7 +608,7 @@ void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
}
// -loadblock=
- BOOST_FOREACH(boost::filesystem::path &path, vImportFiles) {
+ BOOST_FOREACH(const boost::filesystem::path& path, vImportFiles) {
FILE *file = fopen(path.string().c_str(), "rb");
if (file) {
CImportingNow imp;
@@ -561,10 +642,27 @@ bool InitSanityCheck(void)
return true;
}
+bool AppInitServers(boost::thread_group& threadGroup)
+{
+ RPCServer::OnStopped(&OnRPCStopped);
+ RPCServer::OnPreCommand(&OnRPCPreCommand);
+ if (!InitHTTPServer())
+ return false;
+ if (!StartRPC())
+ return false;
+ if (!StartHTTPRPC())
+ return false;
+ if (GetBoolArg("-rest", false) && !StartREST())
+ return false;
+ if (!StartHTTPServer(threadGroup))
+ return false;
+ return true;
+}
+
/** Initialize bitcoin.
* @pre Parameters should be parsed and config file should be read.
*/
-bool AppInit2(boost::thread_group& threadGroup)
+bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
{
// ********************************************************* Step 1: setup
#ifdef _MSC_VER
@@ -588,17 +686,12 @@ bool AppInit2(boost::thread_group& threadGroup)
typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE);
-
- // Initialize Windows Sockets
- WSADATA wsadata;
- int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
- if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
- {
- return InitError(strprintf("Error: Winsock library failed to start (WSAStartup returned error %d)", ret));
- }
#endif
-#ifndef WIN32
+ if (!SetupNetworking())
+ return InitError("Error: Initializing networking failed");
+
+#ifndef WIN32
if (GetBoolArg("-sysperms", false)) {
#ifdef ENABLE_WALLET
if (!GetBoolArg("-disablewallet", false))
@@ -623,11 +716,9 @@ bool AppInit2(boost::thread_group& threadGroup)
sa_hup.sa_flags = 0;
sigaction(SIGHUP, &sa_hup, NULL);
-#if defined (__SVR4) && defined (__sun)
- // ignore SIGPIPE on Solaris
+ // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
signal(SIGPIPE, SIG_IGN);
#endif
-#endif
// ********************************************************* Step 2: parameter interactions
const CChainParams& chainparams = Params();
@@ -637,6 +728,9 @@ bool AppInit2(boost::thread_group& threadGroup)
fLogTimestamps = GetBoolArg("-logtimestamps", true);
fLogIPs = GetBoolArg("-logips", false);
+ LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+ LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
// when specifying an explicit binding address, you want to listen on it
// even when -connect or -proxy is specified
if (mapArgs.count("-bind")) {
@@ -660,6 +754,10 @@ bool AppInit2(boost::thread_group& threadGroup)
// to protect privacy, do not listen by default if a default proxy server is specified
if (SoftSetBoolArg("-listen", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__);
+ // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1
+ // to listen locally, so don't rely on this happening through -listen below.
+ if (SoftSetBoolArg("-upnp", false))
+ LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__);
// to protect privacy, do not discover addresses by default
if (SoftSetBoolArg("-discover", false))
LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__);
@@ -691,30 +789,31 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("%s: parameter interaction: -zapwallettxes=<mode> -> setting -rescan=1\n", __func__);
}
- // Make sure enough file descriptors are available
- int nBind = std::max((int)mapArgs.count("-bind") + (int)mapArgs.count("-whitebind"), 1);
- nMaxConnections = GetArg("-maxconnections", 125);
- nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
- int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
- if (nFD < MIN_CORE_FILEDESCRIPTORS)
- return InitError(_("Not enough file descriptors available."));
- if (nFD - MIN_CORE_FILEDESCRIPTORS < nMaxConnections)
- nMaxConnections = nFD - MIN_CORE_FILEDESCRIPTORS;
-
// if using block pruning, then disable txindex
- // also disable the wallet (for now, until SPV support is implemented in wallet)
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", false))
return InitError(_("Prune mode is incompatible with -txindex."));
#ifdef ENABLE_WALLET
- if (!GetBoolArg("-disablewallet", false)) {
- if (SoftSetBoolArg("-disablewallet", true))
- LogPrintf("%s : parameter interaction: -prune -> setting -disablewallet=1\n", __func__);
- else
- return InitError(_("Can't run with a wallet in prune mode."));
+ if (GetBoolArg("-rescan", false)) {
+ return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again."));
}
#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);
+ nMaxConnections = std::max(nUserMaxConnections, 0);
+
+ // Trim requested connection counts, to fit into system limitations
+ nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS)), 0);
+ int nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS);
+ if (nFD < MIN_CORE_FILEDESCRIPTORS)
+ return InitError(_("Not enough file descriptors available."));
+ nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS, nMaxConnections);
+
+ if (nMaxConnections < nUserMaxConnections)
+ InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
// ********************************************************* Step 3: parameter-to-internal-flags
@@ -745,7 +844,7 @@ bool AppInit2(boost::thread_group& threadGroup)
// -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency
nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS);
if (nScriptCheckThreads <= 0)
- nScriptCheckThreads += boost::thread::hardware_concurrency();
+ nScriptCheckThreads += GetNumCores();
if (nScriptCheckThreads <= 1)
nScriptCheckThreads = 0;
else if (nScriptCheckThreads > MAX_SCRIPTCHECK_THREADS)
@@ -775,12 +874,6 @@ bool AppInit2(boost::thread_group& threadGroup)
if (nConnectTimeout <= 0)
nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
- // Continue to put "/P2SH/" in the coinbase to monitor
- // BIP16 support.
- // This can be removed eventually...
- const char* pszP2SH = "/P2SH/";
- COINBASE_FLAGS << std::vector<unsigned char>(pszP2SH, pszP2SH+strlen(pszP2SH));
-
// Fee-per-kilobyte amount considered the same as "free"
// If you are mining, be careful setting this:
// if you set it to zero then
@@ -796,6 +889,10 @@ bool AppInit2(boost::thread_group& threadGroup)
return InitError(strprintf(_("Invalid amount for -minrelaytxfee=<amount>: '%s'"), mapArgs["-minrelaytxfee"]));
}
+ fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !Params().RequireStandard());
+ if (Params().RequireStandard() && !fRequireStandard)
+ return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString()));
+
#ifdef ENABLE_WALLET
if (mapArgs.count("-mintxfee"))
{
@@ -833,16 +930,24 @@ bool AppInit2(boost::thread_group& threadGroup)
mapArgs["-maxtxfee"], ::minRelayTxFee.ToString()));
}
}
- nTxConfirmTarget = GetArg("-txconfirmtarget", 1);
- bSpendZeroConfChange = GetArg("-spendzeroconfchange", true);
- fSendFreeTransactions = GetArg("-sendfreetransactions", false);
+ nTxConfirmTarget = GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
+ bSpendZeroConfChange = GetBoolArg("-spendzeroconfchange", true);
+ fSendFreeTransactions = GetBoolArg("-sendfreetransactions", false);
std::string strWalletFile = GetArg("-wallet", "wallet.dat");
#endif // ENABLE_WALLET
- fIsBareMultisigStd = GetArg("-permitbaremultisig", true) != 0;
+ fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", true);
nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes);
+ fAlerts = GetBoolArg("-alerts", DEFAULT_ALERTS);
+
+ // Option to startup with mocktime set (used for regression testing):
+ SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op
+
+ if (GetBoolArg("-peerbloomfilters", true))
+ nLocalServices |= NODE_BLOOM;
+
// ********************************************************* Step 4: application initialization: dir lock, daemonize, pidfile, debug log
// Initialize elliptic curve code
@@ -862,16 +967,24 @@ bool AppInit2(boost::thread_group& threadGroup)
boost::filesystem::path pathLockFile = GetDataDir() / ".lock";
FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
if (file) fclose(file);
- static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
- if (!lock.try_lock())
- return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running."), strDataDir));
+
+ try {
+ static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
+ if (!lock.try_lock())
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running."), strDataDir));
+ } catch(const boost::interprocess::interprocess_exception& e) {
+ return InitError(strprintf(_("Cannot obtain a lock on data directory %s. Bitcoin Core is probably already running.") + " %s.", strDataDir, e.what()));
+ }
+
#ifndef WIN32
CreatePidFile(GetPidFile(), getpid());
#endif
if (GetBoolArg("-shrinkdebugfile", !fDebug))
ShrinkDebugFile();
- LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
- LogPrintf("Bitcoin version %s (%s)\n", FormatFullVersion(), CLIENT_DATE);
+
+ if (fPrintToDebugLog)
+ OpenDebugLog();
+
LogPrintf("Using OpenSSL version %s\n", SSLeay_version(SSLEAY_VERSION));
#ifdef ENABLE_WALLET
LogPrintf("Using BerkeleyDB version %s\n", DbEnv::version(0, 0, 0));
@@ -890,6 +1003,10 @@ bool AppInit2(boost::thread_group& threadGroup)
threadGroup.create_thread(&ThreadScriptCheck);
}
+ // Start the lightweight task scheduler thread
+ CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler);
+ threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop));
+
/* Start the RPC server already. It will be started in "warmup" mode
* and not really process calls already (but it will signify connections
* that the server is there and will be ready later). Warmup mode will
@@ -898,9 +1015,8 @@ bool AppInit2(boost::thread_group& threadGroup)
if (fServer)
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
- RPCServer::OnStopped(&OnRPCStopped);
- RPCServer::OnPreCommand(&OnRPCPreCommand);
- StartRPCThreads();
+ if (!AppInitServers(threadGroup))
+ return InitError(_("Unable to start HTTP server. See debug log for details."));
}
int64_t nStart;
@@ -913,24 +1029,38 @@ bool AppInit2(boost::thread_group& threadGroup)
std::string warningString;
std::string errorString;
-
+
if (!CWallet::Verify(strWalletFile, warningString, errorString))
return false;
-
+
if (!warningString.empty())
InitWarning(warningString);
if (!errorString.empty())
return InitError(warningString);
-
+
} // (!fDisableWallet)
#endif // ENABLE_WALLET
// ********************************************************* Step 6: network initialization
RegisterNodeSignals(GetNodeSignals());
+ // sanitize comments per BIP-0014, format user agent and check total size
+ std::vector<string> uacomments;
+ BOOST_FOREACH(string cmt, mapMultiArgs["-uacomment"])
+ {
+ if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT))
+ return InitError(strprintf("User Agent comment (%s) contains unsafe characters.", cmt));
+ uacomments.push_back(SanitizeString(cmt, SAFE_CHARS_UA_COMMENT));
+ }
+ strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments);
+ if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) {
+ return InitError(strprintf("Total length of network version string %i exceeds maximum of %i characters. Reduce the number and/or size of uacomments.",
+ strSubVersion.size(), MAX_SUBVERSION_LENGTH));
+ }
+
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
- BOOST_FOREACH(std::string snet, mapMultiArgs["-onlynet"]) {
+ BOOST_FOREACH(const std::string& snet, mapMultiArgs["-onlynet"]) {
enum Network net = ParseNetwork(snet);
if (net == NET_UNROUTABLE)
return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet));
@@ -952,31 +1082,36 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
- proxyType addrProxy;
- bool fProxy = false;
- if (mapArgs.count("-proxy")) {
- addrProxy = proxyType(CService(mapArgs["-proxy"], 9050), GetArg("-proxyrandomize", true));
+ bool proxyRandomize = GetBoolArg("-proxyrandomize", true);
+ // -proxy sets a proxy for all outgoing network traffic
+ // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default
+ std::string proxyArg = GetArg("-proxy", "");
+ if (proxyArg != "" && proxyArg != "0") {
+ proxyType addrProxy = proxyType(CService(proxyArg, 9050), proxyRandomize);
if (!addrProxy.IsValid())
- return InitError(strprintf(_("Invalid -proxy address: '%s'"), mapArgs["-proxy"]));
+ return InitError(strprintf(_("Invalid -proxy address: '%s'"), proxyArg));
SetProxy(NET_IPV4, addrProxy);
SetProxy(NET_IPV6, addrProxy);
+ SetProxy(NET_TOR, addrProxy);
SetNameProxy(addrProxy);
- fProxy = true;
+ SetReachable(NET_TOR); // by default, -proxy sets onion as reachable, unless -noonion later
}
- // -onion can override normal proxy, -noonion disables connecting to .onion entirely
- if (!(mapArgs.count("-onion") && mapArgs["-onion"] == "0") &&
- (fProxy || mapArgs.count("-onion"))) {
- proxyType addrOnion;
- if (!mapArgs.count("-onion"))
- addrOnion = addrProxy;
- else
- addrOnion = proxyType(CService(mapArgs["-onion"], 9050), GetArg("-proxyrandomize", true));
- if (!addrOnion.IsValid())
- return InitError(strprintf(_("Invalid -onion address: '%s'"), mapArgs["-onion"]));
- SetProxy(NET_TOR, addrOnion);
- SetReachable(NET_TOR);
+ // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses
+ // -noonion (or -onion=0) disables connecting to .onion entirely
+ // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none)
+ std::string onionArg = GetArg("-onion", "");
+ if (onionArg != "") {
+ if (onionArg == "0") { // Handle -noonion/-onion=0
+ SetReachable(NET_TOR, false); // set onions as unreachable
+ } else {
+ proxyType addrOnion = proxyType(CService(onionArg, 9050), proxyRandomize);
+ if (!addrOnion.IsValid())
+ return InitError(strprintf(_("Invalid -onion address: '%s'"), onionArg));
+ SetProxy(NET_TOR, addrOnion);
+ SetReachable(NET_TOR);
+ }
}
// see Step 2: parameter interactions for more information about these
@@ -987,13 +1122,13 @@ bool AppInit2(boost::thread_group& threadGroup)
bool fBound = false;
if (fListen) {
if (mapArgs.count("-bind") || mapArgs.count("-whitebind")) {
- BOOST_FOREACH(std::string strBind, mapMultiArgs["-bind"]) {
+ 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));
fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR));
}
- BOOST_FOREACH(std::string strBind, mapMultiArgs["-whitebind"]) {
+ 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));
@@ -1013,7 +1148,7 @@ bool AppInit2(boost::thread_group& threadGroup)
}
if (mapArgs.count("-externalip")) {
- BOOST_FOREACH(string strAddr, mapMultiArgs["-externalip"]) {
+ 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));
@@ -1021,9 +1156,18 @@ bool AppInit2(boost::thread_group& threadGroup)
}
}
- BOOST_FOREACH(string strDest, mapMultiArgs["-seednode"])
+ BOOST_FOREACH(const std::string& strDest, mapMultiArgs["-seednode"])
AddOneShot(strDest);
+#if ENABLE_ZMQ
+ pzmqNotificationInterface = CZMQNotificationInterface::CreateWithArguments(mapArgs);
+
+ if (pzmqNotificationInterface) {
+ pzmqNotificationInterface->Initialize();
+ RegisterValidationInterface(pzmqNotificationInterface);
+ }
+#endif
+
// ********************************************************* Step 7: load block chain
fReindex = GetBoolArg("-reindex", false);
@@ -1056,18 +1200,20 @@ bool AppInit2(boost::thread_group& threadGroup)
}
// cache size calculations
- size_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
- if (nTotalCache < (nMinDbCache << 20))
- nTotalCache = (nMinDbCache << 20); // total cache cannot be less than nMinDbCache
- else if (nTotalCache > (nMaxDbCache << 20))
- nTotalCache = (nMaxDbCache << 20); // total cache cannot be greater than nMaxDbCache
- size_t nBlockTreeDBCache = nTotalCache / 8;
+ int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20);
+ nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache
+ nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greated than nMaxDbcache
+ int64_t nBlockTreeDBCache = nTotalCache / 8;
if (nBlockTreeDBCache > (1 << 21) && !GetBoolArg("-txindex", false))
nBlockTreeDBCache = (1 << 21); // block tree db cache shouldn't be larger than 2 MiB
nTotalCache -= nBlockTreeDBCache;
- size_t nCoinDBCache = nTotalCache / 2; // use half of the remaining cache for coindb cache
+ int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache
nTotalCache -= nCoinDBCache;
- nCoinCacheSize = nTotalCache / 300; // coins in memory require around 300 bytes
+ nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache
+ LogPrintf("Cache configuration:\n");
+ LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024));
+ LogPrintf("* Using %.1fMiB for in-memory UTXO set\n", nCoinCacheUsage * (1.0 / 1024 / 1024));
bool fLoaded = false;
while (!fLoaded) {
@@ -1092,9 +1238,9 @@ bool AppInit2(boost::thread_group& threadGroup)
if (fReindex) {
pblocktree->WriteReindexing(true);
- //If we're reindexing in prune mode, wipe away all our block and undo data files
+ //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (fPruneMode)
- DeleteAllBlockFiles();
+ CleanupBlockRevFiles();
}
if (!LoadBlockIndex()) {
@@ -1131,6 +1277,18 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("Prune: pruned datadir may not have more than %d blocks; -checkblocks=%d may fail\n",
MIN_BLOCKS_TO_KEEP, GetArg("-checkblocks", 288));
}
+
+ {
+ LOCK(cs_main);
+ CBlockIndex* tip = chainActive.Tip();
+ if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) {
+ strLoadError = _("The block database contains a block which appears to be from the future. "
+ "This may be due to your computer's date and time being set incorrectly. "
+ "Only rebuild the block database if you are sure that your computer's date and time are correct");
+ break;
+ }
+ }
+
if (!CVerifyDB().VerifyDB(pcoinsdbview, GetArg("-checklevel", 3),
GetArg("-checkblocks", 288))) {
strLoadError = _("Corrupted block database detected");
@@ -1181,15 +1339,6 @@ bool AppInit2(boost::thread_group& threadGroup)
mempool.ReadFeeEstimates(est_filein);
fFeeEstimatesInitialized = true;
- // if prune mode, unset NODE_NETWORK and prune block files
- if (fPruneMode) {
- LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
- nLocalServices &= ~NODE_NETWORK;
- if (!fReindex) {
- PruneAndFlush();
- }
- }
-
// ********************************************************* Step 8: load wallet
#ifdef ENABLE_WALLET
if (fDisableWallet) {
@@ -1292,6 +1441,19 @@ bool AppInit2(boost::thread_group& threadGroup)
}
if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{
+ //We can't rescan beyond non-pruned blocks, stop and throw an error
+ //this might happen if a user uses a old wallet within a pruned node
+ // or if he ran -disablewallet for a longer time, then decided to re-enable
+ if (fPruneMode)
+ {
+ CBlockIndex *block = chainActive.Tip();
+ while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA) && block->pprev->nTx > 0 && pindexRescan != block)
+ block = block->pprev;
+
+ if (pindexRescan != block)
+ return InitError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)"));
+ }
+
uiInterface.InitMessage(_("Rescanning..."));
LogPrintf("Rescanning last %i blocks (from block %i)...\n", chainActive.Height() - pindexRescan->nHeight, pindexRescan->nHeight);
nStart = GetTimeMillis();
@@ -1328,9 +1490,23 @@ bool AppInit2(boost::thread_group& threadGroup)
pwalletMain->SetBroadcastTransactions(GetBoolArg("-walletbroadcast", true));
} // (!fDisableWallet)
#else // ENABLE_WALLET
- LogPrintf("No wallet compiled in!\n");
+ LogPrintf("No wallet support compiled in!\n");
#endif // !ENABLE_WALLET
- // ********************************************************* Step 9: import blocks
+
+ // ********************************************************* Step 9: data directory maintenance
+
+ // if pruning, unset the service bit and perform the initial blockstore prune
+ // after any wallet rescanning has taken place.
+ if (fPruneMode) {
+ uiInterface.InitMessage(_("Pruning blockstore..."));
+ LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
+ nLocalServices &= ~NODE_NETWORK;
+ if (!fReindex) {
+ PruneAndFlush();
+ }
+ }
+
+ // ********************************************************* Step 10: import blocks
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
@@ -1344,7 +1520,7 @@ bool AppInit2(boost::thread_group& threadGroup)
std::vector<boost::filesystem::path> vImportFiles;
if (mapArgs.count("-loadblock"))
{
- BOOST_FOREACH(string strFile, mapMultiArgs["-loadblock"])
+ BOOST_FOREACH(const std::string& strFile, mapMultiArgs["-loadblock"])
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles));
@@ -1354,7 +1530,7 @@ bool AppInit2(boost::thread_group& threadGroup)
MilliSleep(10);
}
- // ********************************************************* Step 10: start node
+ // ********************************************************* Step 11: start node
if (!CheckDiskSpace())
return false;
@@ -1373,13 +1549,16 @@ bool AppInit2(boost::thread_group& threadGroup)
LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0);
#endif
- StartNode(threadGroup);
+ StartNode(threadGroup, scheduler);
+
+ // Monitor the chain, and alert if we get blocks much quicker or slower than expected
+ int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
+ CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
+ boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
+ scheduler.scheduleEvery(f, nPowTargetSpacing);
-#ifdef ENABLE_WALLET
// Generate coins in the background
- if (pwalletMain)
- GenerateBitcoins(GetBoolArg("-gen", false), pwalletMain, GetArg("-genproclimit", 1));
-#endif
+ GenerateBitcoins(GetBoolArg("-gen", false), GetArg("-genproclimit", 1), Params());
// ********************************************************* Step 11: finished
diff --git a/src/init.h b/src/init.h
index d451f65be9..8cd51b0286 100644
--- a/src/init.h
+++ b/src/init.h
@@ -8,6 +8,7 @@
#include <string>
+class CScheduler;
class CWallet;
namespace boost
@@ -19,8 +20,10 @@ extern CWallet* pwalletMain;
void StartShutdown();
bool ShutdownRequested();
+/** Interrupt threads */
+void Interrupt(boost::thread_group& threadGroup);
void Shutdown();
-bool AppInit2(boost::thread_group& threadGroup);
+bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler);
/** The help message mode determines what help message to show */
enum HelpMessageMode {
diff --git a/src/json/LICENSE.txt b/src/json/LICENSE.txt
deleted file mode 100644
index 797d5363b3..0000000000
--- a/src/json/LICENSE.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-The MIT License
-
-Copyright (c) 2007 - 2009 John W. Wilkinson
-
-Permission is hereby granted, free of charge, to any person
-obtaining a copy of this software and associated documentation
-files (the "Software"), to deal in the Software without
-restriction, including without limitation the rights to use,
-copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the
-Software is furnished to do so, subject to the following
-conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
diff --git a/src/json/json_spirit.h b/src/json/json_spirit.h
deleted file mode 100644
index ac1879d5b3..0000000000
--- a/src/json/json_spirit.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef JSON_SPIRIT
-#define JSON_SPIRIT
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include "json_spirit_reader.h"
-#include "json_spirit_writer.h"
-#include "json_spirit_utils.h"
-
-#endif
diff --git a/src/json/json_spirit_error_position.h b/src/json/json_spirit_error_position.h
deleted file mode 100644
index 17208507df..0000000000
--- a/src/json/json_spirit_error_position.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef JSON_SPIRIT_ERROR_POSITION
-#define JSON_SPIRIT_ERROR_POSITION
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include <string>
-
-namespace json_spirit
-{
- // An Error_position exception is thrown by the "read_or_throw" functions below on finding an error.
- // Note the "read_or_throw" functions are around 3 times slower than the standard functions "read"
- // functions that return a bool.
- //
- struct Error_position
- {
- Error_position();
- Error_position( unsigned int line, unsigned int column, const std::string& reason );
- bool operator==( const Error_position& lhs ) const;
- unsigned int line_;
- unsigned int column_;
- std::string reason_;
- };
-
- inline Error_position::Error_position()
- : line_( 0 )
- , column_( 0 )
- {
- }
-
- inline Error_position::Error_position( unsigned int line, unsigned int column, const std::string& reason )
- : line_( line )
- , column_( column )
- , reason_( reason )
- {
- }
-
- inline bool Error_position::operator==( const Error_position& lhs ) const
- {
- if( this == &lhs ) return true;
-
- return ( reason_ == lhs.reason_ ) &&
- ( line_ == lhs.line_ ) &&
- ( column_ == lhs.column_ );
-}
-}
-
-#endif
diff --git a/src/json/json_spirit_reader.cpp b/src/json/json_spirit_reader.cpp
deleted file mode 100644
index aa4f637226..0000000000
--- a/src/json/json_spirit_reader.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_reader.h"
-#include "json_spirit_reader_template.h"
-
-using namespace json_spirit;
-
-bool json_spirit::read( const std::string& s, Value& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::string& s, Value& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::istream& is, Value& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::istream& is, Value& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-bool json_spirit::read( const std::wstring& s, wValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::wstring& s, wValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::wistream& is, wValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::wistream& is, wValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#endif
-
-bool json_spirit::read( const std::string& s, mValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::string& s, mValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::istream& is, mValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::istream& is, mValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-bool json_spirit::read( const std::wstring& s, wmValue& value )
-{
- return read_string( s, value );
-}
-
-void json_spirit::read_or_throw( const std::wstring& s, wmValue& value )
-{
- read_string_or_throw( s, value );
-}
-
-bool json_spirit::read( std::wistream& is, wmValue& value )
-{
- return read_stream( is, value );
-}
-
-void json_spirit::read_or_throw( std::wistream& is, wmValue& value )
-{
- read_stream_or_throw( is, value );
-}
-
-bool json_spirit::read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
-{
- return read_range( begin, end, value );
-}
-
-void json_spirit::read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value )
-{
- begin = read_range_or_throw( begin, end, value );
-}
-
-#endif
diff --git a/src/json/json_spirit_reader.h b/src/json/json_spirit_reader.h
deleted file mode 100644
index 96494a9789..0000000000
--- a/src/json/json_spirit_reader.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef JSON_SPIRIT_READER
-#define JSON_SPIRIT_READER
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include "json_spirit_error_position.h"
-#include <iostream>
-
-namespace json_spirit
-{
- // functions to reads a JSON values
-
- bool read( const std::string& s, Value& value );
- bool read( std::istream& is, Value& value );
- bool read( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
-
- void read_or_throw( const std::string& s, Value& value );
- void read_or_throw( std::istream& is, Value& value );
- void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, Value& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- bool read( const std::wstring& s, wValue& value );
- bool read( std::wistream& is, wValue& value );
- bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
-
- void read_or_throw( const std::wstring& s, wValue& value );
- void read_or_throw( std::wistream& is, wValue& value );
- void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wValue& value );
-
-#endif
-
- bool read( const std::string& s, mValue& value );
- bool read( std::istream& is, mValue& value );
- bool read( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
-
- void read_or_throw( const std::string& s, mValue& value );
- void read_or_throw( std::istream& is, mValue& value );
- void read_or_throw( std::string::const_iterator& begin, std::string::const_iterator end, mValue& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- bool read( const std::wstring& s, wmValue& value );
- bool read( std::wistream& is, wmValue& value );
- bool read( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
-
- void read_or_throw( const std::wstring& s, wmValue& value );
- void read_or_throw( std::wistream& is, wmValue& value );
- void read_or_throw( std::wstring::const_iterator& begin, std::wstring::const_iterator end, wmValue& value );
-
-#endif
-}
-
-#endif
diff --git a/src/json/json_spirit_reader_template.h b/src/json/json_spirit_reader_template.h
deleted file mode 100644
index 46f5892f62..0000000000
--- a/src/json/json_spirit_reader_template.h
+++ /dev/null
@@ -1,612 +0,0 @@
-#ifndef JSON_SPIRIT_READER_TEMPLATE
-#define JSON_SPIRIT_READER_TEMPLATE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_value.h"
-#include "json_spirit_error_position.h"
-
-//#define BOOST_SPIRIT_THREADSAFE // uncomment for multithreaded use, requires linking to boost.thread
-
-#include <boost/bind.hpp>
-#include <boost/function.hpp>
-#include <boost/version.hpp>
-
-#if BOOST_VERSION >= 103800
- #include <boost/spirit/include/classic_core.hpp>
- #include <boost/spirit/include/classic_confix.hpp>
- #include <boost/spirit/include/classic_escape_char.hpp>
- #include <boost/spirit/include/classic_multi_pass.hpp>
- #include <boost/spirit/include/classic_position_iterator.hpp>
- #define spirit_namespace boost::spirit::classic
-#else
- #include <boost/spirit/core.hpp>
- #include <boost/spirit/utility/confix.hpp>
- #include <boost/spirit/utility/escape_char.hpp>
- #include <boost/spirit/iterator/multi_pass.hpp>
- #include <boost/spirit/iterator/position_iterator.hpp>
- #define spirit_namespace boost::spirit
-#endif
-
-namespace json_spirit
-{
- const spirit_namespace::int_parser < int64_t > int64_p = spirit_namespace::int_parser < int64_t >();
- const spirit_namespace::uint_parser< uint64_t > uint64_p = spirit_namespace::uint_parser< uint64_t >();
-
- template< class Iter_type >
- bool is_eq( Iter_type first, Iter_type last, const char* c_str )
- {
- for( Iter_type i = first; i != last; ++i, ++c_str )
- {
- if( *c_str == 0 ) return false;
-
- if( *i != *c_str ) return false;
- }
-
- return true;
- }
-
- template< class Char_type >
- Char_type hex_to_num( const Char_type c )
- {
- if( ( c >= '0' ) && ( c <= '9' ) ) return c - '0';
- if( ( c >= 'a' ) && ( c <= 'f' ) ) return c - 'a' + 10;
- if( ( c >= 'A' ) && ( c <= 'F' ) ) return c - 'A' + 10;
- return 0;
- }
-
- template< class Char_type, class Iter_type >
- Char_type hex_str_to_char( Iter_type& begin )
- {
- const Char_type c1( *( ++begin ) );
- const Char_type c2( *( ++begin ) );
-
- return ( hex_to_num( c1 ) << 4 ) + hex_to_num( c2 );
- }
-
- template< class Char_type, class Iter_type >
- Char_type unicode_str_to_char( Iter_type& begin )
- {
- const Char_type c1( *( ++begin ) );
- const Char_type c2( *( ++begin ) );
- const Char_type c3( *( ++begin ) );
- const Char_type c4( *( ++begin ) );
-
- return ( hex_to_num( c1 ) << 12 ) +
- ( hex_to_num( c2 ) << 8 ) +
- ( hex_to_num( c3 ) << 4 ) +
- hex_to_num( c4 );
- }
-
- template< class String_type >
- void append_esc_char_and_incr_iter( String_type& s,
- typename String_type::const_iterator& begin,
- typename String_type::const_iterator end )
- {
- typedef typename String_type::value_type Char_type;
-
- const Char_type c2( *begin );
-
- switch( c2 )
- {
- case 't': s += '\t'; break;
- case 'b': s += '\b'; break;
- case 'f': s += '\f'; break;
- case 'n': s += '\n'; break;
- case 'r': s += '\r'; break;
- case '\\': s += '\\'; break;
- case '/': s += '/'; break;
- case '"': s += '"'; break;
- case 'x':
- {
- if( end - begin >= 3 ) // expecting "xHH..."
- {
- s += hex_str_to_char< Char_type >( begin );
- }
- break;
- }
- case 'u':
- {
- if( end - begin >= 5 ) // expecting "uHHHH..."
- {
- s += unicode_str_to_char< Char_type >( begin );
- }
- break;
- }
- }
- }
-
- template< class String_type >
- String_type substitute_esc_chars( typename String_type::const_iterator begin,
- typename String_type::const_iterator end )
- {
- typedef typename String_type::const_iterator Iter_type;
-
- if( end - begin < 2 ) return String_type( begin, end );
-
- String_type result;
-
- result.reserve( end - begin );
-
- const Iter_type end_minus_1( end - 1 );
-
- Iter_type substr_start = begin;
- Iter_type i = begin;
-
- for( ; i < end_minus_1; ++i )
- {
- if( *i == '\\' )
- {
- result.append( substr_start, i );
-
- ++i; // skip the '\'
-
- append_esc_char_and_incr_iter( result, i, end );
-
- substr_start = i + 1;
- }
- }
-
- result.append( substr_start, end );
-
- return result;
- }
-
- template< class String_type >
- String_type get_str_( typename String_type::const_iterator begin,
- typename String_type::const_iterator end )
- {
- assert( end - begin >= 2 );
-
- typedef typename String_type::const_iterator Iter_type;
-
- Iter_type str_without_quotes( ++begin );
- Iter_type end_without_quotes( --end );
-
- return substitute_esc_chars< String_type >( str_without_quotes, end_without_quotes );
- }
-
- inline std::string get_str( std::string::const_iterator begin, std::string::const_iterator end )
- {
- return get_str_< std::string >( begin, end );
- }
-
- inline std::wstring get_str( std::wstring::const_iterator begin, std::wstring::const_iterator end )
- {
- return get_str_< std::wstring >( begin, end );
- }
-
- template< class String_type, class Iter_type >
- String_type get_str( Iter_type begin, Iter_type end )
- {
- const String_type tmp( begin, end ); // convert multipass iterators to string iterators
-
- return get_str( tmp.begin(), tmp.end() );
- }
-
- // this class's methods get called by the spirit parse resulting
- // in the creation of a JSON object or array
- //
- // NB Iter_type could be a std::string iterator, wstring iterator, a position iterator or a multipass iterator
- //
- template< class Value_type, class Iter_type >
- class Semantic_actions
- {
- public:
-
- typedef typename Value_type::Config_type Config_type;
- typedef typename Config_type::String_type String_type;
- typedef typename Config_type::Object_type Object_type;
- typedef typename Config_type::Array_type Array_type;
- typedef typename String_type::value_type Char_type;
-
- Semantic_actions( Value_type& value )
- : value_( value )
- , current_p_( 0 )
- {
- }
-
- void begin_obj( Char_type c )
- {
- assert( c == '{' );
-
- begin_compound< Object_type >();
- }
-
- void end_obj( Char_type c )
- {
- assert( c == '}' );
-
- end_compound();
- }
-
- void begin_array( Char_type c )
- {
- assert( c == '[' );
-
- begin_compound< Array_type >();
- }
-
- void end_array( Char_type c )
- {
- assert( c == ']' );
-
- end_compound();
- }
-
- void new_name( Iter_type begin, Iter_type end )
- {
- assert( current_p_->type() == obj_type );
-
- name_ = get_str< String_type >( begin, end );
- }
-
- void new_str( Iter_type begin, Iter_type end )
- {
- add_to_current( get_str< String_type >( begin, end ) );
- }
-
- void new_true( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "true" ) );
-
- add_to_current( true );
- }
-
- void new_false( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "false" ) );
-
- add_to_current( false );
- }
-
- void new_null( Iter_type begin, Iter_type end )
- {
- assert( is_eq( begin, end, "null" ) );
-
- add_to_current( Value_type() );
- }
-
- void new_int( int64_t i )
- {
- add_to_current( i );
- }
-
- void new_uint64( uint64_t ui )
- {
- add_to_current( ui );
- }
-
- void new_real( double d )
- {
- add_to_current( d );
- }
-
- private:
-
- Semantic_actions& operator=( const Semantic_actions& );
- // to prevent "assignment operator could not be generated" warning
-
- Value_type* add_first( const Value_type& value )
- {
- assert( current_p_ == 0 );
-
- value_ = value;
- current_p_ = &value_;
- return current_p_;
- }
-
- template< class Array_or_obj >
- void begin_compound()
- {
- if( current_p_ == 0 )
- {
- add_first( Array_or_obj() );
- }
- else
- {
- stack_.push_back( current_p_ );
-
- Array_or_obj new_array_or_obj; // avoid copy by building new array or object in place
-
- current_p_ = add_to_current( new_array_or_obj );
- }
- }
-
- void end_compound()
- {
- if( current_p_ != &value_ )
- {
- current_p_ = stack_.back();
-
- stack_.pop_back();
- }
- }
-
- Value_type* add_to_current( const Value_type& value )
- {
- if( current_p_ == 0 )
- {
- return add_first( value );
- }
- else if( current_p_->type() == array_type )
- {
- current_p_->get_array().push_back( value );
-
- return &current_p_->get_array().back();
- }
-
- assert( current_p_->type() == obj_type );
-
- return &Config_type::add( current_p_->get_obj(), name_, value );
- }
-
- Value_type& value_; // this is the object or array that is being created
- Value_type* current_p_; // the child object or array that is currently being constructed
-
- std::vector< Value_type* > stack_; // previous child objects and arrays
-
- String_type name_; // of current name/value pair
- };
-
- template< typename Iter_type >
- void throw_error( spirit_namespace::position_iterator< Iter_type > i, const std::string& reason )
- {
- throw Error_position( i.get_position().line, i.get_position().column, reason );
- }
-
- template< typename Iter_type >
- void throw_error( Iter_type i, const std::string& reason )
- {
- throw reason;
- }
-
- // the spirit grammer
- //
- template< class Value_type, class Iter_type >
- class Json_grammer : public spirit_namespace::grammar< Json_grammer< Value_type, Iter_type > >
- {
- public:
-
- typedef Semantic_actions< Value_type, Iter_type > Semantic_actions_t;
-
- Json_grammer( Semantic_actions_t& semantic_actions )
- : actions_( semantic_actions )
- {
- }
-
- static void throw_not_value( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a value" );
- }
-
- static void throw_not_array( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not an array" );
- }
-
- static void throw_not_object( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not an object" );
- }
-
- static void throw_not_pair( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a pair" );
- }
-
- static void throw_not_colon( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "no colon in pair" );
- }
-
- static void throw_not_string( Iter_type begin, Iter_type end )
- {
- throw_error( begin, "not a string" );
- }
-
- template< typename ScannerT >
- class definition
- {
- public:
-
- definition( const Json_grammer& self )
- {
- using namespace spirit_namespace;
-
- typedef typename Value_type::String_type::value_type Char_type;
-
- // first we convert the semantic action class methods to functors with the
- // parameter signature expected by spirit
-
- typedef boost::function< void( Char_type ) > Char_action;
- typedef boost::function< void( Iter_type, Iter_type ) > Str_action;
- typedef boost::function< void( double ) > Real_action;
- typedef boost::function< void( int64_t ) > Int_action;
- typedef boost::function< void( uint64_t ) > Uint64_action;
-
- Char_action begin_obj ( boost::bind( &Semantic_actions_t::begin_obj, &self.actions_, _1 ) );
- Char_action end_obj ( boost::bind( &Semantic_actions_t::end_obj, &self.actions_, _1 ) );
- Char_action begin_array( boost::bind( &Semantic_actions_t::begin_array, &self.actions_, _1 ) );
- Char_action end_array ( boost::bind( &Semantic_actions_t::end_array, &self.actions_, _1 ) );
- Str_action new_name ( boost::bind( &Semantic_actions_t::new_name, &self.actions_, _1, _2 ) );
- Str_action new_str ( boost::bind( &Semantic_actions_t::new_str, &self.actions_, _1, _2 ) );
- Str_action new_true ( boost::bind( &Semantic_actions_t::new_true, &self.actions_, _1, _2 ) );
- Str_action new_false ( boost::bind( &Semantic_actions_t::new_false, &self.actions_, _1, _2 ) );
- Str_action new_null ( boost::bind( &Semantic_actions_t::new_null, &self.actions_, _1, _2 ) );
- Real_action new_real ( boost::bind( &Semantic_actions_t::new_real, &self.actions_, _1 ) );
- Int_action new_int ( boost::bind( &Semantic_actions_t::new_int, &self.actions_, _1 ) );
- Uint64_action new_uint64 ( boost::bind( &Semantic_actions_t::new_uint64, &self.actions_, _1 ) );
-
- // actual grammer
-
- json_
- = value_ | eps_p[ &throw_not_value ]
- ;
-
- value_
- = string_[ new_str ]
- | number_
- | object_
- | array_
- | str_p( "true" ) [ new_true ]
- | str_p( "false" )[ new_false ]
- | str_p( "null" ) [ new_null ]
- ;
-
- object_
- = ch_p('{')[ begin_obj ]
- >> !members_
- >> ( ch_p('}')[ end_obj ] | eps_p[ &throw_not_object ] )
- ;
-
- members_
- = pair_ >> *( ',' >> pair_ )
- ;
-
- pair_
- = string_[ new_name ]
- >> ( ':' | eps_p[ &throw_not_colon ] )
- >> ( value_ | eps_p[ &throw_not_value ] )
- ;
-
- array_
- = ch_p('[')[ begin_array ]
- >> !elements_
- >> ( ch_p(']')[ end_array ] | eps_p[ &throw_not_array ] )
- ;
-
- elements_
- = value_ >> *( ',' >> value_ )
- ;
-
- string_
- = lexeme_d // this causes white space inside a string to be retained
- [
- confix_p
- (
- '"',
- *lex_escape_ch_p,
- '"'
- )
- ]
- ;
-
- number_
- = strict_real_p[ new_real ]
- | int64_p [ new_int ]
- | uint64_p [ new_uint64 ]
- ;
- }
-
- spirit_namespace::rule< ScannerT > json_, object_, members_, pair_, array_, elements_, value_, string_, number_;
-
- const spirit_namespace::rule< ScannerT >& start() const { return json_; }
- };
-
- private:
-
- Json_grammer& operator=( const Json_grammer& ); // to prevent "assignment operator could not be generated" warning
-
- Semantic_actions_t& actions_;
- };
-
- template< class Iter_type, class Value_type >
- Iter_type read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
- {
- Semantic_actions< Value_type, Iter_type > semantic_actions( value );
-
- const spirit_namespace::parse_info< Iter_type > info =
- spirit_namespace::parse( begin, end,
- Json_grammer< Value_type, Iter_type >( semantic_actions ),
- spirit_namespace::space_p );
-
- if( !info.hit )
- {
- assert( false ); // in theory exception should already have been thrown
- throw_error( info.stop, "error" );
- }
-
- return info.stop;
- }
-
- template< class Iter_type, class Value_type >
- void add_posn_iter_and_read_range_or_throw( Iter_type begin, Iter_type end, Value_type& value )
- {
- typedef spirit_namespace::position_iterator< Iter_type > Posn_iter_t;
-
- const Posn_iter_t posn_begin( begin, end );
- const Posn_iter_t posn_end( end, end );
-
- read_range_or_throw( posn_begin, posn_end, value );
- }
-
- template< class Iter_type, class Value_type >
- bool read_range( Iter_type& begin, Iter_type end, Value_type& value )
- {
- try
- {
- begin = read_range_or_throw( begin, end, value );
-
- return true;
- }
- catch( ... )
- {
- return false;
- }
- }
-
- template< class String_type, class Value_type >
- void read_string_or_throw( const String_type& s, Value_type& value )
- {
- add_posn_iter_and_read_range_or_throw( s.begin(), s.end(), value );
- }
-
- template< class String_type, class Value_type >
- bool read_string( const String_type& s, Value_type& value )
- {
- typename String_type::const_iterator begin = s.begin();
-
- return read_range( begin, s.end(), value );
- }
-
- template< class Istream_type >
- struct Multi_pass_iters
- {
- typedef typename Istream_type::char_type Char_type;
- typedef std::istream_iterator< Char_type, Char_type > istream_iter;
- typedef spirit_namespace::multi_pass< istream_iter > Mp_iter;
-
- Multi_pass_iters( Istream_type& is )
- {
- is.unsetf( std::ios::skipws );
-
- begin_ = spirit_namespace::make_multi_pass( istream_iter( is ) );
- end_ = spirit_namespace::make_multi_pass( istream_iter() );
- }
-
- Mp_iter begin_;
- Mp_iter end_;
- };
-
- template< class Istream_type, class Value_type >
- bool read_stream( Istream_type& is, Value_type& value )
- {
- Multi_pass_iters< Istream_type > mp_iters( is );
-
- return read_range( mp_iters.begin_, mp_iters.end_, value );
- }
-
- template< class Istream_type, class Value_type >
- void read_stream_or_throw( Istream_type& is, Value_type& value )
- {
- const Multi_pass_iters< Istream_type > mp_iters( is );
-
- add_posn_iter_and_read_range_or_throw( mp_iters.begin_, mp_iters.end_, value );
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_stream_reader.h b/src/json/json_spirit_stream_reader.h
deleted file mode 100644
index 7e59c9adc2..0000000000
--- a/src/json/json_spirit_stream_reader.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef JSON_SPIRIT_READ_STREAM
-#define JSON_SPIRIT_READ_STREAM
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_reader_template.h"
-
-namespace json_spirit
-{
- // these classes allows you to read multiple top level contiguous values from a stream,
- // the normal stream read functions have a bug that prevent multiple top level values
- // from being read unless they are separated by spaces
-
- template< class Istream_type, class Value_type >
- class Stream_reader
- {
- public:
-
- Stream_reader( Istream_type& is )
- : iters_( is )
- {
- }
-
- bool read_next( Value_type& value )
- {
- return read_range( iters_.begin_, iters_.end_, value );
- }
-
- private:
-
- typedef Multi_pass_iters< Istream_type > Mp_iters;
-
- Mp_iters iters_;
- };
-
- template< class Istream_type, class Value_type >
- class Stream_reader_thrower
- {
- public:
-
- Stream_reader_thrower( Istream_type& is )
- : iters_( is )
- , posn_begin_( iters_.begin_, iters_.end_ )
- , posn_end_( iters_.end_, iters_.end_ )
- {
- }
-
- void read_next( Value_type& value )
- {
- posn_begin_ = read_range_or_throw( posn_begin_, posn_end_, value );
- }
-
- private:
-
- typedef Multi_pass_iters< Istream_type > Mp_iters;
- typedef spirit_namespace::position_iterator< typename Mp_iters::Mp_iter > Posn_iter_t;
-
- Mp_iters iters_;
- Posn_iter_t posn_begin_, posn_end_;
- };
-}
-
-#endif
diff --git a/src/json/json_spirit_utils.h b/src/json/json_spirit_utils.h
deleted file mode 100644
index 553e3b96a4..0000000000
--- a/src/json/json_spirit_utils.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef JSON_SPIRIT_UTILS
-#define JSON_SPIRIT_UTILS
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include <map>
-
-namespace json_spirit
-{
- template< class Obj_t, class Map_t >
- void obj_to_map( const Obj_t& obj, Map_t& mp_obj )
- {
- mp_obj.clear();
-
- for( typename Obj_t::const_iterator i = obj.begin(); i != obj.end(); ++i )
- {
- mp_obj[ i->name_ ] = i->value_;
- }
- }
-
- template< class Obj_t, class Map_t >
- void map_to_obj( const Map_t& mp_obj, Obj_t& obj )
- {
- obj.clear();
-
- for( typename Map_t::const_iterator i = mp_obj.begin(); i != mp_obj.end(); ++i )
- {
- obj.push_back( typename Obj_t::value_type( i->first, i->second ) );
- }
- }
-
- typedef std::map< std::string, Value > Mapped_obj;
-
-#ifndef BOOST_NO_STD_WSTRING
- typedef std::map< std::wstring, wValue > wMapped_obj;
-#endif
-
- template< class Object_type, class String_type >
- const typename Object_type::value_type::Value_type& find_value( const Object_type& obj, const String_type& name )
- {
- for( typename Object_type::const_iterator i = obj.begin(); i != obj.end(); ++i )
- {
- if( i->name_ == name )
- {
- return i->value_;
- }
- }
-
- return Object_type::value_type::Value_type::null;
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_value.cpp b/src/json/json_spirit_value.cpp
deleted file mode 100644
index 44d2f06a01..0000000000
--- a/src/json/json_spirit_value.cpp
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Copyright (c) 2007 John W Wilkinson
-
- This source code can be used for any purpose as long as
- this comment is retained. */
-
-// json spirit version 2.00
-
-#include "json_spirit_value.h"
diff --git a/src/json/json_spirit_value.h b/src/json/json_spirit_value.h
deleted file mode 100644
index 13cc89210c..0000000000
--- a/src/json/json_spirit_value.h
+++ /dev/null
@@ -1,534 +0,0 @@
-#ifndef JSON_SPIRIT_VALUE
-#define JSON_SPIRIT_VALUE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include <vector>
-#include <map>
-#include <string>
-#include <cassert>
-#include <sstream>
-#include <stdexcept>
-#include <stdint.h>
-#include <boost/config.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/variant.hpp>
-
-namespace json_spirit
-{
- enum Value_type{ obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
- static const char* Value_type_name[]={"obj", "array", "str", "bool", "int", "real", "null"};
-
- template< class Config > // Config determines whether the value uses std::string or std::wstring and
- // whether JSON Objects are represented as vectors or maps
- class Value_impl
- {
- public:
-
- typedef Config Config_type;
- typedef typename Config::String_type String_type;
- typedef typename Config::Object_type Object;
- typedef typename Config::Array_type Array;
- typedef typename String_type::const_pointer Const_str_ptr; // eg const char*
-
- Value_impl(); // creates null value
- Value_impl( Const_str_ptr value );
- Value_impl( const String_type& value );
- Value_impl( const Object& value );
- Value_impl( const Array& value );
- Value_impl( bool value );
- Value_impl( int value );
- Value_impl( int64_t value );
- Value_impl( uint64_t value );
- Value_impl( double value );
-
- Value_impl( const Value_impl& other );
-
- bool operator==( const Value_impl& lhs ) const;
-
- Value_impl& operator=( const Value_impl& lhs );
-
- Value_type type() const;
-
- bool is_uint64() const;
- bool is_null() const;
-
- const String_type& get_str() const;
- const Object& get_obj() const;
- const Array& get_array() const;
- bool get_bool() const;
- int get_int() const;
- int64_t get_int64() const;
- uint64_t get_uint64() const;
- double get_real() const;
-
- Object& get_obj();
- Array& get_array();
-
- template< typename T > T get_value() const; // example usage: int i = value.get_value< int >();
- // or double d = value.get_value< double >();
-
- static const Value_impl null;
-
- private:
-
- void check_type( const Value_type vtype ) const;
-
- typedef boost::variant< String_type,
- boost::recursive_wrapper< Object >, boost::recursive_wrapper< Array >,
- bool, int64_t, double > Variant;
-
- Value_type type_;
- Variant v_;
- bool is_uint64_;
- };
-
- // vector objects
-
- template< class Config >
- struct Pair_impl
- {
- typedef typename Config::String_type String_type;
- typedef typename Config::Value_type Value_type;
-
- Pair_impl( const String_type& name, const Value_type& value );
-
- bool operator==( const Pair_impl& lhs ) const;
-
- String_type name_;
- Value_type value_;
- };
-
- template< class String >
- struct Config_vector
- {
- typedef String String_type;
- typedef Value_impl< Config_vector > Value_type;
- typedef Pair_impl < Config_vector > Pair_type;
- typedef std::vector< Value_type > Array_type;
- typedef std::vector< Pair_type > Object_type;
-
- static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
- {
- obj.push_back( Pair_type( name , value ) );
-
- return obj.back().value_;
- }
-
- static String_type get_name( const Pair_type& pair )
- {
- return pair.name_;
- }
-
- static Value_type get_value( const Pair_type& pair )
- {
- return pair.value_;
- }
- };
-
- // typedefs for ASCII
-
- typedef Config_vector< std::string > Config;
-
- typedef Config::Value_type Value;
- typedef Config::Pair_type Pair;
- typedef Config::Object_type Object;
- typedef Config::Array_type Array;
-
- // typedefs for Unicode
-
-#ifndef BOOST_NO_STD_WSTRING
-
- typedef Config_vector< std::wstring > wConfig;
-
- typedef wConfig::Value_type wValue;
- typedef wConfig::Pair_type wPair;
- typedef wConfig::Object_type wObject;
- typedef wConfig::Array_type wArray;
-#endif
-
- // map objects
-
- template< class String >
- struct Config_map
- {
- typedef String String_type;
- typedef Value_impl< Config_map > Value_type;
- typedef std::vector< Value_type > Array_type;
- typedef std::map< String_type, Value_type > Object_type;
- typedef typename Object_type::value_type Pair_type;
-
- static Value_type& add( Object_type& obj, const String_type& name, const Value_type& value )
- {
- return obj[ name ] = value;
- }
-
- static String_type get_name( const Pair_type& pair )
- {
- return pair.first;
- }
-
- static Value_type get_value( const Pair_type& pair )
- {
- return pair.second;
- }
- };
-
- // typedefs for ASCII
-
- typedef Config_map< std::string > mConfig;
-
- typedef mConfig::Value_type mValue;
- typedef mConfig::Object_type mObject;
- typedef mConfig::Array_type mArray;
-
- // typedefs for Unicode
-
-#ifndef BOOST_NO_STD_WSTRING
-
- typedef Config_map< std::wstring > wmConfig;
-
- typedef wmConfig::Value_type wmValue;
- typedef wmConfig::Object_type wmObject;
- typedef wmConfig::Array_type wmArray;
-
-#endif
-
- ///////////////////////////////////////////////////////////////////////////////////////////////
- //
- // implementation
-
- template< class Config >
- const Value_impl< Config > Value_impl< Config >::null;
-
- template< class Config >
- Value_impl< Config >::Value_impl()
- : type_( null_type )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Const_str_ptr value )
- : type_( str_type )
- , v_( String_type( value ) )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const String_type& value )
- : type_( str_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Object& value )
- : type_( obj_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Array& value )
- : type_( array_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( bool value )
- : type_( bool_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( int value )
- : type_( int_type )
- , v_( static_cast< int64_t >( value ) )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( int64_t value )
- : type_( int_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( uint64_t value )
- : type_( int_type )
- , v_( static_cast< int64_t >( value ) )
- , is_uint64_( true )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( double value )
- : type_( real_type )
- , v_( value )
- , is_uint64_( false )
- {
- }
-
- template< class Config >
- Value_impl< Config >::Value_impl( const Value_impl< Config >& other )
- : type_( other.type() )
- , v_( other.v_ )
- , is_uint64_( other.is_uint64_ )
- {
- }
-
- template< class Config >
- Value_impl< Config >& Value_impl< Config >::operator=( const Value_impl& lhs )
- {
- Value_impl tmp( lhs );
-
- std::swap( type_, tmp.type_ );
- std::swap( v_, tmp.v_ );
- std::swap( is_uint64_, tmp.is_uint64_ );
-
- return *this;
- }
-
- template< class Config >
- bool Value_impl< Config >::operator==( const Value_impl& lhs ) const
- {
- if( this == &lhs ) return true;
-
- if( type() != lhs.type() ) return false;
-
- return v_ == lhs.v_;
- }
-
- template< class Config >
- Value_type Value_impl< Config >::type() const
- {
- return type_;
- }
-
- template< class Config >
- bool Value_impl< Config >::is_uint64() const
- {
- return is_uint64_;
- }
-
- template< class Config >
- bool Value_impl< Config >::is_null() const
- {
- return type() == null_type;
- }
-
- template< class Config >
- void Value_impl< Config >::check_type( const Value_type vtype ) const
- {
- if( type() != vtype )
- {
- std::ostringstream os;
-
- ///// Bitcoin: Tell the types by name instead of by number
- os << "value is type " << Value_type_name[type()] << ", expected " << Value_type_name[vtype];
-
- throw std::runtime_error( os.str() );
- }
- }
-
- template< class Config >
- const typename Config::String_type& Value_impl< Config >::get_str() const
- {
- check_type( str_type );
-
- return *boost::get< String_type >( &v_ );
- }
-
- template< class Config >
- const typename Value_impl< Config >::Object& Value_impl< Config >::get_obj() const
- {
- check_type( obj_type );
-
- return *boost::get< Object >( &v_ );
- }
-
- template< class Config >
- const typename Value_impl< Config >::Array& Value_impl< Config >::get_array() const
- {
- check_type( array_type );
-
- return *boost::get< Array >( &v_ );
- }
-
- template< class Config >
- bool Value_impl< Config >::get_bool() const
- {
- check_type( bool_type );
-
- return boost::get< bool >( v_ );
- }
-
- template< class Config >
- int Value_impl< Config >::get_int() const
- {
- check_type( int_type );
-
- return static_cast< int >( get_int64() );
- }
-
- template< class Config >
- int64_t Value_impl< Config >::get_int64() const
- {
- check_type( int_type );
-
- return boost::get< int64_t >( v_ );
- }
-
- template< class Config >
- uint64_t Value_impl< Config >::get_uint64() const
- {
- check_type( int_type );
-
- return static_cast< uint64_t >( get_int64() );
- }
-
- template< class Config >
- double Value_impl< Config >::get_real() const
- {
- if( type() == int_type )
- {
- return is_uint64() ? static_cast< double >( get_uint64() )
- : static_cast< double >( get_int64() );
- }
-
- check_type( real_type );
-
- return boost::get< double >( v_ );
- }
-
- template< class Config >
- typename Value_impl< Config >::Object& Value_impl< Config >::get_obj()
- {
- check_type( obj_type );
-
- return *boost::get< Object >( &v_ );
- }
-
- template< class Config >
- typename Value_impl< Config >::Array& Value_impl< Config >::get_array()
- {
- check_type( array_type );
-
- return *boost::get< Array >( &v_ );
- }
-
- template< class Config >
- Pair_impl< Config >::Pair_impl( const String_type& name, const Value_type& value )
- : name_( name )
- , value_( value )
- {
- }
-
- template< class Config >
- bool Pair_impl< Config >::operator==( const Pair_impl< Config >& lhs ) const
- {
- if( this == &lhs ) return true;
-
- return ( name_ == lhs.name_ ) && ( value_ == lhs.value_ );
- }
-
- // converts a C string, ie. 8 bit char array, to a string object
- //
- template < class String_type >
- String_type to_str( const char* c_str )
- {
- String_type result;
-
- for( const char* p = c_str; *p != 0; ++p )
- {
- result += *p;
- }
-
- return result;
- }
-
- //
-
- namespace internal_
- {
- template< typename T >
- struct Type_to_type
- {
- };
-
- template< class Value >
- int get_value( const Value& value, Type_to_type< int > )
- {
- return value.get_int();
- }
-
- template< class Value >
- int64_t get_value( const Value& value, Type_to_type< int64_t > )
- {
- return value.get_int64();
- }
-
- template< class Value >
- uint64_t get_value( const Value& value, Type_to_type< uint64_t > )
- {
- return value.get_uint64();
- }
-
- template< class Value >
- double get_value( const Value& value, Type_to_type< double > )
- {
- return value.get_real();
- }
-
- template< class Value >
- typename Value::String_type get_value( const Value& value, Type_to_type< typename Value::String_type > )
- {
- return value.get_str();
- }
-
- template< class Value >
- typename Value::Array get_value( const Value& value, Type_to_type< typename Value::Array > )
- {
- return value.get_array();
- }
-
- template< class Value >
- typename Value::Object get_value( const Value& value, Type_to_type< typename Value::Object > )
- {
- return value.get_obj();
- }
-
- template< class Value >
- bool get_value( const Value& value, Type_to_type< bool > )
- {
- return value.get_bool();
- }
- }
-
- template< class Config >
- template< typename T >
- T Value_impl< Config >::get_value() const
- {
- return internal_::get_value( *this, internal_::Type_to_type< T >() );
- }
-}
-
-#endif
diff --git a/src/json/json_spirit_writer.cpp b/src/json/json_spirit_writer.cpp
deleted file mode 100644
index d24a632cf3..0000000000
--- a/src/json/json_spirit_writer.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_writer.h"
-#include "json_spirit_writer_template.h"
-
-void json_spirit::write( const Value& value, std::ostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const Value& value, std::ostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::string json_spirit::write( const Value& value )
-{
- return write_string( value, false );
-}
-
-std::string json_spirit::write_formatted( const Value& value )
-{
- return write_string( value, true );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-void json_spirit::write( const wValue& value, std::wostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const wValue& value, std::wostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::wstring json_spirit::write( const wValue& value )
-{
- return write_string( value, false );
-}
-
-std::wstring json_spirit::write_formatted( const wValue& value )
-{
- return write_string( value, true );
-}
-
-#endif
-
-void json_spirit::write( const mValue& value, std::ostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const mValue& value, std::ostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::string json_spirit::write( const mValue& value )
-{
- return write_string( value, false );
-}
-
-std::string json_spirit::write_formatted( const mValue& value )
-{
- return write_string( value, true );
-}
-
-#ifndef BOOST_NO_STD_WSTRING
-
-void json_spirit::write( const wmValue& value, std::wostream& os )
-{
- write_stream( value, os, false );
-}
-
-void json_spirit::write_formatted( const wmValue& value, std::wostream& os )
-{
- write_stream( value, os, true );
-}
-
-std::wstring json_spirit::write( const wmValue& value )
-{
- return write_string( value, false );
-}
-
-std::wstring json_spirit::write_formatted( const wmValue& value )
-{
- return write_string( value, true );
-}
-
-#endif
diff --git a/src/json/json_spirit_writer.h b/src/json/json_spirit_writer.h
deleted file mode 100644
index 52e14068e7..0000000000
--- a/src/json/json_spirit_writer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef JSON_SPIRIT_WRITER
-#define JSON_SPIRIT_WRITER
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-# pragma once
-#endif
-
-#include "json_spirit_value.h"
-#include <iostream>
-
-namespace json_spirit
-{
- // functions to convert JSON Values to text,
- // the "formatted" versions add whitespace to format the output nicely
-
- void write ( const Value& value, std::ostream& os );
- void write_formatted( const Value& value, std::ostream& os );
- std::string write ( const Value& value );
- std::string write_formatted( const Value& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- void write ( const wValue& value, std::wostream& os );
- void write_formatted( const wValue& value, std::wostream& os );
- std::wstring write ( const wValue& value );
- std::wstring write_formatted( const wValue& value );
-
-#endif
-
- void write ( const mValue& value, std::ostream& os );
- void write_formatted( const mValue& value, std::ostream& os );
- std::string write ( const mValue& value );
- std::string write_formatted( const mValue& value );
-
-#ifndef BOOST_NO_STD_WSTRING
-
- void write ( const wmValue& value, std::wostream& os );
- void write_formatted( const wmValue& value, std::wostream& os );
- std::wstring write ( const wmValue& value );
- std::wstring write_formatted( const wmValue& value );
-
-#endif
-}
-
-#endif
diff --git a/src/json/json_spirit_writer_template.h b/src/json/json_spirit_writer_template.h
deleted file mode 100644
index 6b4978a1ff..0000000000
--- a/src/json/json_spirit_writer_template.h
+++ /dev/null
@@ -1,249 +0,0 @@
-#ifndef JSON_SPIRIT_WRITER_TEMPLATE
-#define JSON_SPIRIT_WRITER_TEMPLATE
-
-// Copyright John W. Wilkinson 2007 - 2009.
-// Distributed under the MIT License, see accompanying file LICENSE.txt
-
-// json spirit version 4.03
-
-#include "json_spirit_value.h"
-
-#include <cassert>
-#include <sstream>
-#include <iomanip>
-
-namespace json_spirit
-{
- inline char to_hex_char( unsigned int c )
- {
- assert( c <= 0xF );
-
- const char ch = static_cast< char >( c );
-
- if( ch < 10 ) return '0' + ch;
-
- return 'A' - 10 + ch;
- }
-
- template< class String_type >
- String_type non_printable_to_string( unsigned int c )
- {
- // Silence the warning: typedef ‘Char_type’ locally defined but not used [-Wunused-local-typedefs]
- // typedef typename String_type::value_type Char_type;
-
- String_type result( 6, '\\' );
-
- result[1] = 'u';
-
- result[ 5 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 4 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 3 ] = to_hex_char( c & 0x000F ); c >>= 4;
- result[ 2 ] = to_hex_char( c & 0x000F );
-
- return result;
- }
-
- template< typename Char_type, class String_type >
- bool add_esc_char( Char_type c, String_type& s )
- {
- switch( c )
- {
- case '"': s += to_str< String_type >( "\\\"" ); return true;
- case '\\': s += to_str< String_type >( "\\\\" ); return true;
- case '\b': s += to_str< String_type >( "\\b" ); return true;
- case '\f': s += to_str< String_type >( "\\f" ); return true;
- case '\n': s += to_str< String_type >( "\\n" ); return true;
- case '\r': s += to_str< String_type >( "\\r" ); return true;
- case '\t': s += to_str< String_type >( "\\t" ); return true;
- }
-
- return false;
- }
-
- template< class String_type >
- String_type add_esc_chars( const String_type& s )
- {
- typedef typename String_type::const_iterator Iter_type;
- typedef typename String_type::value_type Char_type;
-
- String_type result;
-
- const Iter_type end( s.end() );
-
- for( Iter_type i = s.begin(); i != end; ++i )
- {
- const Char_type c( *i );
-
- if( add_esc_char( c, result ) ) continue;
-
- const wint_t unsigned_c( ( c >= 0 ) ? c : 256 + c );
-
- if( iswprint( unsigned_c ) )
- {
- result += c;
- }
- else
- {
- result += non_printable_to_string< String_type >( unsigned_c );
- }
- }
-
- return result;
- }
-
- // this class generates the JSON text,
- // it keeps track of the indentation level etc.
- //
- template< class Value_type, class Ostream_type >
- class Generator
- {
- typedef typename Value_type::Config_type Config_type;
- typedef typename Config_type::String_type String_type;
- typedef typename Config_type::Object_type Object_type;
- typedef typename Config_type::Array_type Array_type;
- typedef typename String_type::value_type Char_type;
- typedef typename Object_type::value_type Obj_member_type;
-
- public:
-
- Generator( const Value_type& value, Ostream_type& os, bool pretty )
- : os_( os )
- , indentation_level_( 0 )
- , pretty_( pretty )
- {
- output( value );
- }
-
- private:
-
- void output( const Value_type& value )
- {
- switch( value.type() )
- {
- case obj_type: output( value.get_obj() ); break;
- case array_type: output( value.get_array() ); break;
- case str_type: output( value.get_str() ); break;
- case bool_type: output( value.get_bool() ); break;
- case int_type: output_int( value ); break;
-
- /// Bitcoin: Added std::fixed and changed precision from 16 to 8
- case real_type: os_ << std::showpoint << std::fixed << std::setprecision(8)
- << value.get_real(); break;
-
- case null_type: os_ << "null"; break;
- default: assert( false );
- }
- }
-
- void output( const Object_type& obj )
- {
- output_array_or_obj( obj, '{', '}' );
- }
-
- void output( const Array_type& arr )
- {
- output_array_or_obj( arr, '[', ']' );
- }
-
- void output( const Obj_member_type& member )
- {
- output( Config_type::get_name( member ) ); space();
- os_ << ':'; space();
- output( Config_type::get_value( member ) );
- }
-
- void output_int( const Value_type& value )
- {
- if( value.is_uint64() )
- {
- os_ << value.get_uint64();
- }
- else
- {
- os_ << value.get_int64();
- }
- }
-
- void output( const String_type& s )
- {
- os_ << '"' << add_esc_chars( s ) << '"';
- }
-
- void output( bool b )
- {
- os_ << to_str< String_type >( b ? "true" : "false" );
- }
-
- template< class T >
- void output_array_or_obj( const T& t, Char_type start_char, Char_type end_char )
- {
- os_ << start_char; new_line();
-
- ++indentation_level_;
-
- for( typename T::const_iterator i = t.begin(); i != t.end(); ++i )
- {
- indent(); output( *i );
-
- typename T::const_iterator next = i;
-
- if( ++next != t.end())
- {
- os_ << ',';
- }
-
- new_line();
- }
-
- --indentation_level_;
-
- indent(); os_ << end_char;
- }
-
- void indent()
- {
- if( !pretty_ ) return;
-
- for( int i = 0; i < indentation_level_; ++i )
- {
- os_ << " ";
- }
- }
-
- void space()
- {
- if( pretty_ ) os_ << ' ';
- }
-
- void new_line()
- {
- if( pretty_ ) os_ << '\n';
- }
-
- Generator& operator=( const Generator& ); // to prevent "assignment operator could not be generated" warning
-
- Ostream_type& os_;
- int indentation_level_;
- bool pretty_;
- };
-
- template< class Value_type, class Ostream_type >
- void write_stream( const Value_type& value, Ostream_type& os, bool pretty )
- {
- Generator< Value_type, Ostream_type >( value, os, pretty );
- }
-
- template< class Value_type >
- typename Value_type::String_type write_string( const Value_type& value, bool pretty )
- {
- typedef typename Value_type::String_type::value_type Char_type;
-
- std::basic_ostringstream< Char_type > os;
-
- write_stream( value, os, pretty );
-
- return os.str();
- }
-}
-
-#endif
diff --git a/src/keystore.cpp b/src/keystore.cpp
index 3bae24b7b9..cf49ba83ad 100644
--- a/src/keystore.cpp
+++ b/src/keystore.cpp
@@ -6,23 +6,30 @@
#include "keystore.h"
#include "key.h"
+#include "pubkey.h"
#include "util.h"
#include <boost/foreach.hpp>
-bool CKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
+bool CKeyStore::AddKey(const CKey &key) {
+ return AddKeyPubKey(key, key.GetPubKey());
+}
+
+bool CBasicKeyStore::GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const
{
CKey key;
- if (!GetKey(address, key))
+ if (!GetKey(address, key)) {
+ WatchKeyMap::const_iterator it = mapWatchKeys.find(address);
+ if (it != mapWatchKeys.end()) {
+ vchPubKeyOut = it->second;
+ return true;
+ }
return false;
+ }
vchPubKeyOut = key.GetPubKey();
return true;
}
-bool CKeyStore::AddKey(const CKey &key) {
- return AddKeyPubKey(key, key.GetPubKey());
-}
-
bool CBasicKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey)
{
LOCK(cs_KeyStore);
@@ -58,10 +65,29 @@ bool CBasicKeyStore::GetCScript(const CScriptID &hash, CScript& redeemScriptOut)
return false;
}
+static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut)
+{
+ //TODO: Use Solver to extract this?
+ CScript::const_iterator pc = dest.begin();
+ opcodetype opcode;
+ std::vector<unsigned char> vch;
+ if (!dest.GetOp(pc, opcode, vch) || vch.size() < 33 || vch.size() > 65)
+ return false;
+ pubKeyOut = CPubKey(vch);
+ if (!pubKeyOut.IsFullyValid())
+ return false;
+ if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch))
+ return false;
+ return true;
+}
+
bool CBasicKeyStore::AddWatchOnly(const CScript &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.insert(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey))
+ mapWatchKeys[pubKey.GetID()] = pubKey;
return true;
}
@@ -69,6 +95,9 @@ bool CBasicKeyStore::RemoveWatchOnly(const CScript &dest)
{
LOCK(cs_KeyStore);
setWatchOnly.erase(dest);
+ CPubKey pubKey;
+ if (ExtractPubKey(dest, pubKey))
+ mapWatchKeys.erase(pubKey.GetID());
return true;
}
diff --git a/src/keystore.h b/src/keystore.h
index 4a4b6d20af..b917bf20b4 100644
--- a/src/keystore.h
+++ b/src/keystore.h
@@ -32,7 +32,7 @@ public:
virtual bool HaveKey(const CKeyID &address) const =0;
virtual bool GetKey(const CKeyID &address, CKey& keyOut) const =0;
virtual void GetKeys(std::set<CKeyID> &setAddress) const =0;
- virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
+ virtual bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const =0;
//! Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki
virtual bool AddCScript(const CScript& redeemScript) =0;
@@ -47,6 +47,7 @@ public:
};
typedef std::map<CKeyID, CKey> KeyMap;
+typedef std::map<CKeyID, CPubKey> WatchKeyMap;
typedef std::map<CScriptID, CScript > ScriptMap;
typedef std::set<CScript> WatchOnlySet;
@@ -55,11 +56,13 @@ class CBasicKeyStore : public CKeyStore
{
protected:
KeyMap mapKeys;
+ WatchKeyMap mapWatchKeys;
ScriptMap mapScripts;
WatchOnlySet setWatchOnly;
public:
bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey);
+ bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
bool HaveKey(const CKeyID &address) const
{
bool result;
diff --git a/src/leveldbwrapper.cpp b/src/leveldbwrapper.cpp
index c353dfa6d9..26cacf95ae 100644
--- a/src/leveldbwrapper.cpp
+++ b/src/leveldbwrapper.cpp
@@ -58,7 +58,8 @@ CLevelDBWrapper::CLevelDBWrapper(const boost::filesystem::path& path, size_t nCa
} else {
if (fWipe) {
LogPrintf("Wiping LevelDB in %s\n", path.string());
- leveldb::DestroyDB(path.string(), options);
+ leveldb::Status result = leveldb::DestroyDB(path.string(), options);
+ HandleError(result);
}
TryCreateDirectory(path);
LogPrintf("Opening LevelDB in %s\n", path.string());
diff --git a/src/limitedmap.h b/src/limitedmap.h
index e8ea549653..5456dfc7c4 100644
--- a/src/limitedmap.h
+++ b/src/limitedmap.h
@@ -27,7 +27,11 @@ protected:
size_type nMaxSize;
public:
- limitedmap(size_type nMaxSizeIn = 0) { nMaxSize = nMaxSizeIn; }
+ limitedmap(size_type nMaxSizeIn)
+ {
+ assert(nMaxSizeIn > 0);
+ nMaxSize = nMaxSizeIn;
+ }
const_iterator begin() const { return map.begin(); }
const_iterator end() const { return map.end(); }
size_type size() const { return map.size(); }
@@ -38,13 +42,12 @@ public:
{
std::pair<iterator, bool> ret = map.insert(x);
if (ret.second) {
- if (nMaxSize && map.size() == nMaxSize) {
+ if (map.size() > nMaxSize) {
map.erase(rmap.begin()->second);
rmap.erase(rmap.begin());
}
rmap.insert(make_pair(x.second, ret.first));
}
- return;
}
void erase(const key_type& k)
{
@@ -81,11 +84,11 @@ public:
size_type max_size() const { return nMaxSize; }
size_type max_size(size_type s)
{
- if (s)
- while (map.size() > s) {
- map.erase(rmap.begin()->second);
- rmap.erase(rmap.begin());
- }
+ assert(s > 0);
+ while (map.size() > s) {
+ map.erase(rmap.begin()->second);
+ rmap.erase(rmap.begin());
+ }
nMaxSize = s;
return nMaxSize;
}
diff --git a/src/main.cpp b/src/main.cpp
index 0791e3ed00..e27b8444b4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -11,16 +11,27 @@
#include "chainparams.h"
#include "checkpoints.h"
#include "checkqueue.h"
+#include "consensus/consensus.h"
+#include "consensus/validation.h"
+#include "hash.h"
#include "init.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/policy.h"
#include "pow.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
+#include "script/script.h"
+#include "script/sigcache.h"
+#include "script/standard.h"
+#include "tinyformat.h"
#include "txdb.h"
#include "txmempool.h"
#include "ui_interface.h"
#include "undo.h"
#include "util.h"
#include "utilmoneystr.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
#include <sstream>
@@ -28,6 +39,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
+#include <boost/math/distributions/poisson.hpp>
#include <boost/thread.hpp>
using namespace std;
@@ -55,10 +67,12 @@ bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = true;
+bool fRequireStandard = true;
bool fCheckBlockIndex = false;
bool fCheckpointsEnabled = true;
-unsigned int nCoinCacheSize = 5000;
+size_t nCoinCacheUsage = 5000 * 300;
uint64_t nPruneTarget = 0;
+bool fAlerts = DEFAULT_ALERTS;
/** Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
CFeeRate minRelayTxFee = CFeeRate(1000);
@@ -69,16 +83,15 @@ struct COrphanTx {
CTransaction tx;
NodeId fromPeer;
};
-map<uint256, COrphanTx> mapOrphanTransactions;
-map<uint256, set<uint256> > mapOrphanTransactionsByPrev;
-void EraseOrphansFor(NodeId peer);
+map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(cs_main);;
+map<uint256, set<uint256> > mapOrphanTransactionsByPrev GUARDED_BY(cs_main);;
+void EraseOrphansFor(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Returns true if there are nRequired or more blocks of minVersion or above
- * in the last Params().ToCheckBlockUpgradeMajority() blocks, starting at pstart
- * and going backwards.
+ * in the last Consensus::Params::nMajorityWindow blocks, starting at pstart and going backwards.
*/
-static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired);
+static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams);
static void CheckBlockIndex();
/** Constant stuff for coinbase transactions we create: */
@@ -149,13 +162,36 @@ namespace {
*/
map<uint256, NodeId> mapBlockSource;
+ /**
+ * Filter for transactions that were recently rejected by
+ * AcceptToMemoryPool. These are not rerequested until the chain tip
+ * changes, at which point the entire filter is reset. Protected by
+ * cs_main.
+ *
+ * Without this filter we'd be re-requesting txs from each of our peers,
+ * increasing bandwidth consumption considerably. For instance, with 100
+ * peers, half of which relay a tx we don't accept, that might be a 50x
+ * bandwidth increase. A flooding attacker attempting to roll-over the
+ * filter using minimum-sized, 60byte, transactions might manage to send
+ * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
+ * two minute window to send invs to us.
+ *
+ * Decreasing the false positive rate is fairly cheap, so we pick one in a
+ * million to make it highly unlikely for users to have issues with this
+ * filter.
+ *
+ * Memory used: 1.7MB
+ */
+ boost::scoped_ptr<CRollingBloomFilter> recentRejects;
+ uint256 hashRecentRejectsChainTip;
+
/** Blocks that are in flight, and that are in the queue to be downloaded. Protected by cs_main. */
struct QueuedBlock {
uint256 hash;
CBlockIndex *pindex; //! Optional.
int64_t nTime; //! Time of "getdata" request in microseconds.
- int nValidatedQueuedBefore; //! Number of blocks queued with validated headers (globally) at the time this one is requested.
bool fValidatedHeaders; //! Whether this block has validated headers at the time of request.
+ int64_t nTimeDisconnect; //! The timeout for this block request (for disconnecting a slow peer)
};
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
@@ -216,6 +252,7 @@ struct CNodeState {
int64_t nStallingSince;
list<QueuedBlock> vBlocksInFlight;
int nBlocksInFlight;
+ int nBlocksInFlightValidHeaders;
//! Whether we consider this a preferred download peer.
bool fPreferredDownload;
@@ -229,6 +266,7 @@ struct CNodeState {
fSyncStarted = false;
nStallingSince = 0;
nBlocksInFlight = 0;
+ nBlocksInFlightValidHeaders = 0;
fPreferredDownload = false;
}
};
@@ -260,6 +298,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload += state->fPreferredDownload;
}
+// Returns time at which to timeout block request (nTime in microseconds)
+int64_t GetBlockTimeout(int64_t nTime, int nValidatedQueuedBefore, const Consensus::Params &consensusParams)
+{
+ return nTime + 500000 * consensusParams.nPowTargetSpacing * (4 + nValidatedQueuedBefore);
+}
+
void InitializeNode(NodeId nodeid, const CNode *pnode) {
LOCK(cs_main);
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
@@ -287,30 +331,36 @@ void FinalizeNode(NodeId nodeid) {
}
// Requires cs_main.
-void MarkBlockAsReceived(const uint256& hash) {
+// Returns a bool indicating whether we requested this block.
+bool MarkBlockAsReceived(const uint256& hash) {
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
if (itInFlight != mapBlocksInFlight.end()) {
CNodeState *state = State(itInFlight->second.first);
nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
+ state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
state->vBlocksInFlight.erase(itInFlight->second.second);
state->nBlocksInFlight--;
state->nStallingSince = 0;
mapBlocksInFlight.erase(itInFlight);
+ return true;
}
+ return false;
}
// Requires cs_main.
-void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex = NULL) {
+void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Params& consensusParams, CBlockIndex *pindex = NULL) {
CNodeState *state = State(nodeid);
assert(state != NULL);
// Make sure it's not listed somewhere already.
MarkBlockAsReceived(hash);
- QueuedBlock newentry = {hash, pindex, GetTimeMicros(), nQueuedValidatedHeaders, pindex != NULL};
+ int64_t nNow = GetTimeMicros();
+ QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL, GetBlockTimeout(nNow, nQueuedValidatedHeaders, consensusParams)};
nQueuedValidatedHeaders += newentry.fValidatedHeaders;
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
state->nBlocksInFlight++;
+ state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
}
@@ -418,13 +468,14 @@ void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vector<CBl
// Iterate over those blocks in vToFetch (in forward direction), adding the ones that
// are not yet downloaded and not in flight to vBlocks. In the mean time, update
- // pindexLastCommonBlock as long as all ancestors are already downloaded.
+ // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
+ // already part of our chain (and therefore don't need it even if pruned).
BOOST_FOREACH(CBlockIndex* pindex, vToFetch) {
if (!pindex->IsValid(BLOCK_VALID_TREE)) {
// We consider the chain that this peer is on invalid.
return;
}
- if (pindex->nStatus & BLOCK_HAVE_DATA) {
+ if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
if (pindex->nChainTx)
state->pindexLastCommonBlock = pindex;
} else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) {
@@ -507,7 +558,7 @@ CBlockTreeDB *pblocktree = NULL;
// mapOrphanTransactions
//
-bool AddOrphanTx(const CTransaction& tx, NodeId peer)
+bool AddOrphanTx(const CTransaction& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
uint256 hash = tx.GetHash();
if (mapOrphanTransactions.count(hash))
@@ -537,7 +588,7 @@ bool AddOrphanTx(const CTransaction& tx, NodeId peer)
return true;
}
-void static EraseOrphanTx(uint256 hash)
+void static EraseOrphanTx(uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.find(hash);
if (it == mapOrphanTransactions.end())
@@ -571,7 +622,7 @@ void EraseOrphansFor(NodeId peer)
}
-unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
+unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
unsigned int nEvicted = 0;
while (mapOrphanTransactions.size() > nMaxOrphans)
@@ -587,86 +638,10 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
return nEvicted;
}
-
-
-
-
-
-
-bool IsStandardTx(const CTransaction& tx, string& reason)
-{
- if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
- reason = "version";
- return false;
- }
-
- // Extremely large transactions with lots of inputs can cost the network
- // almost as much to process as they cost the sender in fees, because
- // computing signature hashes is O(ninputs*txsize). Limiting transactions
- // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
- unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
- if (sz >= MAX_STANDARD_TX_SIZE) {
- reason = "tx-size";
- return false;
- }
-
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
- // keys. (remember the 520 byte limit on redeemScript size) That works
- // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
- // bytes of scriptSig, which we round off to 1650 bytes for some minor
- // future-proofing. That's also enough to spend a 20-of-20
- // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
- // considered standard)
- if (txin.scriptSig.size() > 1650) {
- reason = "scriptsig-size";
- return false;
- }
- if (!txin.scriptSig.IsPushOnly()) {
- reason = "scriptsig-not-pushonly";
- return false;
- }
- }
-
- unsigned int nDataOut = 0;
- txnouttype whichType;
- BOOST_FOREACH(const CTxOut& txout, tx.vout) {
- if (!::IsStandard(txout.scriptPubKey, whichType)) {
- reason = "scriptpubkey";
- return false;
- }
-
- if (whichType == TX_NULL_DATA)
- nDataOut++;
- else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
- reason = "bare-multisig";
- return false;
- } else if (txout.IsDust(::minRelayTxFee)) {
- reason = "dust";
- return false;
- }
- }
-
- // only one OP_RETURN txout is permitted
- if (nDataOut > 1) {
- reason = "multi-op-return";
- return false;
- }
-
- return true;
-}
-
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
{
- AssertLockHeld(cs_main);
- // Time based nLockTime implemented in 0.1.6
if (tx.nLockTime == 0)
return true;
- if (nBlockHeight == 0)
- nBlockHeight = chainActive.Height();
- if (nBlockTime == 0)
- nBlockTime = GetAdjustedTime();
if ((int64_t)tx.nLockTime < ((int64_t)tx.nLockTime < LOCKTIME_THRESHOLD ? (int64_t)nBlockHeight : nBlockTime))
return true;
BOOST_FOREACH(const CTxIn& txin, tx.vin)
@@ -675,72 +650,10 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
return true;
}
-/**
- * Check transaction inputs to mitigate two
- * potential denial-of-service attacks:
- *
- * 1. scriptSigs with extra data stuffed into them,
- * not consumed by scriptPubKey (or P2SH script)
- * 2. P2SH scripts with a crazy number of expensive
- * CHECKSIG/CHECKMULTISIG operations
- */
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+bool CheckFinalTx(const CTransaction &tx)
{
- if (tx.IsCoinBase())
- return true; // Coinbases don't use vin normally
-
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- {
- const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
-
- vector<vector<unsigned char> > vSolutions;
- txnouttype whichType;
- // get the scriptPubKey corresponding to this input:
- const CScript& prevScript = prev.scriptPubKey;
- if (!Solver(prevScript, whichType, vSolutions))
- return false;
- int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
- if (nArgsExpected < 0)
- return false;
-
- // Transactions with extra stuff in their scriptSigs are
- // non-standard. Note that this EvalScript() call will
- // be quick, because if there are any operations
- // beside "push data" in the scriptSig
- // IsStandardTx() will have already returned false
- // and this method isn't called.
- vector<vector<unsigned char> > stack;
- if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
- return false;
-
- if (whichType == TX_SCRIPTHASH)
- {
- if (stack.empty())
- return false;
- CScript subscript(stack.back().begin(), stack.back().end());
- vector<vector<unsigned char> > vSolutions2;
- txnouttype whichType2;
- if (Solver(subscript, whichType2, vSolutions2))
- {
- int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
- if (tmpExpected < 0)
- return false;
- nArgsExpected += tmpExpected;
- }
- else
- {
- // Any other Script with less than 15 sigops OK:
- unsigned int sigops = subscript.GetSigOpCount(true);
- // ... extra data left on the stack after execution is OK, too:
- return (sigops <= MAX_P2SH_SIGOPS);
- }
- }
-
- if (stack.size() != (unsigned int)nArgsExpected)
- return false;
- }
-
- return true;
+ AssertLockHeld(cs_main);
+ return IsFinalTx(tx, chainActive.Height() + 1, GetAdjustedTime());
}
unsigned int GetLegacySigOpCount(const CTransaction& tx)
@@ -783,30 +696,24 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
{
// Basic checks that don't depend on any context
if (tx.vin.empty())
- return state.DoS(10, error("CheckTransaction(): vin empty"),
- REJECT_INVALID, "bad-txns-vin-empty");
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty");
if (tx.vout.empty())
- return state.DoS(10, error("CheckTransaction(): vout empty"),
- REJECT_INVALID, "bad-txns-vout-empty");
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty");
// Size limits
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE)
- return state.DoS(100, error("CheckTransaction(): size limits failed"),
- REJECT_INVALID, "bad-txns-oversize");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize");
// Check for negative or overflow output values
CAmount nValueOut = 0;
BOOST_FOREACH(const CTxOut& txout, tx.vout)
{
if (txout.nValue < 0)
- return state.DoS(100, error("CheckTransaction(): txout.nValue negative"),
- REJECT_INVALID, "bad-txns-vout-negative");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-negative");
if (txout.nValue > MAX_MONEY)
- return state.DoS(100, error("CheckTransaction(): txout.nValue too high"),
- REJECT_INVALID, "bad-txns-vout-toolarge");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-vout-toolarge");
nValueOut += txout.nValue;
if (!MoneyRange(nValueOut))
- return state.DoS(100, error("CheckTransaction(): txout total out of range"),
- REJECT_INVALID, "bad-txns-txouttotal-toolarge");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-txouttotal-toolarge");
}
// Check for duplicate inputs
@@ -814,23 +721,20 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
BOOST_FOREACH(const CTxIn& txin, tx.vin)
{
if (vInOutPoints.count(txin.prevout))
- return state.DoS(100, error("CheckTransaction(): duplicate inputs"),
- REJECT_INVALID, "bad-txns-inputs-duplicate");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-duplicate");
vInOutPoints.insert(txin.prevout);
}
if (tx.IsCoinBase())
{
if (tx.vin[0].scriptSig.size() < 2 || tx.vin[0].scriptSig.size() > 100)
- return state.DoS(100, error("CheckTransaction(): coinbase script size"),
- REJECT_INVALID, "bad-cb-length");
+ return state.DoS(100, false, REJECT_INVALID, "bad-cb-length");
}
else
{
BOOST_FOREACH(const CTxIn& txin, tx.vin)
if (txin.prevout.IsNull())
- return state.DoS(10, error("CheckTransaction(): prevout is null"),
- REJECT_INVALID, "bad-txns-prevout-null");
+ return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null");
}
return true;
@@ -865,6 +769,14 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF
return nMinFee;
}
+/** Convert CValidationState to a human-readable message for logging */
+static std::string FormatStateMessage(const CValidationState &state)
+{
+ return strprintf("%s%s (code %i)",
+ state.GetRejectReason(),
+ state.GetDebugMessage().empty() ? "" : ", "+state.GetDebugMessage(),
+ state.GetRejectCode());
+}
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
bool* pfMissingInputs, bool fRejectAbsurdFee)
@@ -874,44 +786,27 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
*pfMissingInputs = false;
if (!CheckTransaction(tx, state))
- return error("AcceptToMemoryPool: CheckTransaction failed");
+ return false;
// Coinbase is only valid in a block, not as a loose transaction
if (tx.IsCoinBase())
- return state.DoS(100, error("AcceptToMemoryPool: coinbase as individual tx"),
- REJECT_INVALID, "coinbase");
+ return state.DoS(100, false, REJECT_INVALID, "coinbase");
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
string reason;
- if (Params().RequireStandard() && !IsStandardTx(tx, reason))
- return state.DoS(0,
- error("AcceptToMemoryPool: nonstandard transaction: %s", reason),
- REJECT_NONSTANDARD, reason);
+ if (fRequireStandard && !IsStandardTx(tx, reason))
+ return state.DoS(0, false, REJECT_NONSTANDARD, reason);
// Only accept nLockTime-using transactions that can be mined in the next
// block; we don't want our mempool filled up with transactions that can't
// be mined yet.
- //
- // However, IsFinalTx() is confusing... Without arguments, it uses
- // chainActive.Height() to evaluate nLockTime; when a block is accepted,
- // chainActive.Height() is set to the value of nHeight in the block.
- // However, when IsFinalTx() is called within CBlock::AcceptBlock(), the
- // height of the block *being* evaluated is what is used. Thus if we want
- // to know if a transaction can be part of the *next* block, we need to
- // call IsFinalTx() with one more than chainActive.Height().
- //
- // Timestamps on the other hand don't get any special treatment, because we
- // can't know what timestamp the next block will have, and there aren't
- // timestamp applications where it matters.
- if (!IsFinalTx(tx, chainActive.Height() + 1))
- return state.DoS(0,
- error("AcceptToMemoryPool: non-final"),
- REJECT_NONSTANDARD, "non-final");
+ if (!CheckFinalTx(tx))
+ return state.DoS(0, false, REJECT_NONSTANDARD, "non-final");
// is it already in the memory pool?
uint256 hash = tx.GetHash();
if (pool.exists(hash))
- return false;
+ return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-in-mempool");
// Check for conflicts with in-memory transactions
{
@@ -922,7 +817,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (pool.mapNextTx.count(outpoint))
{
// Disable replacement feature for now
- return false;
+ return state.Invalid(false, REJECT_CONFLICT, "txn-mempool-conflict");
}
}
}
@@ -939,7 +834,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// do we already have it?
if (view.HaveCoins(hash))
- return false;
+ return state.Invalid(false, REJECT_ALREADY_KNOWN, "txn-already-known");
// do all inputs exist?
// Note that this does not check for the presence of actual outputs (see the next check for that),
@@ -948,14 +843,13 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (!view.HaveCoins(txin.prevout.hash)) {
if (pfMissingInputs)
*pfMissingInputs = true;
- return false;
+ return false; // fMissingInputs and !state.IsInvalid() is used to detect this condition, don't set state.Invalid()
}
}
// are the actual inputs available?
if (!view.HaveInputs(tx))
- return state.Invalid(error("AcceptToMemoryPool: inputs already spent"),
- REJECT_DUPLICATE, "bad-txns-inputs-spent");
+ return state.Invalid(false, REJECT_DUPLICATE, "bad-txns-inputs-spent");
// Bring the best block into scope
view.GetBestBlock();
@@ -967,8 +861,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
}
// Check for non-standard pay-to-script-hash in inputs
- if (Params().RequireStandard() && !AreInputsStandard(tx, view))
- return error("AcceptToMemoryPool: nonstandard transaction input");
+ 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
@@ -978,24 +872,21 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
unsigned int nSigOps = GetLegacySigOpCount(tx);
nSigOps += GetP2SHSigOpCount(tx, view);
if (nSigOps > MAX_STANDARD_TX_SIGOPS)
- return state.DoS(0,
- error("AcceptToMemoryPool: too many sigops %s, %d > %d",
- hash.ToString(), nSigOps, MAX_STANDARD_TX_SIGOPS),
- REJECT_NONSTANDARD, "bad-txns-too-many-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;
double dPriority = view.GetPriority(tx, chainActive.Height());
- CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height());
+ CTxMemPoolEntry entry(tx, nFees, GetTime(), dPriority, chainActive.Height(), mempool.HasNoInputsOf(tx));
unsigned int nSize = entry.GetTxSize();
// Don't accept it if it can't get into a block
CAmount txMinFee = GetMinRelayFee(tx, nSize, true);
if (fLimitFree && nFees < txMinFee)
- return state.DoS(0, error("AcceptToMemoryPool: not enough fees %s, %d < %d",
- hash.ToString(), nFees, txMinFee),
- REJECT_INSUFFICIENTFEE, "insufficient fee");
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "insufficient fee", false,
+ strprintf("%d < %d", nFees, txMinFee));
// Require that free transactions have sufficient priority to be mined in the next block.
if (GetBoolArg("-relaypriority", true) && nFees < ::minRelayTxFee.GetFee(nSize) && !AllowFree(view.GetPriority(tx, chainActive.Height() + 1))) {
@@ -1020,23 +911,31 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// -limitfreerelay unit is thousand-bytes-per-minute
// At default rate it would take over a month to fill 1GB
if (dFreeCount >= GetArg("-limitfreerelay", 15)*10*1000)
- return state.DoS(0, error("AcceptToMemoryPool: free transaction rejected by rate limiter"),
- REJECT_INSUFFICIENTFEE, "rate limited free transaction");
+ return state.DoS(0, false, REJECT_INSUFFICIENTFEE, "rate limited free transaction");
LogPrint("mempool", "Rate limit dFreeCount: %g => %g\n", dFreeCount, dFreeCount+nSize);
dFreeCount += nSize;
}
if (fRejectAbsurdFee && nFees > ::minRelayTxFee.GetFee(nSize) * 10000)
- return error("AcceptToMemoryPool: absurdly high fees %s, %d > %d",
- hash.ToString(),
- nFees, ::minRelayTxFee.GetFee(nSize) * 10000);
+ return state.Invalid(false,
+ REJECT_HIGHFEE, "absurdly-high-fee",
+ strprintf("%d > %d", nFees, ::minRelayTxFee.GetFee(nSize) * 10000));
+
+ // Calculate in-mempool ancestors, up to a limit.
+ CTxMemPool::setEntries setAncestors;
+ size_t nLimitAncestors = GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT);
+ size_t nLimitAncestorSize = GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT)*1000;
+ size_t nLimitDescendants = GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT);
+ size_t nLimitDescendantSize = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000;
+ std::string errString;
+ if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) {
+ return state.DoS(0, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString);
+ }
// Check against previous transactions
// This is done last to help prevent CPU exhaustion denial-of-service attacks.
if (!CheckInputs(tx, state, view, true, STANDARD_SCRIPT_VERIFY_FLAGS, true))
- {
- return error("AcceptToMemoryPool: ConnectInputs failed %s", hash.ToString());
- }
+ return false;
// Check again against just the consensus-critical mandatory script
// verification flags, in case of bugs in the standard flags that cause
@@ -1049,11 +948,12 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
// can be exploited as a DoS attack.
if (!CheckInputs(tx, state, view, true, MANDATORY_SCRIPT_VERIFY_FLAGS, true))
{
- return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString());
+ return error("%s: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s, %s",
+ __func__, hash.ToString(), FormatStateMessage(state));
}
// Store transaction in memory
- pool.addUnchecked(hash, entry);
+ pool.addUnchecked(hash, entry, setAncestors, !IsInitialBlockDownload());
}
SyncWithWallets(tx, NULL);
@@ -1134,7 +1034,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
// CBlock and CBlockIndex
//
-bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
+bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
@@ -1143,7 +1043,7 @@ bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos)
// Write index header
unsigned int nSize = fileout.GetSerializeSize(block);
- fileout << FLATDATA(Params().MessageStart()) << nSize;
+ fileout << FLATDATA(messageStart) << nSize;
// Write block
long fileOutPos = ftell(fileout.Get());
@@ -1189,19 +1089,17 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex)
return true;
}
-CAmount GetBlockValue(int nHeight, const CAmount& nFees)
+CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
- CAmount nSubsidy = 50 * COIN;
- int halvings = nHeight / Params().SubsidyHalvingInterval();
-
+ int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64)
- return nFees;
+ return 0;
+ CAmount nSubsidy = 50 * COIN;
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
nSubsidy >>= halvings;
-
- return nSubsidy + nFees;
+ return nSubsidy;
}
bool IsInitialBlockDownload()
@@ -1329,9 +1227,11 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
log(pindexNew->nChainWork.getdouble())/log(2.0), DateTimeStrFormat("%Y-%m-%d %H:%M:%S",
pindexNew->GetBlockTime()));
+ CBlockIndex *tip = chainActive.Tip();
+ assert (tip);
LogPrintf("%s: current best=%s height=%d log2_work=%.8g date=%s\n", __func__,
- chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0),
- DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()));
+ tip->GetBlockHash().ToString(), chainActive.Height(), log(tip->nChainWork.getdouble())/log(2.0),
+ DateTimeStrFormat("%Y-%m-%d %H:%M:%S", tip->GetBlockTime()));
CheckForkWarningConditions();
}
@@ -1340,7 +1240,8 @@ void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state
if (state.IsInvalid(nDoS)) {
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
if (it != mapBlockSource.end() && State(it->second)) {
- CBlockReject reject = {state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
+ assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
+ CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
State(it->second)->rejects.push_back(reject);
if (nDoS > 0)
Misbehaving(it->second, nDoS);
@@ -1390,27 +1291,26 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, cacheStore), &error)) {
- return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error));
+ return false;
}
return true;
}
-bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+int GetSpendHeight(const CCoinsViewCache& inputs)
{
- if (!tx.IsCoinBase())
- {
- if (pvChecks)
- pvChecks->reserve(tx.vin.size());
+ LOCK(cs_main);
+ CBlockIndex* pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
+ return pindexPrev->nHeight + 1;
+}
+namespace Consensus {
+bool CheckTxInputs(const CTransaction& tx, CValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight)
+{
// This doesn't trigger the DoS code on purpose; if it did, it would make it easier
// for an attacker to attempt to split the network.
if (!inputs.HaveInputs(tx))
- return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString()));
+ return state.Invalid(false, 0, "", "Inputs unavailable");
- // While checking, GetBestBlock() refers to the parent block.
- // This is also true for mempool checks.
- CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second;
- int nSpendHeight = pindexPrev->nHeight + 1;
CAmount nValueIn = 0;
CAmount nFees = 0;
for (unsigned int i = 0; i < tx.vin.size(); i++)
@@ -1422,33 +1322,42 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
// If prev is coinbase, check that it's matured
if (coins->IsCoinBase()) {
if (nSpendHeight - coins->nHeight < COINBASE_MATURITY)
- return state.Invalid(
- error("CheckInputs(): tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight),
- REJECT_INVALID, "bad-txns-premature-spend-of-coinbase");
+ return state.Invalid(false,
+ REJECT_INVALID, "bad-txns-premature-spend-of-coinbase",
+ strprintf("tried to spend coinbase at depth %d", nSpendHeight - coins->nHeight));
}
// Check for negative or overflow input values
nValueIn += coins->vout[prevout.n].nValue;
if (!MoneyRange(coins->vout[prevout.n].nValue) || !MoneyRange(nValueIn))
- return state.DoS(100, error("CheckInputs(): txin values out of range"),
- REJECT_INVALID, "bad-txns-inputvalues-outofrange");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputvalues-outofrange");
}
if (nValueIn < tx.GetValueOut())
- return state.DoS(100, error("CheckInputs(): %s value in (%s) < value out (%s)",
- tx.GetHash().ToString(), FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())),
- REJECT_INVALID, "bad-txns-in-belowout");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", false,
+ strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(tx.GetValueOut())));
// Tally transaction fees
CAmount nTxFee = nValueIn - tx.GetValueOut();
if (nTxFee < 0)
- return state.DoS(100, error("CheckInputs(): %s nTxFee < 0", tx.GetHash().ToString()),
- REJECT_INVALID, "bad-txns-fee-negative");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative");
nFees += nTxFee;
if (!MoneyRange(nFees))
- return state.DoS(100, error("CheckInputs(): nFees out of range"),
- REJECT_INVALID, "bad-txns-fee-outofrange");
+ return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange");
+ return true;
+}
+}// namespace Consensus
+
+bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheStore, std::vector<CScriptCheck> *pvChecks)
+{
+ if (!tx.IsCoinBase())
+ {
+ if (!Consensus::CheckTxInputs(tx, state, inputs, GetSpendHeight(inputs)))
+ return false;
+
+ if (pvChecks)
+ pvChecks->reserve(tx.vin.size());
// The first loop above does all the inexpensive checks.
// Only if ALL inputs pass do we perform expensive ECDSA signature checks.
@@ -1499,7 +1408,7 @@ bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsVi
namespace {
-bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock)
+bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint256& hashBlock, const CMessageHeader::MessageStartChars& messageStart)
{
// Open history file to append
CAutoFile fileout(OpenUndoFile(pos), SER_DISK, CLIENT_VERSION);
@@ -1508,7 +1417,7 @@ bool UndoWriteToDisk(const CBlockUndo& blockundo, CDiskBlockPos& pos, const uint
// Write index header
unsigned int nSize = fileout.GetSerializeSize(blockundo);
- fileout << FLATDATA(Params().MessageStart()) << nSize;
+ fileout << FLATDATA(messageStart) << nSize;
// Write undo data
long fileOutPos = ftell(fileout.Get());
@@ -1553,6 +1462,24 @@ bool UndoReadFromDisk(CBlockUndo& blockundo, const CDiskBlockPos& pos, const uin
return true;
}
+/** Abort with a message */
+bool AbortNode(const std::string& strMessage, const std::string& userMessage="")
+{
+ strMiscWarning = strMessage;
+ LogPrintf("*** %s\n", strMessage);
+ uiInterface.ThreadSafeMessageBox(
+ userMessage.empty() ? _("Error: A fatal internal error occurred, see debug.log for details") : userMessage,
+ "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return false;
+}
+
+bool AbortNode(CValidationState& state, const std::string& strMessage, const std::string& userMessage="")
+{
+ AbortNode(strMessage, userMessage);
+ return state.Error(strMessage);
+}
+
} // anon namespace
/**
@@ -1588,7 +1515,7 @@ static bool ApplyTxInUndo(const CTxInUndo& undo, CCoinsViewCache& view, const CO
return fClean;
}
-bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
+bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
assert(pindex->GetBlockHash() == view.GetBestBlock());
@@ -1688,6 +1615,68 @@ void ThreadScriptCheck() {
scriptcheckqueue.Thread();
}
+//
+// Called periodically asynchronously; alerts if it smells like
+// we're being fed a bad chain (blocks being generated much
+// too slowly or too quickly).
+//
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader,
+ int64_t nPowTargetSpacing)
+{
+ if (bestHeader == NULL || initialDownloadCheck()) return;
+
+ static int64_t lastAlertTime = 0;
+ int64_t now = GetAdjustedTime();
+ if (lastAlertTime > now-60*60*24) return; // Alert at most once per day
+
+ const int SPAN_HOURS=4;
+ const int SPAN_SECONDS=SPAN_HOURS*60*60;
+ int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing;
+
+ boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED);
+
+ std::string strWarning;
+ int64_t startTime = GetAdjustedTime()-SPAN_SECONDS;
+
+ LOCK(cs);
+ const CBlockIndex* i = bestHeader;
+ int nBlocks = 0;
+ while (i->GetBlockTime() >= startTime) {
+ ++nBlocks;
+ i = i->pprev;
+ if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed
+ }
+
+ // How likely is it to find that many by chance?
+ double p = boost::math::pdf(poisson, nBlocks);
+
+ LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS);
+ LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p);
+
+ // Aim for one false-positive about every fifty years of normal running:
+ const int FIFTY_YEARS = 50*365*24*60*60;
+ double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS);
+
+ if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED)
+ {
+ // Many fewer blocks than expected: alert!
+ strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"),
+ nBlocks, SPAN_HOURS, BLOCKS_EXPECTED);
+ }
+ else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED)
+ {
+ // Many more blocks than expected: alert!
+ strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"),
+ nBlocks, SPAN_HOURS, BLOCKS_EXPECTED);
+ }
+ if (!strWarning.empty())
+ {
+ strMiscWarning = strWarning;
+ CAlert::Notify(strWarning, true);
+ lastAlertTime = now;
+ }
+}
+
static int64_t nTimeVerify = 0;
static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0;
@@ -1714,7 +1703,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true;
}
- bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
+ bool fScriptChecks = true;
+ if (fCheckpointsEnabled) {
+ CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) {
+ // This block is an ancestor of a checkpoint: disable script checks
+ fScriptChecks = false;
+ }
+ }
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent.
@@ -1747,7 +1743,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
unsigned int flags = fStrictPayToScriptHash ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE;
// Start enforcing the DERSIG (BIP66) rules, for block.nVersion=3 blocks, when 75% of the network has upgraded:
- if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, Params().EnforceBlockUpgradeMajority())) {
+ if (block.nVersion >= 3 && IsSuperMajority(3, pindex->pprev, chainparams.GetConsensus().nMajorityEnforceBlockUpgrade, chainparams.GetConsensus())) {
flags |= SCRIPT_VERIFY_DERSIG;
}
@@ -1794,7 +1790,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
std::vector<CScriptCheck> vChecks;
if (!CheckInputs(tx, state, view, fScriptChecks, flags, false, nScriptCheckThreads ? &vChecks : NULL))
- return false;
+ return error("ConnectBlock(): CheckInputs on %s failed with %s",
+ tx.GetHash().ToString(), FormatStateMessage(state));
control.Add(vChecks);
}
@@ -1810,10 +1807,11 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart;
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001);
- if (block.vtx[0].GetValueOut() > GetBlockValue(pindex->nHeight, nFees))
+ CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
+ if (block.vtx[0].GetValueOut() > blockReward)
return state.DoS(100,
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
- block.vtx[0].GetValueOut(), GetBlockValue(pindex->nHeight, nFees)),
+ block.vtx[0].GetValueOut(), blockReward),
REJECT_INVALID, "bad-cb-amount");
if (!control.Wait())
@@ -1831,8 +1829,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CDiskBlockPos pos;
if (!FindUndoPos(state, pindex->nFile, pos, ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + 40))
return error("ConnectBlock(): FindUndoPos failed");
- if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash()))
- return state.Abort("Failed to write undo data");
+ if (!UndoWriteToDisk(blockundo, pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
+ return AbortNode(state, "Failed to write undo data");
// update nUndoPos in block index
pindex->nUndoPos = pos.nPos;
@@ -1845,7 +1843,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
if (fTxIndex)
if (!pblocktree->WriteTxIndex(vPos))
- return state.Abort("Failed to write transaction index");
+ return AbortNode(state, "Failed to write transaction index");
// add this block to the view's block chain
view.SetBestBlock(pindex->GetBlockHash());
@@ -1880,11 +1878,14 @@ enum FlushStateMode {
bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
LOCK2(cs_main, cs_LastBlockFile);
static int64_t nLastWrite = 0;
+ static int64_t nLastFlush = 0;
+ static int64_t nLastSetChain = 0;
std::set<int> setFilesToPrune;
bool fFlushForPrune = false;
try {
if (fPruneMode && fCheckForPruning) {
FindFilesToPrune(setFilesToPrune);
+ fCheckForPruning = false;
if (!setFilesToPrune.empty()) {
fFlushForPrune = true;
if (!fHavePruned) {
@@ -1893,16 +1894,32 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
}
}
}
- if ((mode == FLUSH_STATE_ALWAYS) ||
- ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->GetCacheSize() > nCoinCacheSize) ||
- (mode == FLUSH_STATE_PERIODIC && GetTimeMicros() > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000) ||
- fFlushForPrune) {
- // Typical CCoins structures on disk are around 100 bytes in size.
- // Pushing a new one to the database can cause it to be written
- // twice (once in the log, and once in the tables). This is already
- // an overestimation, as most will delete an existing entry or
- // overwrite one. Still, use a conservative safety factor of 2.
- if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
+ int64_t nNow = GetTimeMicros();
+ // Avoid writing/flushing immediately after startup.
+ if (nLastWrite == 0) {
+ nLastWrite = nNow;
+ }
+ if (nLastFlush == 0) {
+ nLastFlush = nNow;
+ }
+ if (nLastSetChain == 0) {
+ nLastSetChain = nNow;
+ }
+ size_t cacheSize = pcoinsTip->DynamicMemoryUsage();
+ // The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage;
+ // The cache is over the limit, we have to write now.
+ bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
+ // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash.
+ bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
+ // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
+ bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
+ // Combine all conditions that result in a full cache flush.
+ bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
+ // Write blocks and block index to disk.
+ if (fDoFullFlush || fPeriodicWrite) {
+ // Depend on nMinDiskSpace to ensure we can write block index
+ if (!CheckDiskSpace(0))
return state.Error("out of disk space");
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
@@ -1921,27 +1938,35 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
setDirtyBlockIndex.erase(it++);
}
if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
- return state.Abort("Files to write to block index database");
+ return AbortNode(state, "Files to write to block index database");
}
}
- // Flush the chainstate (which may refer to block index entries).
- if (!pcoinsTip->Flush())
- return state.Abort("Failed to write to coin database");
-
// Finally remove any pruned files
- if (fFlushForPrune) {
+ if (fFlushForPrune)
UnlinkPrunedFiles(setFilesToPrune);
- fCheckForPruning = false;
- }
-
+ nLastWrite = nNow;
+ }
+ // Flush best chain related state. This can only be done if the blocks / block index write was also done.
+ if (fDoFullFlush) {
+ // Typical CCoins structures on disk are around 128 bytes in size.
+ // Pushing a new one to the database can cause it to be written
+ // twice (once in the log, and once in the tables). This is already
+ // an overestimation, as most will delete an existing entry or
+ // overwrite one. Still, use a conservative safety factor of 2.
+ if (!CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize()))
+ return state.Error("out of disk space");
+ // Flush the chainstate (which may refer to block index entries).
+ if (!pcoinsTip->Flush())
+ return AbortNode(state, "Failed to write to coin database");
+ nLastFlush = nNow;
+ }
+ if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) {
// Update best block in wallet (so we can detect restored wallets).
- if (mode != FLUSH_STATE_IF_NEEDED) {
- GetMainSignals().SetBestChain(chainActive.GetLocator());
- }
- nLastWrite = GetTimeMicros();
+ GetMainSignals().SetBestChain(chainActive.GetLocator());
+ nLastSetChain = nNow;
}
} catch (const std::runtime_error& e) {
- return state.Abort(std::string("System error while flushing: ") + e.what());
+ return AbortNode(state, std::string("System error while flushing: ") + e.what());
}
return true;
}
@@ -1966,10 +1991,10 @@ void static UpdateTip(CBlockIndex *pindexNew) {
nTimeBestReceived = GetTime();
mempool.AddTransactionsUpdated(1);
- LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u\n", __func__,
+ LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__,
chainActive.Tip()->GetBlockHash().ToString(), chainActive.Height(), log(chainActive.Tip()->nChainWork.getdouble())/log(2.0), (unsigned long)chainActive.Tip()->nChainTx,
DateTimeStrFormat("%Y-%m-%d %H:%M:%S", chainActive.Tip()->GetBlockTime()),
- Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), (unsigned int)pcoinsTip->GetCacheSize());
+ Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.Tip()), pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize());
cvBlockChange.notify_all();
@@ -2005,7 +2030,7 @@ bool static DisconnectTip(CValidationState &state) {
// Read block from disk.
CBlock block;
if (!ReadBlockFromDisk(block, pindexDelete))
- return state.Abort("Failed to read block");
+ return AbortNode(state, "Failed to read block");
// Apply the block atomically to the chain state.
int64_t nStart = GetTimeMicros();
{
@@ -2019,13 +2044,23 @@ bool static DisconnectTip(CValidationState &state) {
if (!FlushStateToDisk(state, FLUSH_STATE_IF_NEEDED))
return false;
// Resurrect mempool transactions from the disconnected block.
+ std::vector<uint256> vHashUpdate;
BOOST_FOREACH(const CTransaction &tx, block.vtx) {
// ignore validation errors in resurrected transactions
list<CTransaction> removed;
CValidationState stateDummy;
- if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL))
+ if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) {
mempool.remove(tx, removed, true);
+ } else if (mempool.exists(tx.GetHash())) {
+ vHashUpdate.push_back(tx.GetHash());
+ }
}
+ // AcceptToMemoryPool/addUnchecked all assume that new mempool entries have
+ // no in-mempool children, which is generally not true when adding
+ // previously-confirmed transactions back to the mempool.
+ // UpdateTransactionsFromBlock finds descendants of any transactions in this
+ // block that were added back and cleans up the mempool state.
+ mempool.UpdateTransactionsFromBlock(vHashUpdate);
mempool.removeCoinbaseSpends(pcoinsTip, pindexDelete->nHeight);
mempool.check(pcoinsTip);
// Update chainActive and related variables.
@@ -2044,11 +2079,11 @@ static int64_t nTimeFlush = 0;
static int64_t nTimeChainState = 0;
static int64_t nTimePostConnect = 0;
-/**
+/**
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*/
-bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *pblock) {
+bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, const CBlock *pblock) {
assert(pindexNew->pprev == chainActive.Tip());
mempool.check(pcoinsTip);
// Read block from disk.
@@ -2056,7 +2091,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
CBlock block;
if (!pblock) {
if (!ReadBlockFromDisk(block, pindexNew))
- return state.Abort("Failed to read block");
+ return AbortNode(state, "Failed to read block");
pblock = &block;
}
// Apply the block atomically to the chain state.
@@ -2065,7 +2100,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
LogPrint("bench", " - Load block from disk: %.2fms [%.2fs]\n", (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001);
{
CCoinsViewCache view(pcoinsTip);
- CInv inv(MSG_BLOCK, pindexNew->GetBlockHash());
bool rv = ConnectBlock(*pblock, state, pindexNew, view);
GetMainSignals().BlockChecked(*pblock, state);
if (!rv) {
@@ -2073,7 +2107,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
InvalidBlockFound(pindexNew, state);
return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString());
}
- mapBlockSource.erase(inv.hash);
+ mapBlockSource.erase(pindexNew->GetBlockHash());
nTime3 = GetTimeMicros(); nTimeConnectTotal += nTime3 - nTime2;
LogPrint("bench", " - Connect total: %.2fms [%.2fs]\n", (nTime3 - nTime2) * 0.001, nTimeConnectTotal * 0.000001);
assert(view.Flush());
@@ -2087,7 +2121,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock *
LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001);
// Remove conflicting transactions from the mempool.
list<CTransaction> txConflicted;
- mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted);
+ mempool.removeForBlock(pblock->vtx, pindexNew->nHeight, txConflicted, !IsInitialBlockDownload());
mempool.check(pcoinsTip);
// Update chainActive & related variables.
UpdateTip(pindexNew);
@@ -2181,7 +2215,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, CBlock *pblock) {
+static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork, const CBlock *pblock) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -2250,7 +2284,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
* or an activated best chain. pblock is either NULL or a pointer to a block
* that is already loaded (to avoid loading it again from disk).
*/
-bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
+bool ActivateBestChain(CValidationState &state, const CBlock *pblock) {
CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL;
const CChainParams& chainParams = Params();
@@ -2288,6 +2322,7 @@ bool ActivateBestChain(CValidationState &state, CBlock *pblock) {
pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
}
// Notify external listeners about the new tip.
+ GetMainSignals().UpdatedBlockTip(hashNewTip);
uiInterface.NotifyBlockTip(hashNewTip);
}
} while(pindexMostWork != chainActive.Tip());
@@ -2592,7 +2627,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state))
- return error("CheckBlock(): CheckTransaction failed");
+ return error("CheckBlock(): CheckTransaction of %s failed with %s",
+ tx.GetHash().ToString(),
+ FormatStateMessage(state));
unsigned int nSigOps = 0;
BOOST_FOREACH(const CTransaction& tx, block.vtx)
@@ -2606,18 +2643,23 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
return true;
}
-bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+static bool CheckIndexAgainstCheckpoint(const CBlockIndex* pindexPrev, CValidationState& state, const CChainParams& chainparams, const uint256& hash)
{
- const CChainParams& chainParams = Params();
- const Consensus::Params& consensusParams = chainParams.GetConsensus();
- uint256 hash = block.GetHash();
- if (hash == consensusParams.hashGenesisBlock)
+ if (*pindexPrev->phashBlock == chainparams.GetConsensus().hashGenesisBlock)
return true;
- assert(pindexPrev);
-
int nHeight = pindexPrev->nHeight+1;
+ // Don't accept any forks from the main chain prior to last checkpoint
+ CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints());
+ if (pcheckpoint && nHeight < pcheckpoint->nHeight)
+ return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
+
+ return true;
+}
+bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex * const pindexPrev)
+{
+ const Consensus::Params& consensusParams = Params().GetConsensus();
// Check proof of work
if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
return state.DoS(100, error("%s: incorrect proof of work", __func__),
@@ -2628,32 +2670,15 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
return state.Invalid(error("%s: block's timestamp is too early", __func__),
REJECT_INVALID, "time-too-old");
- if(fCheckpointsEnabled)
- {
- // Check that the block chain matches the known block chain up to a checkpoint
- if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash))
- return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),
- REJECT_CHECKPOINT, "checkpoint mismatch");
-
- // Don't accept any forks from the main chain prior to last checkpoint
- CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints());
- if (pcheckpoint && nHeight < pcheckpoint->nHeight)
- return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight));
- }
-
// Reject block.nVersion=1 blocks when 95% (75% on testnet) of the network has upgraded:
- if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated))
- {
+ if (block.nVersion < 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s: rejected nVersion=1 block", __func__),
REJECT_OBSOLETE, "bad-version");
- }
// Reject block.nVersion=2 blocks when 95% (75% on testnet) of the network has upgraded:
- if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated))
- {
+ if (block.nVersion < 3 && IsSuperMajority(3, pindexPrev, consensusParams.nMajorityRejectBlockOutdated, consensusParams))
return state.Invalid(error("%s : rejected nVersion=2 block", __func__),
REJECT_OBSOLETE, "bad-version");
- }
return true;
}
@@ -2661,6 +2686,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta
bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex * const pindexPrev)
{
const int nHeight = pindexPrev == NULL ? 0 : pindexPrev->nHeight + 1;
+ const Consensus::Params& consensusParams = Params().GetConsensus();
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx)
@@ -2670,7 +2696,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
// Enforce block.nVersion=2 rule that the coinbase starts with serialized block height
// if 750 of the last 1,000 blocks are version 2 or greater (51/100 if testnet):
- if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, Params().EnforceBlockUpgradeMajority()))
+ if (block.nVersion >= 2 && IsSuperMajority(2, pindexPrev, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))
{
CScript expect = CScript() << nHeight;
if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
@@ -2690,33 +2716,37 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
uint256 hash = block.GetHash();
BlockMap::iterator miSelf = mapBlockIndex.find(hash);
CBlockIndex *pindex = NULL;
- if (miSelf != mapBlockIndex.end()) {
- // Block header is already known.
- pindex = miSelf->second;
- if (ppindex)
- *ppindex = pindex;
- if (pindex->nStatus & BLOCK_FAILED_MASK)
- return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
- return true;
- }
+ if (hash != chainparams.GetConsensus().hashGenesisBlock) {
- if (!CheckBlockHeader(block, state))
- return false;
+ if (miSelf != mapBlockIndex.end()) {
+ // Block header is already known.
+ pindex = miSelf->second;
+ if (ppindex)
+ *ppindex = pindex;
+ if (pindex->nStatus & BLOCK_FAILED_MASK)
+ return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate");
+ return true;
+ }
- // Get prev block index
- CBlockIndex* pindexPrev = NULL;
- if (hash != chainparams.GetConsensus().hashGenesisBlock) {
+ if (!CheckBlockHeader(block, state))
+ return false;
+
+ // Get prev block index
+ CBlockIndex* pindexPrev = NULL;
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock);
if (mi == mapBlockIndex.end())
return state.DoS(10, error("%s: prev block not found", __func__), 0, "bad-prevblk");
pindexPrev = (*mi).second;
if (pindexPrev->nStatus & BLOCK_FAILED_MASK)
return state.DoS(100, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk");
- }
- if (!ContextualCheckBlockHeader(block, state, pindexPrev))
- return false;
+ assert(pindexPrev);
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, hash))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
+ if (!ContextualCheckBlockHeader(block, state, pindexPrev))
+ return false;
+ }
if (pindex == NULL)
pindex = AddToBlockIndex(block);
@@ -2726,8 +2756,9 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
return true;
}
-bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp)
+bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
{
+ const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
CBlockIndex *&pindex = *ppindex;
@@ -2735,13 +2766,25 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (!AcceptBlockHeader(block, state, &pindex))
return false;
- // If we're pruning, ensure that we don't allow a peer to dump a copy
- // of old blocks. But we might need blocks that are not on the main chain
- // to handle a reorg, even if we've processed once.
- if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
- // TODO: deal better with duplicate blocks.
- // return state.DoS(20, error("AcceptBlock(): already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
- return true;
+ // Try to process all requested blocks that we don't have, but only
+ // process an unrequested block if it's new and has enough work to
+ // advance our tip, and isn't too many blocks ahead.
+ bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
+ bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
+ // Blocks that are too out-of-order needlessly limit the effectiveness of
+ // pruning, because pruning will not delete block files that contain any
+ // blocks which are too close in height to the tip. Apply this test
+ // regardless of whether pruning is enabled; it should generally be safe to
+ // not process unrequested blocks.
+ bool fTooFarAhead = (pindex->nHeight > int(chainActive.Height() + MIN_BLOCKS_TO_KEEP));
+
+ // TODO: deal better with return value and error conditions for duplicate
+ // and unrequested blocks.
+ if (fAlreadyHave) return true;
+ if (!fRequested) { // If we didn't ask for it:
+ if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
+ if (!fHasMoreWork) return true; // Don't process less-work chains
+ if (fTooFarAhead) return true; // Block height is too high
}
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
@@ -2763,12 +2806,12 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))
return error("AcceptBlock(): FindBlockPos failed");
if (dbp == NULL)
- if (!WriteBlockToDisk(block, blockPos))
- return state.Abort("Failed to write block");
+ if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
+ AbortNode(state, "Failed to write block");
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
} catch (const std::runtime_error& e) {
- return state.Abort(std::string("System error: ") + e.what());
+ return AbortNode(state, std::string("System error: ") + e.what());
}
if (fCheckForPruning)
@@ -2777,11 +2820,10 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return true;
}
-static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired)
+static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned nRequired, const Consensus::Params& consensusParams)
{
- unsigned int nToCheck = Params().ToCheckBlockUpgradeMajority();
unsigned int nFound = 0;
- for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; i++)
+ for (int i = 0; i < consensusParams.nMajorityWindow && nFound < nRequired && pstart != NULL; i++)
{
if (pstart->nVersion >= minVersion)
++nFound;
@@ -2791,21 +2833,22 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
}
-bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
+bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
{
// Preliminary checks
bool checked = CheckBlock(*pblock, state);
{
LOCK(cs_main);
- MarkBlockAsReceived(pblock->GetHash());
+ bool fRequested = MarkBlockAsReceived(pblock->GetHash());
+ fRequested |= fForceProcessing;
if (!checked) {
return error("%s: CheckBlock FAILED", __func__);
}
// Store to disk
CBlockIndex *pindex = NULL;
- bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
+ bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp);
if (pindex && pfrom) {
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
}
@@ -2822,8 +2865,11 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot)
{
+ const CChainParams& chainparams = Params();
AssertLockHeld(cs_main);
- assert(pindexPrev == chainActive.Tip());
+ assert(pindexPrev && pindexPrev == chainActive.Tip());
+ if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, block.GetHash()))
+ return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, state.GetRejectReason().c_str());
CCoinsViewCache viewNew(pcoinsTip);
CBlockIndex indexDummy(block);
@@ -2844,24 +2890,6 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
return true;
}
-
-
-
-
-
-
-
-bool AbortNode(const std::string &strMessage, const std::string &userMessage) {
- strMiscWarning = strMessage;
- LogPrintf("*** %s\n", strMessage);
- uiInterface.ThreadSafeMessageBox(
- userMessage.empty() ? _("Error: A fatal internal error occured, see debug.log for details") : userMessage,
- "", CClientUIInterface::MSG_ERROR);
- StartShutdown();
- return false;
-}
-
-
/**
* BLOCK PRUNING CODE
*/
@@ -2930,7 +2958,7 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
return;
}
- unsigned int nLastBlockWeMustKeep = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
+ unsigned int nLastBlockWeCanPrune = chainActive.Tip()->nHeight - MIN_BLOCKS_TO_KEEP;
uint64_t nCurrentUsage = CalculateCurrentUsage();
// We don't check to prune until after we've allocated new space for files
// So we should leave a buffer under our target to account for another allocation
@@ -2949,9 +2977,9 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
break;
- // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip
- if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeMustKeep)
- break;
+ // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
+ if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
+ continue;
PruneOneBlockFile(fileNumber);
// Queue up the files for removal
@@ -2961,10 +2989,10 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
}
}
- LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB min_must_keep=%d removed %d blk/rev pairs\n",
+ LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
nPruneTarget/1024/1024, nCurrentUsage/1024/1024,
((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,
- nLastBlockWeMustKeep, count);
+ nLastBlockWeCanPrune, count);
}
bool CheckDiskSpace(uint64_t nAdditionalBytes)
@@ -3195,7 +3223,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
- if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize() + pcoinsTip->GetCacheSize()) <= nCoinCacheSize) {
+ if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
bool fClean = true;
if (!DisconnectBlock(block, state, pindex, coins, &fClean))
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
@@ -3254,6 +3282,7 @@ void UnloadBlockIndex()
setDirtyBlockIndex.clear();
setDirtyFileInfo.clear();
mapNodeState.clear();
+ recentRejects.reset(NULL);
BOOST_FOREACH(BlockMap::value_type& entry, mapBlockIndex) {
delete entry.second;
@@ -3272,7 +3301,12 @@ bool LoadBlockIndex()
bool InitBlockIndex() {
+ const CChainParams& chainparams = Params();
LOCK(cs_main);
+
+ // Initialize global variables that cannot be constructed at startup.
+ recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
+
// Check whether we're already initialized
if (chainActive.Genesis() != NULL)
return true;
@@ -3292,7 +3326,7 @@ bool InitBlockIndex() {
CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
return error("LoadBlockIndex(): FindBlockPos failed");
- if (!WriteBlockToDisk(block, blockPos))
+ if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
return error("LoadBlockIndex(): writing genesis block to disk failed");
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
@@ -3370,7 +3404,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
// process in case the block isn't known yet
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
CValidationState state;
- if (ProcessNewBlock(state, NULL, &block, dbp))
+ if (ProcessNewBlock(state, NULL, &block, true, dbp))
nLoaded++;
if (state.IsError())
break;
@@ -3392,7 +3426,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
head.ToString());
CValidationState dummy;
- if (ProcessNewBlock(dummy, NULL, &block, &it->second))
+ if (ProcessNewBlock(dummy, NULL, &block, true, &it->second))
{
nLoaded++;
queue.push_back(block.GetHash());
@@ -3403,7 +3437,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
}
}
} catch (const std::exception& e) {
- LogPrintf("%s: Deserialize or I/O error - %s", __func__, e.what());
+ LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, e.what());
}
}
} catch (const std::runtime_error& e) {
@@ -3604,7 +3638,7 @@ void static CheckBlockIndex()
// CAlert
//
-string GetWarnings(string strFor)
+std::string GetWarnings(const std::string& strFor)
{
int nPriority = 0;
string strStatusBar;
@@ -3669,16 +3703,27 @@ string GetWarnings(string strFor)
//
-bool static AlreadyHave(const CInv& inv)
+bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
switch (inv.type)
{
case MSG_TX:
{
- bool txInMap = false;
- txInMap = mempool.exists(inv.hash);
- return txInMap || mapOrphanTransactions.count(inv.hash) ||
- pcoinsTip->HaveCoins(inv.hash);
+ assert(recentRejects);
+ if (chainActive.Tip()->GetBlockHash() != hashRecentRejectsChainTip)
+ {
+ // If the chain tip has changed previously rejected transactions
+ // might be now valid, e.g. due to a nLockTime'd tx becoming valid,
+ // or a double-spend. Reset the rejects filter and give those
+ // txs a second chance.
+ hashRecentRejectsChainTip = chainActive.Tip()->GetBlockHash();
+ recentRejects->reset();
+ }
+
+ return recentRejects->contains(inv.hash) ||
+ mempool.exists(inv.hash) ||
+ mapOrphanTransactions.count(inv.hash) ||
+ pcoinsTip->HaveCoins(inv.hash);
}
case MSG_BLOCK:
return mapBlockIndex.count(inv.hash);
@@ -3864,7 +3909,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (!vRecv.empty())
vRecv >> addrFrom >> nNonce;
if (!vRecv.empty()) {
- vRecv >> LIMITED_STRING(pfrom->strSubVer, 256);
+ vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
}
if (!vRecv.empty())
@@ -4087,7 +4132,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vToFetch.push_back(inv);
// Mark block as in flight already, even though the actual "getdata" message only goes out
// later (within the same cs_main lock, though).
- MarkBlockAsInFlight(pfrom->GetId(), inv.hash);
+ MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus());
}
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
}
@@ -4180,6 +4225,9 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LOCK(cs_main);
+ if (IsInitialBlockDownload())
+ return true;
+
CBlockIndex* pindex = NULL;
if (locator.IsNull())
{
@@ -4233,12 +4281,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
mempool.check(pcoinsTip);
RelayTransaction(tx);
vWorkQueue.push_back(inv.hash);
- vEraseQueue.push_back(inv.hash);
- LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n",
- pfrom->id, pfrom->cleanSubVer,
+ LogPrint("mempool", "AcceptToMemoryPool: peer=%d: accepted %s (poolsz %u)\n",
+ pfrom->id,
tx.GetHash().ToString(),
- mempool.mapTx.size());
+ mempool.size());
// Recursively process any orphan transactions that depended on this one
set<NodeId> setMisbehaving;
@@ -4260,7 +4307,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
// anyone relaying LegitTxX banned)
CValidationState stateDummy;
- vEraseQueue.push_back(orphanHash);
if (setMisbehaving.count(fromPeer))
continue;
@@ -4269,6 +4315,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString());
RelayTransaction(orphanTx);
vWorkQueue.push_back(orphanHash);
+ vEraseQueue.push_back(orphanHash);
}
else if (!fMissingInputs2)
{
@@ -4280,8 +4327,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
setMisbehaving.insert(fromPeer);
LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString());
}
- // too-little-fee orphan
+ // Has inputs but not accepted to mempool
+ // Probably non-standard or insufficient fee/priority
LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString());
+ vEraseQueue.push_back(orphanHash);
+ assert(recentRejects);
+ recentRejects->insert(orphanHash);
}
mempool.check(pcoinsTip);
}
@@ -4299,20 +4350,34 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
unsigned int nEvicted = LimitOrphanTxSize(nMaxOrphanTx);
if (nEvicted > 0)
LogPrint("mempool", "mapOrphan overflow, removed %u tx\n", nEvicted);
- } else if (pfrom->fWhitelisted) {
- // Always relay transactions received from whitelisted peers, even
- // if they are already in the mempool (allowing the node to function
- // as a gateway for nodes hidden behind it).
- RelayTransaction(tx);
+ } else {
+ // AcceptToMemoryPool() returned false, possibly because the tx is
+ // already in the mempool; if the tx isn't in the mempool that
+ // means it was rejected and we shouldn't ask for it again.
+ if (!mempool.exists(tx.GetHash())) {
+ assert(recentRejects);
+ recentRejects->insert(tx.GetHash());
+ }
+ if (pfrom->fWhitelisted) {
+ // Always relay transactions received from whitelisted peers, even
+ // if they were rejected from the mempool, allowing the node to
+ // function as a gateway for nodes hidden behind it.
+ //
+ // FIXME: This includes invalid transactions, which means a
+ // whitelisted peer could get us banned! We may want to change
+ // that.
+ RelayTransaction(tx);
+ }
}
int nDoS = 0;
if (state.IsInvalid(nDoS))
{
- LogPrint("mempool", "%s from peer=%d %s was not accepted into the memory pool: %s\n", tx.GetHash().ToString(),
- pfrom->id, pfrom->cleanSubVer,
- state.GetRejectReason());
- pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
- state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
+ LogPrint("mempoolrej", "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(),
+ pfrom->id,
+ FormatStateMessage(state));
+ if (state.GetRejectCode() < REJECT_INTERNAL) // Never send AcceptToMemoryPool's internal codes over P2P
+ pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
+ state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0)
Misbehaving(pfrom->GetId(), nDoS);
}
@@ -4384,9 +4449,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
pfrom->AddInventoryKnown(inv);
CValidationState state;
- ProcessNewBlock(state, pfrom, &block);
+ // Process all blocks from whitelisted peers, even if not requested,
+ // unless we're still syncing with the network.
+ // Such an unrequested block may still be processed, subject to the
+ // conditions in AcceptBlock().
+ bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
+ ProcessNewBlock(state, pfrom, &block, forceProcessing, NULL);
int nDoS;
if (state.IsInvalid(nDoS)) {
+ assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash);
if (nDoS > 0) {
@@ -4479,6 +4550,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (pingUsecTime > 0) {
// Successful ping time measurement, replace previous
pfrom->nPingUsecTime = pingUsecTime;
+ pfrom->nMinPingUsecTime = std::min(pfrom->nMinPingUsecTime, pingUsecTime);
} else {
// This should never happen
sProblem = "Timing mishap";
@@ -4502,9 +4574,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
if (!(sProblem.empty())) {
- LogPrint("net", "pong peer=%d %s: %s, %x expected, %x received, %u bytes\n",
+ LogPrint("net", "pong peer=%d: %s, %x expected, %x received, %u bytes\n",
pfrom->id,
- pfrom->cleanSubVer,
sProblem,
pfrom->nPingNonceSent,
nonce,
@@ -4516,7 +4587,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
- else if (strCommand == "alert")
+ else if (fAlerts && strCommand == "alert")
{
CAlert alert;
vRecv >> alert;
@@ -4547,6 +4618,21 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
+ else if (!(nLocalServices & NODE_BLOOM) &&
+ (strCommand == "filterload" ||
+ strCommand == "filteradd" ||
+ strCommand == "filterclear") &&
+ //TODO: Remove this line after reasonable network upgrade
+ pfrom->nVersion >= NO_BLOOM_VERSION)
+ {
+ if (pfrom->nVersion >= NO_BLOOM_VERSION)
+ Misbehaving(pfrom->GetId(), 100);
+ //TODO: Enable this after reasonable network upgrade
+ //else
+ // pfrom->fDisconnect = true;
+ }
+
+
else if (strCommand == "filterload")
{
CBloomFilter filter;
@@ -4801,7 +4887,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
{
// Periodically clear addrKnown to allow refresh broadcasts
if (nLastRebroadcast)
- pnode->addrKnown.clear();
+ pnode->addrKnown.reset();
// Rebroadcast our address
AdvertizeLocal(pnode);
@@ -4846,7 +4932,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
LogPrintf("Warning: not banning local peer %s!\n", pto->addr.ToString());
else
{
- CNode::Ban(pto->addr);
+ CNode::Ban(pto->addr, BanReasonNodeMisbehaving);
}
}
state.fShouldBan = false;
@@ -4941,9 +5027,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
// to unreasonably increase our timeout.
- if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0 && state.vBlocksInFlight.front().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight.front().nValidatedQueuedBefore)) {
- LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", state.vBlocksInFlight.front().hash.ToString(), pto->id);
- pto->fDisconnect = true;
+ // We also compare the block download timeout originally calculated against the time at which we'd disconnect
+ // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
+ // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
+ // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
+ // more quickly than once every 5 minutes, then we'll shorten the download window for this block).
+ if (!pto->fDisconnect && state.vBlocksInFlight.size() > 0) {
+ QueuedBlock &queuedBlock = state.vBlocksInFlight.front();
+ int64_t nTimeoutIfRequestedNow = GetBlockTimeout(nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders, consensusParams);
+ if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) {
+ LogPrint("net", "Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n", pto->id, queuedBlock.hash.ToString(), queuedBlock.nTimeDisconnect, nTimeoutIfRequestedNow);
+ queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
+ }
+ if (queuedBlock.nTimeDisconnect < nNow) {
+ LogPrintf("Timeout downloading block %s from peer=%d, disconnecting\n", queuedBlock.hash.ToString(), pto->id);
+ pto->fDisconnect = true;
+ }
}
//
@@ -4956,7 +5055,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
BOOST_FOREACH(CBlockIndex *pindex, vToDownload) {
vGetData.push_back(CInv(MSG_BLOCK, pindex->GetBlockHash()));
- MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), pindex);
+ MarkBlockAsInFlight(pto->GetId(), pindex->GetBlockHash(), consensusParams, pindex);
LogPrint("net", "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
pindex->nHeight, pto->id);
}
diff --git a/src/main.h b/src/main.h
index 90b809e85e..a6001eed8f 100644
--- a/src/main.h
+++ b/src/main.h
@@ -12,19 +12,10 @@
#include "amount.h"
#include "chain.h"
-#include "chainparams.h"
#include "coins.h"
-#include "consensus/consensus.h"
#include "net.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
-#include "script/script.h"
-#include "script/sigcache.h"
-#include "script/standard.h"
+#include "script/script_error.h"
#include "sync.h"
-#include "tinyformat.h"
-#include "txmempool.h"
-#include "uint256.h"
#include <algorithm>
#include <exception>
@@ -42,24 +33,24 @@ class CBlockTreeDB;
class CBloomFilter;
class CInv;
class CScriptCheck;
+class CTxMemPool;
class CValidationInterface;
class CValidationState;
struct CNodeStateStats;
-/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
-static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
-static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
-/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
-static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
-/** The maximum size for transactions we're willing to relay/mine */
-static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
-/** Maximum number of signature check operations in an IsStandard() P2SH script */
-static const unsigned int MAX_P2SH_SIGOPS = 15;
-/** The maximum number of sigops we're willing to relay/mine in a single tx */
-static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
+/** Default for accepting alerts from the P2P network. */
+static const bool DEFAULT_ALERTS = true;
/** Default for -maxorphantx, maximum number of orphan transactions kept in memory */
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100;
+/** Default for -limitancestorcount, max number of in-mempool ancestors */
+static const unsigned int DEFAULT_ANCESTOR_LIMIT = 100;
+/** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
+static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 900;
+/** Default for -limitdescendantcount, max number of in-mempool descendants */
+static const unsigned int DEFAULT_DESCENDANT_LIMIT = 1000;
+/** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */
+static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 2500;
/** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
@@ -82,21 +73,13 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000;
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
* harder). We'll probably want to make this a per-peer adaptive value at some point. */
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
-/** Time to wait (in seconds) between writing blockchain state to disk. */
-static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
+/** Time to wait (in seconds) between writing blocks/block index to disk. */
+static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
+/** Time to wait (in seconds) between flushing chainstate to disk. */
+static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;
-/** "reject" message codes */
-static const unsigned char REJECT_MALFORMED = 0x01;
-static const unsigned char REJECT_INVALID = 0x10;
-static const unsigned char REJECT_OBSOLETE = 0x11;
-static const unsigned char REJECT_DUPLICATE = 0x12;
-static const unsigned char REJECT_NONSTANDARD = 0x40;
-static const unsigned char REJECT_DUST = 0x41;
-static const unsigned char REJECT_INSUFFICIENTFEE = 0x42;
-static const unsigned char REJECT_CHECKPOINT = 0x43;
-
struct BlockHasher
{
size_t operator()(const uint256& hash) const { return hash.GetCheapHash(); }
@@ -117,10 +100,12 @@ extern bool fReindex;
extern int nScriptCheckThreads;
extern bool fTxIndex;
extern bool fIsBareMultisigStd;
+extern bool fRequireStandard;
extern bool fCheckBlockIndex;
extern bool fCheckpointsEnabled;
-extern unsigned int nCoinCacheSize;
+extern size_t nCoinCacheUsage;
extern CFeeRate minRelayTxFee;
+extern bool fAlerts;
/** Best header we've seen so far (used for getheaders queries' starting points). */
extern CBlockIndex *pindexBestHeader;
@@ -136,7 +121,7 @@ extern bool fPruneMode;
/** Number of MiB of block files that we're trying to stay below. */
extern uint64_t nPruneTarget;
/** Block files containing a block-height within MIN_BLOCKS_TO_KEEP of chainActive.Tip() will not be pruned. */
-static const signed int MIN_BLOCKS_TO_KEEP = 288;
+static const unsigned int MIN_BLOCKS_TO_KEEP = 288;
// Require that user allocate at least 550MB for block & undo files (blk???.dat and rev???.dat)
// At 1MB per block, 288 blocks = 288MB.
@@ -146,7 +131,7 @@ static const signed int MIN_BLOCKS_TO_KEEP = 288;
// full block file chunks, we need the high water mark which triggers the prune to be
// one 128MB block file + added 15% undo data = 147MB greater for a total of 545MB
// Setting the target to > than 550MB will make it likely we can respect the target.
-static const signed int MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
+static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024;
/** Register with a network node to receive its signals */
void RegisterNodeSignals(CNodeSignals& nodeSignals);
@@ -161,10 +146,11 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
* @param[in] pblock The block we want to process.
+ * @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
* @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
* @return True if state.IsValid()
*/
-bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
+bool ProcessNewBlock(CValidationState &state, const CNode* pfrom, const CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp);
/** Check whether enough disk space is available for an incoming block */
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
/** Open a block file (blk?????.dat) */
@@ -192,15 +178,17 @@ bool ProcessMessages(CNode* pfrom);
bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */
void ThreadScriptCheck();
+/** Try to detect Partition (network isolation) attacks against us */
+void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */
-std::string GetWarnings(std::string strFor);
+std::string GetWarnings(const std::string& strFor);
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
bool GetTransaction(const uint256 &hash, CTransaction &tx, uint256 &hashBlock, bool fAllowSlow = false);
/** Find the best known block, and make it the tip of the block chain */
-bool ActivateBestChain(CValidationState &state, CBlock *pblock = NULL);
-CAmount GetBlockValue(int nHeight, const CAmount& nFees);
+bool ActivateBestChain(CValidationState &state, const CBlock *pblock = NULL);
+CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
/**
* Prune block and undo files (blk???.dat and undo???.dat) so that the disk space used is less than a user-defined target.
@@ -226,8 +214,6 @@ void UnlinkPrunedFiles(std::set<int>& setFilesToPrune);
/** Create a new block index entry for a given block hash */
CBlockIndex * InsertBlockIndex(uint256 hash);
-/** Abort with a message */
-bool AbortNode(const std::string &msg, const std::string &userMessage="");
/** Get statistics from node state */
bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats);
/** Increase a node's misbehavior score. */
@@ -277,25 +263,6 @@ struct CDiskTxPos : public CDiskBlockPos
CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree);
-/**
- * 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
- * script can be anything; an attacker could use a very
- * expensive-to-check-upon-redemption script like:
- * DUP CHECKSIG DROP ... repeated 100 times... OP_1
- */
-
-/**
- * Check for standard transaction types
- * @param[in] mapInputs Map of previous transactions that have outputs we're spending
- * @return True if all inputs (scriptSigs) use only standard transaction forms
- */
-bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
-
/**
* Count ECDSA signature operations the old-fashioned (pre-0.6) way
* @return number of sigops this transaction's outputs will produce when spent
@@ -327,12 +294,18 @@ void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCach
/** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state);
-/** Check for standard transaction types
- * @return True if all outputs (scriptPubKeys) use only standard transaction forms
+/**
+ * Check if transaction is final and can be included in a block with the
+ * specified height and time. Consensus critical.
*/
-bool IsStandardTx(const CTransaction& tx, std::string& reason);
+bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime);
-bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64_t nBlockTime = 0);
+/**
+ * Check if transaction will be final in the next block to be created.
+ *
+ * Calls IsFinalTx() with current block height and appropriate block time.
+ */
+bool CheckFinalTx(const CTransaction &tx);
/**
* Closure representing one script verification
@@ -370,7 +343,7 @@ public:
/** Functions for disk access for blocks */
-bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos);
+bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
@@ -381,7 +354,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex);
* In case pfClean is provided, operation will try to be tolerant about errors, and *pfClean
* will be true if no problems were found. Otherwise, the return value will be false in case
* of problems. Note that in any case, coins may be modified. */
-bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
+bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL);
/** Apply the effects of this block (with given index) on the UTXO set represented by coins */
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false);
@@ -397,8 +370,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
-/** Store block on disk. If dbp is provided, the file is known to already reside on disk */
-bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
+/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
+bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
@@ -457,69 +430,6 @@ public:
}
};
-/** Capture information about block/transaction validation */
-class CValidationState {
-private:
- enum mode_state {
- MODE_VALID, //! everything ok
- MODE_INVALID, //! network rule violation (DoS value may be set)
- MODE_ERROR, //! run-time error
- } mode;
- int nDoS;
- std::string strRejectReason;
- unsigned char chRejectCode;
- bool corruptionPossible;
-public:
- CValidationState() : mode(MODE_VALID), nDoS(0), chRejectCode(0), corruptionPossible(false) {}
- bool DoS(int level, bool ret = false,
- unsigned char chRejectCodeIn=0, std::string strRejectReasonIn="",
- bool corruptionIn=false) {
- chRejectCode = chRejectCodeIn;
- strRejectReason = strRejectReasonIn;
- corruptionPossible = corruptionIn;
- if (mode == MODE_ERROR)
- return ret;
- nDoS += level;
- mode = MODE_INVALID;
- return ret;
- }
- bool Invalid(bool ret = false,
- unsigned char _chRejectCode=0, std::string _strRejectReason="") {
- return DoS(0, ret, _chRejectCode, _strRejectReason);
- }
- bool Error(std::string strRejectReasonIn="") {
- if (mode == MODE_VALID)
- strRejectReason = strRejectReasonIn;
- mode = MODE_ERROR;
- return false;
- }
- bool Abort(const std::string &msg) {
- AbortNode(msg);
- return Error(msg);
- }
- bool IsValid() const {
- return mode == MODE_VALID;
- }
- bool IsInvalid() const {
- return mode == MODE_INVALID;
- }
- bool IsError() const {
- return mode == MODE_ERROR;
- }
- bool IsInvalid(int &nDoSOut) const {
- if (IsInvalid()) {
- nDoSOut = nDoS;
- return true;
- }
- return false;
- }
- bool CorruptionPossible() const {
- return corruptionPossible;
- }
- unsigned char GetRejectCode() const { return chRejectCode; }
- std::string GetRejectReason() const { return strRejectReason; }
-};
-
/** RAII wrapper for VerifyDB: Verify consistency of the block and coin databases */
class CVerifyDB {
public:
@@ -546,4 +456,23 @@ extern CCoinsViewCache *pcoinsTip;
/** Global variable that points to the active block tree (protected by cs_main) */
extern CBlockTreeDB *pblocktree;
+/**
+ * Return the spend height, which is one more than the inputs.GetBestBlock().
+ * While checking, GetBestBlock() refers to the parent block. (protected by cs_main)
+ * This is also true for mempool checks.
+ */
+int GetSpendHeight(const CCoinsViewCache& inputs);
+
+/** Reject codes greater or equal to this can be returned by AcceptToMemPool
+ * for transactions, to signal internal conditions. They cannot and should not
+ * be sent over the P2P network.
+ */
+static const unsigned int REJECT_INTERNAL = 0x100;
+/** Too high fee. Can not be triggered by P2P transactions */
+static const unsigned int REJECT_HIGHFEE = 0x100;
+/** Transaction is already known (either in mempool or blockchain) */
+static const unsigned int REJECT_ALREADY_KNOWN = 0x101;
+/** Transaction conflicts with a transaction already known */
+static const unsigned int REJECT_CONFLICT = 0x102;
+
#endif // BITCOIN_MAIN_H
diff --git a/src/memusage.h b/src/memusage.h
new file mode 100644
index 0000000000..b475c3313b
--- /dev/null
+++ b/src/memusage.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2015 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_MEMUSAGE_H
+#define BITCOIN_MEMUSAGE_H
+
+#include <stdlib.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include <boost/foreach.hpp>
+#include <boost/unordered_set.hpp>
+#include <boost/unordered_map.hpp>
+
+namespace memusage
+{
+
+/** Compute the total memory used by allocating alloc bytes. */
+static size_t MallocUsage(size_t alloc);
+
+/** Dynamic memory usage for built-in types is zero. */
+static inline size_t DynamicUsage(const int8_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint8_t& v) { return 0; }
+static inline size_t DynamicUsage(const int16_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint16_t& v) { return 0; }
+static inline size_t DynamicUsage(const int32_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint32_t& v) { return 0; }
+static inline size_t DynamicUsage(const int64_t& v) { return 0; }
+static inline size_t DynamicUsage(const uint64_t& v) { return 0; }
+static inline size_t DynamicUsage(const float& v) { return 0; }
+static inline size_t DynamicUsage(const double& v) { return 0; }
+template<typename X> static inline size_t DynamicUsage(X * const &v) { return 0; }
+template<typename X> static inline size_t DynamicUsage(const X * const &v) { return 0; }
+
+/** Compute the memory used for dynamically allocated but owned data structures.
+ * For generic data types, this is *not* recursive. DynamicUsage(vector<vector<int> >)
+ * will compute the memory used for the vector<int>'s, but not for the ints inside.
+ * This is for efficiency reasons, as these functions are intended to be fast. If
+ * application data structures require more accurate inner accounting, they should
+ * iterate themselves, or use more efficient caching + updating on modification.
+ */
+
+static inline size_t MallocUsage(size_t alloc)
+{
+ // Measured on libc6 2.19 on Linux.
+ if (sizeof(void*) == 8) {
+ return ((alloc + 31) >> 4) << 4;
+ } else if (sizeof(void*) == 4) {
+ return ((alloc + 15) >> 3) << 3;
+ } else {
+ assert(0);
+ }
+}
+
+// STL data structures
+
+template<typename X>
+struct stl_tree_node
+{
+private:
+ int color;
+ void* parent;
+ void* left;
+ void* right;
+ X x;
+};
+
+template<typename X>
+static inline size_t DynamicUsage(const std::vector<X>& v)
+{
+ return MallocUsage(v.capacity() * sizeof(X));
+}
+
+template<typename X, typename Y>
+static inline size_t DynamicUsage(const std::set<X, Y>& s)
+{
+ return MallocUsage(sizeof(stl_tree_node<X>)) * s.size();
+}
+
+template<typename X, typename Y>
+static inline size_t IncrementalDynamicUsage(const std::set<X, Y>& s)
+{
+ return MallocUsage(sizeof(stl_tree_node<X>));
+}
+
+template<typename X, typename Y, typename Z>
+static inline size_t DynamicUsage(const std::map<X, Y, Z>& m)
+{
+ return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >)) * m.size();
+}
+
+template<typename X, typename Y, typename Z>
+static inline size_t IncrementalDynamicUsage(const std::map<X, Y, Z>& m)
+{
+ return MallocUsage(sizeof(stl_tree_node<std::pair<const X, Y> >));
+}
+
+// Boost data structures
+
+template<typename X>
+struct boost_unordered_node : private X
+{
+private:
+ void* ptr;
+};
+
+template<typename X, typename Y>
+static inline size_t DynamicUsage(const boost::unordered_set<X, Y>& s)
+{
+ return MallocUsage(sizeof(boost_unordered_node<X>)) * s.size() + MallocUsage(sizeof(void*) * s.bucket_count());
+}
+
+template<typename X, typename Y, typename Z>
+static inline size_t DynamicUsage(const boost::unordered_map<X, Y, Z>& m)
+{
+ return MallocUsage(sizeof(boost_unordered_node<std::pair<const X, Y> >)) * m.size() + MallocUsage(sizeof(void*) * m.bucket_count());
+}
+
+}
+
+#endif
diff --git a/src/merkleblock.cpp b/src/merkleblock.cpp
index 4d90fd8cd7..f8e877df25 100644
--- a/src/merkleblock.cpp
+++ b/src/merkleblock.cpp
@@ -168,7 +168,7 @@ uint256 CPartialMerkleTree::ExtractMatches(std::vector<uint256> &vMatch) {
// traverse the partial tree
unsigned int nBitsUsed = 0, nHashUsed = 0;
uint256 hashMerkleRoot = TraverseAndExtract(nHeight, 0, nBitsUsed, nHashUsed, vMatch);
- // verify that no problems occured during the tree traversal
+ // verify that no problems occurred during the tree traversal
if (fBad)
return uint256();
// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
diff --git a/src/miner.cpp b/src/miner.cpp
index 4bceb7d7b4..b2a356e52d 100644
--- a/src/miner.cpp
+++ b/src/miner.cpp
@@ -6,19 +6,23 @@
#include "miner.h"
#include "amount.h"
+#include "chain.h"
#include "chainparams.h"
+#include "coins.h"
#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "hash.h"
#include "main.h"
#include "net.h"
+#include "policy/policy.h"
#include "pow.h"
#include "primitives/transaction.h"
+#include "script/standard.h"
#include "timedata.h"
+#include "txmempool.h"
#include "util.h"
#include "utilmoneystr.h"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
+#include "validationinterface.h"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
@@ -80,17 +84,24 @@ public:
}
};
-void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
+int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
{
- pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+ int64_t nOldTime = pblock->nTime;
+ int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime());
+
+ if (nOldTime < nNewTime)
+ pblock->nTime = nNewTime;
// Updating time can change work required on testnet:
if (consensusParams.fPowAllowMinDifficultyBlocks)
pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
+
+ return nNewTime - nOldTime;
}
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
{
+ const CChainParams& chainparams = Params();
// Create new block
auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
if(!pblocktemplate.get())
@@ -136,6 +147,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LOCK2(cs_main, mempool.cs);
CBlockIndex* pindexPrev = chainActive.Tip();
const int nHeight = pindexPrev->nHeight + 1;
+ pblock->nTime = GetAdjustedTime();
CCoinsViewCache view(pcoinsTip);
// Priority order to process transactions
@@ -146,11 +158,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
// This vector will be sorted into a priority queue:
vector<TxPriority> vecPriority;
vecPriority.reserve(mempool.mapTx.size());
- for (map<uint256, CTxMemPoolEntry>::iterator mi = mempool.mapTx.begin();
+ for (CTxMemPool::indexed_transaction_set::iterator mi = mempool.mapTx.begin();
mi != mempool.mapTx.end(); ++mi)
{
- const CTransaction& tx = mi->second.GetTx();
- if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight))
+ const CTransaction& tx = mi->GetTx();
+ if (tx.IsCoinBase() || !IsFinalTx(tx, nHeight, pblock->nTime))
continue;
COrphan* porphan = NULL;
@@ -184,7 +196,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
}
mapDependers[txin.prevout.hash].push_back(porphan);
porphan->setDependsOn.insert(txin.prevout.hash);
- nTotalIn += mempool.mapTx[txin.prevout.hash].GetTx().vout[txin.prevout.n].nValue;
+ nTotalIn += mempool.mapTx.find(txin.prevout.hash)->GetTx().vout[txin.prevout.n].nValue;
continue;
}
const CCoins* coins = view.AccessCoins(txin.prevout.hash);
@@ -214,7 +226,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
porphan->feeRate = feeRate;
}
else
- vecPriority.push_back(TxPriority(dPriority, feeRate, &mi->second.GetTx()));
+ vecPriority.push_back(TxPriority(dPriority, feeRate, &(mi->GetTx())));
}
// Collect transactions into block
@@ -320,7 +332,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize);
// Compute final coinbase transaction.
- txNew.vout[0].nValue = GetBlockValue(nHeight, nFees);
+ txNew.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
txNew.vin[0].scriptSig = CScript() << nHeight << OP_0;
pblock->vtx[0] = txNew;
pblocktemplate->vTxFees[0] = -nFees;
@@ -340,7 +352,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn)
return pblocktemplate.release();
}
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce)
{
// Update nExtraNonce
static uint256 hashPrevBlock;
@@ -359,7 +371,6 @@ void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int&
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
}
-#ifdef ENABLE_WALLET
//////////////////////////////////////////////////////////////////////////////
//
// Internal miner
@@ -398,17 +409,7 @@ bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phas
}
}
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey)
-{
- CPubKey pubkey;
- if (!reservekey.GetReservedKey(pubkey))
- return NULL;
-
- CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
- return CreateNewBlock(scriptPubKey);
-}
-
-static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
+static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams)
{
LogPrintf("%s\n", pblock->ToString());
LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0].vout[0].nValue));
@@ -420,35 +421,35 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
return error("BitcoinMiner: generated block is stale");
}
- // Remove key from key pool
- reservekey.KeepKey();
-
- // Track how many getdata requests this block gets
- {
- LOCK(wallet.cs_wallet);
- wallet.mapRequestCount[pblock->GetHash()] = 0;
- }
+ // Inform about the new block
+ GetMainSignals().BlockFound(pblock->GetHash());
// Process this block the same as if we had received it from another node
CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock))
+ if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
return error("BitcoinMiner: ProcessNewBlock, block not accepted");
return true;
}
-void static BitcoinMiner(CWallet *pwallet)
+void static BitcoinMiner(const CChainParams& chainparams)
{
LogPrintf("BitcoinMiner started\n");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("bitcoin-miner");
- const CChainParams& chainparams = Params();
- // Each thread has its own key and counter
- CReserveKey reservekey(pwallet);
unsigned int nExtraNonce = 0;
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
try {
+ // Throw an error if no script was provided. This can happen
+ // due to some internal error but also if the keypool is empty.
+ // In the latter case, already the pointer is NULL.
+ if (!coinbaseScript || coinbaseScript->reserveScript.empty())
+ throw std::runtime_error("No coinbase script available (mining requires a wallet)");
+
while (true) {
if (chainparams.MiningRequiresPeers()) {
// Busy-wait for the network to come online so we don't waste time mining
@@ -471,7 +472,7 @@ void static BitcoinMiner(CWallet *pwallet)
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip();
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
{
LogPrintf("Error in BitcoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
@@ -503,8 +504,9 @@ void static BitcoinMiner(CWallet *pwallet)
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("BitcoinMiner:\n");
LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", hash.GetHex(), hashTarget.GetHex());
- ProcessBlockFound(pblock, *pwallet, reservekey);
+ ProcessBlockFound(pblock, chainparams);
SetThreadPriority(THREAD_PRIORITY_LOWEST);
+ coinbaseScript->KeepScript();
// In regression test mode, stop mining after a block is found.
if (chainparams.MineBlocksOnDemand())
@@ -527,7 +529,9 @@ void static BitcoinMiner(CWallet *pwallet)
break;
// Update nTime every few seconds
- UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
+ if (UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev) < 0)
+ break; // Recreate the block if the clock has run backwards,
+ // so that we can use the correct time.
if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks)
{
// Changing pblock->nTime can change work required on testnet:
@@ -548,17 +552,12 @@ void static BitcoinMiner(CWallet *pwallet)
}
}
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
+void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams)
{
static boost::thread_group* minerThreads = NULL;
- if (nThreads < 0) {
- // In regtest threads defaults to 1
- if (Params().DefaultMinerThreads())
- nThreads = Params().DefaultMinerThreads();
- else
- nThreads = boost::thread::hardware_concurrency();
- }
+ if (nThreads < 0)
+ nThreads = GetNumCores();
if (minerThreads != NULL)
{
@@ -572,7 +571,5 @@ void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads)
minerThreads = new boost::thread_group();
for (int i = 0; i < nThreads; i++)
- minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet));
+ minerThreads->create_thread(boost::bind(&BitcoinMiner, boost::cref(chainparams)));
}
-
-#endif // ENABLE_WALLET
diff --git a/src/miner.h b/src/miner.h
index 96a6b70ecd..7e0e58d540 100644
--- a/src/miner.h
+++ b/src/miner.h
@@ -11,6 +11,7 @@
#include <stdint.h>
class CBlockIndex;
+class CChainParams;
class CReserveKey;
class CScript;
class CWallet;
@@ -24,12 +25,11 @@ struct CBlockTemplate
};
/** Run the miner threads */
-void GenerateBitcoins(bool fGenerate, CWallet* pwallet, int nThreads);
+void GenerateBitcoins(bool fGenerate, int nThreads, const CChainParams& chainparams);
/** Generate a new block, without valid proof-of-work */
CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn);
-CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey);
/** Modify the extranonce in a block */
-void IncrementExtraNonce(CBlock* pblock, CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
-void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
+void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
+int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
#endif // BITCOIN_MINER_H
diff --git a/src/net.cpp b/src/net.cpp
index 2de04fc574..87c4f0af0a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -12,9 +12,12 @@
#include "addrman.h"
#include "chainparams.h"
#include "clientversion.h"
+#include "crypto/common.h"
+#include "hash.h"
#include "primitives/transaction.h"
+#include "scheduler.h"
#include "ui_interface.h"
-#include "crypto/common.h"
+#include "utilstrencodings.h"
#ifdef WIN32
#include <string.h>
@@ -77,8 +80,9 @@ static CNode* pnodeLocalHost = NULL;
uint64_t nLocalHostNonce = 0;
static std::vector<ListenSocket> vhListenSocket;
CAddrMan addrman;
-int nMaxConnections = 125;
+int nMaxConnections = DEFAULT_MAX_PEER_CONNECTIONS;
bool fAddressesInitialized = false;
+std::string strSubVersion;
vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
@@ -106,7 +110,7 @@ boost::condition_variable messageHandlerCondition;
static CNodeSignals g_signals;
CNodeSignals& GetNodeSignals() { return g_signals; }
-void AddOneShot(string strDest)
+void AddOneShot(const std::string& strDest)
{
LOCK(cs_vOneShots);
vOneShots.push_back(strDest);
@@ -331,6 +335,15 @@ CNode* FindNode(const CNetAddr& ip)
return NULL;
}
+CNode* FindNode(const CSubNet& subNet)
+{
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (subNet.Match((CNetAddr)pnode->addr))
+ return (pnode);
+ return NULL;
+}
+
CNode* FindNode(const std::string& addrName)
{
LOCK(cs_vNodes);
@@ -375,6 +388,12 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
if (pszDest ? ConnectSocketByName(addrConnect, hSocket, pszDest, Params().GetDefaultPort(), nConnectTimeout, &proxyConnectionFailed) :
ConnectSocket(addrConnect, hSocket, nConnectTimeout, &proxyConnectionFailed))
{
+ if (!IsSelectableSocket(hSocket)) {
+ LogPrintf("Cannot create connection: non-selectable socket created (fd >= FD_SETSIZE ?)\n");
+ CloseSocket(hSocket);
+ return NULL;
+ }
+
addrman.Attempt(addrConnect);
// Add node
@@ -426,19 +445,22 @@ void CNode::PushVersion()
else
LogPrint("net", "send version message: version %d, blocks=%d, us=%s, peer=%d\n", PROTOCOL_VERSION, nBestHeight, addrMe.ToString(), id);
PushMessage("version", PROTOCOL_VERSION, nLocalServices, nTime, addrYou, addrMe,
- nLocalHostNonce, FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>()), nBestHeight, true);
+ nLocalHostNonce, strSubVersion, nBestHeight, true);
}
-std::map<CNetAddr, int64_t> CNode::setBanned;
+banmap_t CNode::setBanned;
CCriticalSection CNode::cs_setBanned;
+bool CNode::setBannedIsDirty;
void CNode::ClearBanned()
{
+ LOCK(cs_setBanned);
setBanned.clear();
+ setBannedIsDirty = true;
}
bool CNode::IsBanned(CNetAddr ip)
@@ -446,25 +468,114 @@ bool CNode::IsBanned(CNetAddr ip)
bool fResult = false;
{
LOCK(cs_setBanned);
- std::map<CNetAddr, int64_t>::iterator i = setBanned.find(ip);
- if (i != setBanned.end())
+ for (banmap_t::iterator it = setBanned.begin(); it != setBanned.end(); it++)
{
- int64_t t = (*i).second;
- if (GetTime() < t)
+ CSubNet subNet = (*it).first;
+ CBanEntry banEntry = (*it).second;
+
+ if(subNet.Match(ip) && GetTime() < banEntry.nBanUntil)
fResult = true;
}
}
return fResult;
}
-bool CNode::Ban(const CNetAddr &addr) {
- int64_t banTime = GetTime()+GetArg("-bantime", 60*60*24); // Default 24-hour ban
+bool CNode::IsBanned(CSubNet subnet)
+{
+ bool fResult = false;
{
LOCK(cs_setBanned);
- if (setBanned[addr] < banTime)
- setBanned[addr] = banTime;
+ banmap_t::iterator i = setBanned.find(subnet);
+ if (i != setBanned.end())
+ {
+ CBanEntry banEntry = (*i).second;
+ if (GetTime() < banEntry.nBanUntil)
+ fResult = true;
+ }
}
- return true;
+ return fResult;
+}
+
+void CNode::Ban(const CNetAddr& addr, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+ CSubNet subNet(addr);
+ Ban(subNet, banReason, bantimeoffset, sinceUnixEpoch);
+}
+
+void CNode::Ban(const CSubNet& subNet, const BanReason &banReason, int64_t bantimeoffset, bool sinceUnixEpoch) {
+ CBanEntry banEntry(GetTime());
+ banEntry.banReason = banReason;
+ if (bantimeoffset <= 0)
+ {
+ bantimeoffset = GetArg("-bantime", 60*60*24); // Default 24-hour ban
+ sinceUnixEpoch = false;
+ }
+ banEntry.nBanUntil = (sinceUnixEpoch ? 0 : GetTime() )+bantimeoffset;
+
+
+ LOCK(cs_setBanned);
+ if (setBanned[subNet].nBanUntil < banEntry.nBanUntil)
+ setBanned[subNet] = banEntry;
+
+ setBannedIsDirty = true;
+}
+
+bool CNode::Unban(const CNetAddr &addr) {
+ CSubNet subNet(addr);
+ return Unban(subNet);
+}
+
+bool CNode::Unban(const CSubNet &subNet) {
+ LOCK(cs_setBanned);
+ if (setBanned.erase(subNet))
+ {
+ setBannedIsDirty = true;
+ return true;
+ }
+ return false;
+}
+
+void CNode::GetBanned(banmap_t &banMap)
+{
+ LOCK(cs_setBanned);
+ banMap = setBanned; //create a thread safe copy
+}
+
+void CNode::SetBanned(const banmap_t &banMap)
+{
+ LOCK(cs_setBanned);
+ setBanned = banMap;
+ setBannedIsDirty = true;
+}
+
+void CNode::SweepBanned()
+{
+ int64_t now = GetTime();
+
+ LOCK(cs_setBanned);
+ banmap_t::iterator it = setBanned.begin();
+ while(it != setBanned.end())
+ {
+ CBanEntry banEntry = (*it).second;
+ if(now > banEntry.nBanUntil)
+ {
+ setBanned.erase(it++);
+ setBannedIsDirty = true;
+ }
+ else
+ ++it;
+ }
+}
+
+bool CNode::BannedSetIsDirty()
+{
+ LOCK(cs_setBanned);
+ return setBannedIsDirty;
+}
+
+void CNode::SetBannedSetDirty(bool dirty)
+{
+ LOCK(cs_setBanned); //reuse setBanned lock for the isDirty flag
+ setBannedIsDirty = dirty;
}
@@ -517,6 +628,7 @@ void CNode::copyStats(CNodeStats &stats)
// Raw ping time is in microseconds, but show it to user as whole seconds (Bitcoin users should be well used to small numbers with many decimal places by now :)
stats.dPingTime = (((double)nPingUsecTime) / 1e6);
+ stats.dPingMin = (((double)nMinPingUsecTime) / 1e6);
stats.dPingWait = (((double)nPingUsecWait) / 1e6);
// Leave string empty if addrLocal invalid (not filled in yet)
@@ -547,7 +659,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes)
return false;
if (msg.in_data && msg.hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
- LogPrint("net", "Oversized message from peer=%i, disconnecting", GetId());
+ LogPrint("net", "Oversized message from peer=%i, disconnecting\n", GetId());
return false;
}
@@ -664,6 +776,222 @@ void SocketSendData(CNode *pnode)
static list<CNode*> vNodesDisconnected;
+class CNodeRef {
+public:
+ CNodeRef(CNode *pnode) : _pnode(pnode) {
+ LOCK(cs_vNodes);
+ _pnode->AddRef();
+ }
+
+ ~CNodeRef() {
+ LOCK(cs_vNodes);
+ _pnode->Release();
+ }
+
+ CNode& operator *() const {return *_pnode;};
+ CNode* operator ->() const {return _pnode;};
+
+ CNodeRef& operator =(const CNodeRef& other)
+ {
+ if (this != &other) {
+ LOCK(cs_vNodes);
+
+ _pnode->Release();
+ _pnode = other._pnode;
+ _pnode->AddRef();
+ }
+ return *this;
+ }
+
+ CNodeRef(const CNodeRef& other):
+ _pnode(other._pnode)
+ {
+ LOCK(cs_vNodes);
+ _pnode->AddRef();
+ }
+private:
+ CNode *_pnode;
+};
+
+static bool ReverseCompareNodeMinPingTime(const CNodeRef &a, const CNodeRef &b)
+{
+ return a->nMinPingUsecTime > b->nMinPingUsecTime;
+}
+
+static bool ReverseCompareNodeTimeConnected(const CNodeRef &a, const CNodeRef &b)
+{
+ return a->nTimeConnected > b->nTimeConnected;
+}
+
+class CompareNetGroupKeyed
+{
+ std::vector<unsigned char> vchSecretKey;
+public:
+ CompareNetGroupKeyed()
+ {
+ vchSecretKey.resize(32, 0);
+ GetRandBytes(vchSecretKey.data(), vchSecretKey.size());
+ }
+
+ bool operator()(const CNodeRef &a, const CNodeRef &b)
+ {
+ std::vector<unsigned char> vchGroupA, vchGroupB;
+ CSHA256 hashA, hashB;
+ std::vector<unsigned char> vchA(32), vchB(32);
+
+ vchGroupA = a->addr.GetGroup();
+ vchGroupB = b->addr.GetGroup();
+
+ hashA.Write(begin_ptr(vchGroupA), vchGroupA.size());
+ hashB.Write(begin_ptr(vchGroupB), vchGroupB.size());
+
+ hashA.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
+ hashB.Write(begin_ptr(vchSecretKey), vchSecretKey.size());
+
+ hashA.Finalize(begin_ptr(vchA));
+ hashB.Finalize(begin_ptr(vchB));
+
+ return vchA < vchB;
+ }
+};
+
+static bool AttemptToEvictConnection(bool fPreferNewConnection) {
+ std::vector<CNodeRef> vEvictionCandidates;
+ {
+ LOCK(cs_vNodes);
+
+ BOOST_FOREACH(CNode *node, vNodes) {
+ if (node->fWhitelisted)
+ continue;
+ if (!node->fInbound)
+ continue;
+ if (node->fDisconnect)
+ continue;
+ if (node->addr.IsLocal())
+ continue;
+ vEvictionCandidates.push_back(CNodeRef(node));
+ }
+ }
+
+ if (vEvictionCandidates.empty()) return false;
+
+ // Protect connections with certain characteristics
+
+ // Deterministically select 4 peers to protect by netgroup.
+ // An attacker cannot predict which netgroups will be protected.
+ static CompareNetGroupKeyed comparerNetGroupKeyed;
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), comparerNetGroupKeyed);
+ vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(4, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
+
+ if (vEvictionCandidates.empty()) return false;
+
+ // Protect the 8 nodes with the best ping times.
+ // An attacker cannot manipulate this metric without physically moving nodes closer to the target.
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeMinPingTime);
+ vEvictionCandidates.erase(vEvictionCandidates.end() - std::min(8, static_cast<int>(vEvictionCandidates.size())), vEvictionCandidates.end());
+
+ if (vEvictionCandidates.empty()) return false;
+
+ // Protect the half of the remaining nodes which have been connected the longest.
+ // This replicates the existing implicit behavior.
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
+ vEvictionCandidates.erase(vEvictionCandidates.end() - static_cast<int>(vEvictionCandidates.size() / 2), vEvictionCandidates.end());
+
+ if (vEvictionCandidates.empty()) return false;
+
+ // Identify the network group with the most connections
+ std::vector<unsigned char> naMostConnections;
+ unsigned int nMostConnections = 0;
+ std::map<std::vector<unsigned char>, std::vector<CNodeRef> > mapAddrCounts;
+ BOOST_FOREACH(const CNodeRef &node, vEvictionCandidates) {
+ mapAddrCounts[node->addr.GetGroup()].push_back(node);
+
+ if (mapAddrCounts[node->addr.GetGroup()].size() > nMostConnections) {
+ nMostConnections = mapAddrCounts[node->addr.GetGroup()].size();
+ naMostConnections = node->addr.GetGroup();
+ }
+ }
+
+ // Reduce to the network group with the most connections
+ vEvictionCandidates = mapAddrCounts[naMostConnections];
+
+ // Do not disconnect peers if there is only 1 connection from their network group
+ if (vEvictionCandidates.size() <= 1)
+ // unless we prefer the new connection (for whitelisted peers)
+ if (!fPreferNewConnection)
+ return false;
+
+ // Disconnect the most recent connection from the network group with the most connections
+ std::sort(vEvictionCandidates.begin(), vEvictionCandidates.end(), ReverseCompareNodeTimeConnected);
+ vEvictionCandidates[0]->fDisconnect = true;
+
+ return true;
+}
+
+static void AcceptConnection(const ListenSocket& hListenSocket) {
+ struct sockaddr_storage sockaddr;
+ socklen_t len = sizeof(sockaddr);
+ SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
+ CAddress addr;
+ int nInbound = 0;
+ int nMaxInbound = nMaxConnections - MAX_OUTBOUND_CONNECTIONS;
+
+ if (hSocket != INVALID_SOCKET)
+ if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
+ LogPrintf("Warning: Unknown socket family\n");
+
+ bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
+ {
+ LOCK(cs_vNodes);
+ BOOST_FOREACH(CNode* pnode, vNodes)
+ if (pnode->fInbound)
+ nInbound++;
+ }
+
+ if (hSocket == INVALID_SOCKET)
+ {
+ int nErr = WSAGetLastError();
+ if (nErr != WSAEWOULDBLOCK)
+ LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
+ return;
+ }
+
+ if (!IsSelectableSocket(hSocket))
+ {
+ LogPrintf("connection from %s dropped: non-selectable socket\n", addr.ToString());
+ CloseSocket(hSocket);
+ return;
+ }
+
+ if (CNode::IsBanned(addr) && !whitelisted)
+ {
+ LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
+ CloseSocket(hSocket);
+ return;
+ }
+
+ if (nInbound >= nMaxInbound)
+ {
+ if (!AttemptToEvictConnection(whitelisted)) {
+ // No connection to evict, disconnect the new connection
+ LogPrint("net", "failed to find an eviction candidate - connection dropped (full)\n");
+ CloseSocket(hSocket);
+ return;
+ }
+ }
+
+ CNode* pnode = new CNode(hSocket, addr, "", true);
+ pnode->AddRef();
+ pnode->fWhitelisted = whitelisted;
+
+ LogPrint("net", "connection from %s accepted\n", addr.ToString());
+
+ {
+ LOCK(cs_vNodes);
+ vNodes.push_back(pnode);
+ }
+}
+
void ThreadSocketHandler()
{
unsigned int nPrevNodeCount = 0;
@@ -821,50 +1149,7 @@ void ThreadSocketHandler()
{
if (hListenSocket.socket != INVALID_SOCKET && FD_ISSET(hListenSocket.socket, &fdsetRecv))
{
- struct sockaddr_storage sockaddr;
- socklen_t len = sizeof(sockaddr);
- SOCKET hSocket = accept(hListenSocket.socket, (struct sockaddr*)&sockaddr, &len);
- CAddress addr;
- int nInbound = 0;
-
- if (hSocket != INVALID_SOCKET)
- if (!addr.SetSockAddr((const struct sockaddr*)&sockaddr))
- LogPrintf("Warning: Unknown socket family\n");
-
- bool whitelisted = hListenSocket.whitelisted || CNode::IsWhitelistedRange(addr);
- {
- LOCK(cs_vNodes);
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (pnode->fInbound)
- nInbound++;
- }
-
- if (hSocket == INVALID_SOCKET)
- {
- int nErr = WSAGetLastError();
- if (nErr != WSAEWOULDBLOCK)
- LogPrintf("socket error accept failed: %s\n", NetworkErrorString(nErr));
- }
- else if (nInbound >= nMaxConnections - MAX_OUTBOUND_CONNECTIONS)
- {
- CloseSocket(hSocket);
- }
- else if (CNode::IsBanned(addr) && !whitelisted)
- {
- LogPrintf("connection from %s dropped (banned)\n", addr.ToString());
- CloseSocket(hSocket);
- }
- else
- {
- CNode* pnode = new CNode(hSocket, addr, "", true);
- pnode->AddRef();
- pnode->fWhitelisted = whitelisted;
-
- {
- LOCK(cs_vNodes);
- vNodes.push_back(pnode);
- }
- }
+ AcceptConnection(hListenSocket);
}
}
@@ -994,10 +1279,14 @@ void ThreadMapPort()
#ifndef UPNPDISCOVER_SUCCESS
/* miniupnpc 1.5 */
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0);
-#else
+#elif MINIUPNPC_API_VERSION < 14
/* miniupnpc 1.6 */
int error = 0;
devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error);
+#else
+ /* miniupnpc 1.9.20150730 */
+ int error = 0;
+ devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error);
#endif
struct UPNPUrls urls;
@@ -1123,7 +1412,7 @@ void ThreadDNSAddressSeed()
vector<CAddress> vAdd;
if (LookupHost(seed.host.c_str(), vIPs))
{
- BOOST_FOREACH(CNetAddr& ip, vIPs)
+ BOOST_FOREACH(const CNetAddr& ip, vIPs)
{
int nOneDay = 24*3600;
CAddress addr = CAddress(CService(ip, Params().GetDefaultPort()));
@@ -1161,6 +1450,17 @@ void DumpAddresses()
addrman.size(), GetTimeMillis() - nStart);
}
+void DumpData()
+{
+ DumpAddresses();
+
+ if (CNode::BannedSetIsDirty())
+ {
+ DumpBanlist();
+ CNode::SetBannedSetDirty(false);
+ }
+}
+
void static ProcessOneShot()
{
string strDest;
@@ -1187,7 +1487,7 @@ void ThreadOpenConnections()
for (int64_t nLoop = 0;; nLoop++)
{
ProcessOneShot();
- BOOST_FOREACH(string strAddr, mapMultiArgs["-connect"])
+ BOOST_FOREACH(const std::string& strAddr, mapMultiArgs["-connect"])
{
CAddress addr;
OpenNetworkConnection(addr, NULL, strAddr.c_str());
@@ -1290,10 +1590,10 @@ void ThreadOpenAddedConnections()
list<string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
- BOOST_FOREACH(string& strAddNode, lAddresses) {
+ BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
CAddress addr;
CSemaphoreGrant grant(*semOutbound);
OpenNetworkConnection(addr, &grant, strAddNode.c_str());
@@ -1308,20 +1608,19 @@ void ThreadOpenAddedConnections()
list<string> lAddresses(0);
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
lAddresses.push_back(strAddNode);
}
list<vector<CService> > lservAddressesToAdd(0);
- BOOST_FOREACH(string& strAddNode, lAddresses)
- {
+ BOOST_FOREACH(const std::string& strAddNode, lAddresses) {
vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
{
lservAddressesToAdd.push_back(vservNode);
{
LOCK(cs_setservAddNodeAddresses);
- BOOST_FOREACH(CService& serv, vservNode)
+ BOOST_FOREACH(const CService& serv, vservNode)
setservAddNodeAddresses.insert(serv);
}
}
@@ -1332,7 +1631,7 @@ void ThreadOpenAddedConnections()
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
for (list<vector<CService> >::iterator it = lservAddressesToAdd.begin(); it != lservAddressesToAdd.end(); it++)
- BOOST_FOREACH(CService& addrNode, *(it))
+ BOOST_FOREACH(const CService& addrNode, *(it))
if (pnode->addr == addrNode)
{
it = lservAddressesToAdd.erase(it);
@@ -1362,7 +1661,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
FindNode((CNetAddr)addrConnect) || CNode::IsBanned(addrConnect) ||
FindNode(addrConnect.ToStringIPPort()))
return false;
- } else if (FindNode(pszDest))
+ } else if (FindNode(std::string(pszDest)))
return false;
CNode* pnode = ConnectNode(addrConnect, pszDest);
@@ -1384,7 +1683,7 @@ void ThreadMessageHandler()
{
boost::mutex condition_mutex;
boost::unique_lock<boost::mutex> lock(condition_mutex);
-
+
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true)
{
@@ -1475,6 +1774,13 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
LogPrintf("%s\n", strError);
return false;
}
+ if (!IsSelectableSocket(hListenSocket))
+ {
+ strError = "Error: Couldn't create a listenable socket for incoming connections";
+ LogPrintf("%s\n", strError);
+ return false;
+ }
+
#ifndef WIN32
#ifdef SO_NOSIGPIPE
@@ -1482,8 +1788,10 @@ bool BindListenPort(const CService &addrBind, string& strError, bool fWhiteliste
setsockopt(hListenSocket, SOL_SOCKET, SO_NOSIGPIPE, (void*)&nOne, sizeof(int));
#endif
// Allow binding if the port is still in TIME_WAIT state after
- // the program was closed and restarted. Not an issue on windows!
+ // the program was closed and restarted.
setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&nOne, sizeof(int));
+#else
+ setsockopt(hListenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&nOne, sizeof(int));
#endif
// Set to non-blocking, incoming connections will also inherit this
@@ -1590,7 +1898,7 @@ void static Discover(boost::thread_group& threadGroup)
#endif
}
-void StartNode(boost::thread_group& threadGroup)
+void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler)
{
uiInterface.InitMessage(_("Loading addresses..."));
// Load addresses for peers.dat
@@ -1600,6 +1908,17 @@ void StartNode(boost::thread_group& threadGroup)
if (!adb.Read(addrman))
LogPrintf("Invalid or missing peers.dat; recreating\n");
}
+
+ //try to read stored banlist
+ CBanDB bandb;
+ banmap_t banmap;
+ if (!bandb.Read(banmap))
+ LogPrintf("Invalid or missing banlist.dat; recreating\n");
+
+ CNode::SetBanned(banmap); //thread save setter
+ CNode::SetBannedSetDirty(false); //no need to write down just read or nonexistent data
+ CNode::SweepBanned(); //sweap out unused entries
+
LogPrintf("Loaded %i addresses from peers.dat %dms\n",
addrman.size(), GetTimeMillis() - nStart);
fAddressesInitialized = true;
@@ -1640,7 +1959,7 @@ void StartNode(boost::thread_group& threadGroup)
threadGroup.create_thread(boost::bind(&TraceThread<void (*)()>, "msghand", &ThreadMessageHandler));
// Dump network addresses
- threadGroup.create_thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, DUMP_ADDRESSES_INTERVAL * 1000));
+ scheduler.scheduleEvery(&DumpData, DUMP_ADDRESSES_INTERVAL);
}
bool StopNode()
@@ -1653,7 +1972,7 @@ bool StopNode()
if (fAddressesInitialized)
{
- DumpAddresses();
+ DumpData();
fAddressesInitialized = false;
}
@@ -1857,11 +2176,11 @@ bool CAddrDB::Read(CAddrMan& addr)
return error("%s: Failed to open file %s", __func__, pathAddr.string());
// use file size to size memory buffer
- int fileSize = boost::filesystem::file_size(pathAddr);
- int dataSize = fileSize - sizeof(uint256);
+ uint64_t fileSize = boost::filesystem::file_size(pathAddr);
+ uint64_t dataSize = 0;
// Don't try to resize to a negative number if file is small
- if (dataSize < 0)
- dataSize = 0;
+ if (fileSize >= sizeof(uint256))
+ dataSize = fileSize - sizeof(uint256);
vector<unsigned char> vchData;
vchData.resize(dataSize);
uint256 hashIn;
@@ -1905,9 +2224,9 @@ bool CAddrDB::Read(CAddrMan& addr)
unsigned int ReceiveFloodSize() { return 1000*GetArg("-maxreceivebuffer", 5*1000); }
unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 1*1000); }
-CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fInboundIn) :
+CNode::CNode(SOCKET hSocketIn, const CAddress& addrIn, const std::string& addrNameIn, bool fInboundIn) :
ssSend(SER_NETWORK, INIT_PROTO_VERSION),
- addrKnown(5000, 0.001, insecure_rand()),
+ addrKnown(5000, 0.001),
setInventoryKnown(SendBufferSize() / 1000)
{
nServices = 0;
@@ -1942,6 +2261,7 @@ CNode::CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn, bool fIn
nPingUsecStart = 0;
nPingUsecTime = 0;
fPingQueued = false;
+ nMinPingUsecTime = std::numeric_limits<int64_t>::max();
{
LOCK(cs_nLastNodeId);
@@ -2032,8 +2352,10 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
Fuzz(GetArg("-fuzzmessagestest", 10));
if (ssSend.size() == 0)
+ {
+ LEAVE_CRITICAL_SECTION(cs_vSend);
return;
-
+ }
// Set the size
unsigned int nSize = ssSend.size() - CMessageHeader::HEADER_SIZE;
WriteLE32((uint8_t*)&ssSend[CMessageHeader::MESSAGE_SIZE_OFFSET], nSize);
@@ -2057,3 +2379,119 @@ void CNode::EndMessage() UNLOCK_FUNCTION(cs_vSend)
LEAVE_CRITICAL_SECTION(cs_vSend);
}
+
+//
+// CBanDB
+//
+
+CBanDB::CBanDB()
+{
+ pathBanlist = GetDataDir() / "banlist.dat";
+}
+
+bool CBanDB::Write(const banmap_t& banSet)
+{
+ // Generate random temporary filename
+ unsigned short randv = 0;
+ GetRandBytes((unsigned char*)&randv, sizeof(randv));
+ std::string tmpfn = strprintf("banlist.dat.%04x", randv);
+
+ // serialize banlist, checksum data up to that point, then append csum
+ CDataStream ssBanlist(SER_DISK, CLIENT_VERSION);
+ ssBanlist << FLATDATA(Params().MessageStart());
+ ssBanlist << banSet;
+ uint256 hash = Hash(ssBanlist.begin(), ssBanlist.end());
+ ssBanlist << hash;
+
+ // open temp output file, and associate with CAutoFile
+ boost::filesystem::path pathTmp = GetDataDir() / tmpfn;
+ FILE *file = fopen(pathTmp.string().c_str(), "wb");
+ CAutoFile fileout(file, SER_DISK, CLIENT_VERSION);
+ if (fileout.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathTmp.string());
+
+ // Write and commit header, data
+ try {
+ fileout << ssBanlist;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Serialize or I/O error - %s", __func__, e.what());
+ }
+ FileCommit(fileout.Get());
+ fileout.fclose();
+
+ // replace existing banlist.dat, if any, with new banlist.dat.XXXX
+ if (!RenameOver(pathTmp, pathBanlist))
+ return error("%s: Rename-into-place failed", __func__);
+
+ return true;
+}
+
+bool CBanDB::Read(banmap_t& banSet)
+{
+ // open input file, and associate with CAutoFile
+ FILE *file = fopen(pathBanlist.string().c_str(), "rb");
+ CAutoFile filein(file, SER_DISK, CLIENT_VERSION);
+ if (filein.IsNull())
+ return error("%s: Failed to open file %s", __func__, pathBanlist.string());
+
+ // use file size to size memory buffer
+ uint64_t fileSize = boost::filesystem::file_size(pathBanlist);
+ uint64_t dataSize = 0;
+ // Don't try to resize to a negative number if file is small
+ if (fileSize >= sizeof(uint256))
+ dataSize = fileSize - sizeof(uint256);
+ vector<unsigned char> vchData;
+ vchData.resize(dataSize);
+ uint256 hashIn;
+
+ // read data and checksum from file
+ try {
+ filein.read((char *)&vchData[0], dataSize);
+ filein >> hashIn;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+ filein.fclose();
+
+ CDataStream ssBanlist(vchData, SER_DISK, CLIENT_VERSION);
+
+ // verify stored checksum matches input data
+ uint256 hashTmp = Hash(ssBanlist.begin(), ssBanlist.end());
+ if (hashIn != hashTmp)
+ return error("%s: Checksum mismatch, data corrupted", __func__);
+
+ unsigned char pchMsgTmp[4];
+ try {
+ // de-serialize file header (network specific magic number) and ..
+ ssBanlist >> FLATDATA(pchMsgTmp);
+
+ // ... verify the network matches ours
+ if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
+ return error("%s: Invalid network magic number", __func__);
+
+ // de-serialize address data into one CAddrMan object
+ ssBanlist >> banSet;
+ }
+ catch (const std::exception& e) {
+ return error("%s: Deserialize or I/O error - %s", __func__, e.what());
+ }
+
+ return true;
+}
+
+void DumpBanlist()
+{
+ int64_t nStart = GetTimeMillis();
+
+ CNode::SweepBanned(); //clean unused entries (if bantime has expired)
+
+ CBanDB bandb;
+ banmap_t banmap;
+ CNode::GetBanned(banmap);
+ bandb.Write(banmap);
+
+ LogPrint("net", "Flushed %d banned node ips/subnets to banlist.dat %dms\n",
+ banmap.size(), GetTimeMillis() - nStart);
+}
diff --git a/src/net.h b/src/net.h
index 7c61a2be6c..6842ee5edc 100644
--- a/src/net.h
+++ b/src/net.h
@@ -8,7 +8,6 @@
#include "bloom.h"
#include "compat.h"
-#include "hash.h"
#include "limitedmap.h"
#include "mruset.h"
#include "netbase.h"
@@ -17,7 +16,6 @@
#include "streams.h"
#include "sync.h"
#include "uint256.h"
-#include "utilstrencodings.h"
#include <deque>
#include <stdint.h>
@@ -31,7 +29,7 @@
#include <boost/signals2/signal.hpp>
class CAddrMan;
-class CBlockIndex;
+class CScheduler;
class CNode;
namespace boost {
@@ -48,6 +46,8 @@ static const unsigned int MAX_INV_SZ = 50000;
static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 2 * 1024 * 1024;
+/** Maximum length of strSubVer in `version` message */
+static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** -listen default */
static const bool DEFAULT_LISTEN = true;
/** -upnp default */
@@ -58,13 +58,16 @@ 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 peer connections to maintain. */
+static const unsigned int DEFAULT_MAX_PEER_CONNECTIONS = 125;
unsigned int ReceiveFloodSize();
unsigned int SendBufferSize();
-void AddOneShot(std::string strDest);
+void AddOneShot(const std::string& strDest);
void AddressCurrentlyConnected(const CService& addr);
CNode* FindNode(const CNetAddr& ip);
+CNode* FindNode(const CSubNet& subNet);
CNode* FindNode(const std::string& addrName);
CNode* FindNode(const CService& ip);
CNode* ConnectNode(CAddress addrConnect, const char *pszDest = NULL);
@@ -72,7 +75,7 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
void MapPort(bool fUseUPnP);
unsigned short GetListenPort();
bool BindListenPort(const CService &bindAddr, std::string& strError, bool fWhitelisted = false);
-void StartNode(boost::thread_group& threadGroup);
+void StartNode(boost::thread_group& threadGroup, CScheduler& scheduler);
bool StopNode();
void SocketSendData(CNode *pnode);
@@ -139,6 +142,8 @@ extern bool fListen;
extern uint64_t nLocalServices;
extern uint64_t nLocalHostNonce;
extern CAddrMan addrman;
+
+/** Maximum number of connections to simultaneously allow (aka connection slots) */
extern int nMaxConnections;
extern std::vector<CNode*> vNodes;
@@ -154,6 +159,9 @@ extern CCriticalSection cs_vAddedNodes;
extern NodeId nLastNodeId;
extern CCriticalSection cs_nLastNodeId;
+/** Subversion as sent to the P2P network in `version` messages */
+extern std::string strSubVersion;
+
struct LocalServiceInfo {
int nScore;
int nPort;
@@ -181,6 +189,7 @@ public:
bool fWhitelisted;
double dPingTime;
double dPingWait;
+ double dPingMin;
std::string addrLocal;
};
@@ -226,8 +235,66 @@ public:
};
+typedef enum BanReason
+{
+ BanReasonUnknown = 0,
+ BanReasonNodeMisbehaving = 1,
+ BanReasonManuallyAdded = 2
+} BanReason;
+
+class CBanEntry
+{
+public:
+ static const int CURRENT_VERSION=1;
+ int nVersion;
+ int64_t nCreateTime;
+ int64_t nBanUntil;
+ uint8_t banReason;
+
+ CBanEntry()
+ {
+ SetNull();
+ }
+
+ CBanEntry(int64_t nCreateTimeIn)
+ {
+ SetNull();
+ nCreateTime = nCreateTimeIn;
+ }
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(this->nVersion);
+ nVersion = this->nVersion;
+ READWRITE(nCreateTime);
+ READWRITE(nBanUntil);
+ READWRITE(banReason);
+ }
+
+ void SetNull()
+ {
+ nVersion = CBanEntry::CURRENT_VERSION;
+ nCreateTime = 0;
+ nBanUntil = 0;
+ banReason = BanReasonUnknown;
+ }
+ std::string banReasonToString()
+ {
+ switch (banReason) {
+ case BanReasonNodeMisbehaving:
+ return "node misbehabing";
+ case BanReasonManuallyAdded:
+ return "manually added";
+ default:
+ return "unknown";
+ }
+ }
+};
+typedef std::map<CSubNet, CBanEntry> banmap_t;
/** Information about a peer */
class CNode
@@ -283,8 +350,9 @@ protected:
// Denial-of-service detection/prevention
// Key is IP address, value is banned-until-time
- static std::map<CNetAddr, int64_t> setBanned;
+ static banmap_t setBanned;
static CCriticalSection cs_setBanned;
+ static bool setBannedIsDirty;
// Whitelisted ranges. Any node connecting from these is automatically
// whitelisted (as well as those connecting to whitelisted binds).
@@ -317,10 +385,12 @@ public:
int64_t nPingUsecStart;
// Last measured round-trip time.
int64_t nPingUsecTime;
+ // Best measured round-trip time.
+ int64_t nMinPingUsecTime;
// Whether a ping is requested.
bool fPingQueued;
- CNode(SOCKET hSocketIn, CAddress addrIn, std::string addrNameIn = "", bool fInboundIn=false);
+ CNode(SOCKET hSocketIn, const CAddress &addrIn, const std::string &addrNameIn = "", bool fInboundIn = false);
~CNode();
private:
@@ -605,7 +675,21 @@ public:
// new code.
static void ClearBanned(); // needed for unit testing
static bool IsBanned(CNetAddr ip);
- static bool Ban(const CNetAddr &ip);
+ static bool IsBanned(CSubNet subnet);
+ static void Ban(const CNetAddr &ip, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static void Ban(const CSubNet &subNet, const BanReason &banReason, int64_t bantimeoffset = 0, bool sinceUnixEpoch = false);
+ static bool Unban(const CNetAddr &ip);
+ static bool Unban(const CSubNet &ip);
+ static void GetBanned(banmap_t &banmap);
+ static void SetBanned(const banmap_t &banmap);
+
+ //!check is the banlist has unwritten changes
+ static bool BannedSetIsDirty();
+ //!set the "dirty" flag for the banlist
+ static void SetBannedSetDirty(bool dirty=true);
+ //!clean unused entries (if bantime has expired)
+ static void SweepBanned();
+
void copyStats(CNodeStats &stats);
static bool IsWhitelistedRange(const CNetAddr &ip);
@@ -636,4 +720,17 @@ public:
bool Read(CAddrMan& addr);
};
+/** Access to the banlist database (banlist.dat) */
+class CBanDB
+{
+private:
+ boost::filesystem::path pathBanlist;
+public:
+ CBanDB();
+ bool Write(const banmap_t& banSet);
+ bool Read(banmap_t& banSet);
+};
+
+void DumpBanlist();
+
#endif // BITCOIN_NET_H
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 2015d0271a..c3d56d9184 100644
--- a/src/netbase.cpp
+++ b/src/netbase.cpp
@@ -35,8 +35,6 @@
#define MSG_NOSIGNAL 0
#endif
-using namespace std;
-
// Settings
static proxyType proxyInfo[NET_MAX];
static proxyType nameProxy;
@@ -268,6 +266,9 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
} else { // Other error or blocking
int nErr = WSAGetLastError();
if (nErr == WSAEINPROGRESS || nErr == WSAEWOULDBLOCK || nErr == WSAEINVAL) {
+ if (!IsSelectableSocket(hSocket)) {
+ return false;
+ }
struct timeval tval = MillisToTimeval(std::min(endTime - curTime, maxWait));
fd_set fdset;
FD_ZERO(&fdset);
@@ -348,7 +349,7 @@ static bool Socks5(const std::string& strDest, int port, const ProxyCredentials
}
if (pchRetA[0] != 0x01 || pchRetA[1] != 0x00) {
CloseSocket(hSocket);
- return error("Proxy authentication unsuccesful");
+ return error("Proxy authentication unsuccessful");
}
} else if (pchRet1[1] == 0x00) {
// Perform no authentication
@@ -597,13 +598,13 @@ bool ConnectSocket(const CService &addrDest, SOCKET& hSocketRet, int nTimeout, b
bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
{
- string strDest;
+ std::string strDest;
int port = portDefault;
if (outProxyConnectionFailed)
*outProxyConnectionFailed = false;
- SplitHostPort(string(pszDest), port, strDest);
+ SplitHostPort(std::string(pszDest), port, strDest);
proxyType nameProxy;
GetNameProxy(nameProxy);
@@ -982,7 +983,7 @@ std::vector<unsigned char> CNetAddr::GetGroup() const
nBits -= 8;
}
if (nBits > 0)
- vchRet.push_back(GetByte(15 - nStartByte) | ((1 << nBits) - 1));
+ vchRet.push_back(GetByte(15 - nStartByte) | ((1 << (8 - nBits)) - 1));
return vchRet;
}
@@ -1252,15 +1253,15 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
std::string strNetmask = strSubnet.substr(slash + 1);
int32_t n;
// IPv4 addresses start at offset 12, and first 12 bytes must match, so just offset n
- int noffset = network.IsIPv4() ? (12 * 8) : 0;
+ const int astartofs = network.IsIPv4() ? 12 : 0;
if (ParseInt32(strNetmask, &n)) // If valid number, assume /24 symtex
{
- if(n >= 0 && n <= (128 - noffset)) // Only valid if in range of bits of address
+ if(n >= 0 && n <= (128 - astartofs*8)) // Only valid if in range of bits of address
{
- n += noffset;
+ n += astartofs*8;
// Clear bits [n..127]
for (; n < 128; ++n)
- netmask[n>>3] &= ~(1<<(n&7));
+ netmask[n>>3] &= ~(1<<(7-(n&7)));
}
else
{
@@ -1271,12 +1272,10 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
{
if (LookupHost(strNetmask.c_str(), vIP, 1, false)) // Never allow lookup for netmask
{
- // Remember: GetByte returns bytes in reversed order
// Copy only the *last* four bytes in case of IPv4, the rest of the mask should stay 1's as
// we don't want pchIPv4 to be part of the mask.
- int asize = network.IsIPv4() ? 4 : 16;
- for(int x=0; x<asize; ++x)
- netmask[15-x] = vIP[0].GetByte(x);
+ for(int x=astartofs; x<16; ++x)
+ netmask[x] = vIP[0].ip[x];
}
else
{
@@ -1289,6 +1288,17 @@ CSubNet::CSubNet(const std::string &strSubnet, bool fAllowLookup)
{
valid = false;
}
+
+ // Normalize network according to netmask
+ for(int x=0; x<16; ++x)
+ network.ip[x] &= netmask[x];
+}
+
+CSubNet::CSubNet(const CNetAddr &addr):
+ valid(addr.IsValid())
+{
+ memset(netmask, 255, sizeof(netmask));
+ network = addr;
}
bool CSubNet::Match(const CNetAddr &addr) const
@@ -1296,22 +1306,62 @@ bool CSubNet::Match(const CNetAddr &addr) const
if (!valid || !addr.IsValid())
return false;
for(int x=0; x<16; ++x)
- if ((addr.GetByte(x) & netmask[15-x]) != network.GetByte(x))
+ if ((addr.ip[x] & netmask[x]) != network.ip[x])
return false;
return true;
}
+static inline int NetmaskBits(uint8_t x)
+{
+ switch(x) {
+ case 0x00: return 0; break;
+ case 0x80: return 1; break;
+ case 0xc0: return 2; break;
+ case 0xe0: return 3; break;
+ case 0xf0: return 4; break;
+ case 0xf8: return 5; break;
+ case 0xfc: return 6; break;
+ case 0xfe: return 7; break;
+ case 0xff: return 8; break;
+ default: return -1; break;
+ }
+}
+
std::string CSubNet::ToString() const
{
+ /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
+ int cidr = 0;
+ bool valid_cidr = true;
+ int n = network.IsIPv4() ? 12 : 0;
+ for (; n < 16 && netmask[n] == 0xff; ++n)
+ cidr += 8;
+ if (n < 16) {
+ int bits = NetmaskBits(netmask[n]);
+ if (bits < 0)
+ valid_cidr = false;
+ else
+ cidr += bits;
+ ++n;
+ }
+ for (; n < 16 && valid_cidr; ++n)
+ if (netmask[n] != 0x00)
+ valid_cidr = false;
+
+ /* Format output */
std::string strNetmask;
- if (network.IsIPv4())
- strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
- else
- strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
- netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
- netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
- netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
- netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
+ if (valid_cidr) {
+ strNetmask = strprintf("%u", cidr);
+ } else {
+ if (network.IsIPv4())
+ strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
+ else
+ strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
+ netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
+ netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
+ netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
+ netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
+ }
+
return network.ToString() + "/" + strNetmask;
}
@@ -1330,6 +1380,11 @@ bool operator!=(const CSubNet& a, const CSubNet& b)
return !(a==b);
}
+bool operator<(const CSubNet& a, const CSubNet& b)
+{
+ return (a.network < b.network || (a.network == b.network && memcmp(a.netmask, b.netmask, 16) < 0));
+}
+
#ifdef WIN32
std::string NetworkErrorString(int err)
{
diff --git a/src/netbase.h b/src/netbase.h
index 6d2ca4afb2..6f8882b852 100644
--- a/src/netbase.h
+++ b/src/netbase.h
@@ -100,6 +100,8 @@ class CNetAddr
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(FLATDATA(ip));
}
+
+ friend class CSubNet;
};
class CSubNet
@@ -116,6 +118,9 @@ class CSubNet
CSubNet();
explicit CSubNet(const std::string &strSubnet, bool fAllowLookup = false);
+ //constructor for single ip subnet (<ipv4>/32 or <ipv6>/128)
+ explicit CSubNet(const CNetAddr &addr);
+
bool Match(const CNetAddr &addr) const;
std::string ToString() const;
@@ -123,6 +128,16 @@ class CSubNet
friend bool operator==(const CSubNet& a, const CSubNet& b);
friend bool operator!=(const CSubNet& a, const CSubNet& b);
+ friend bool operator<(const CSubNet& a, const CSubNet& b);
+
+ ADD_SERIALIZE_METHODS;
+
+ template <typename Stream, typename Operation>
+ inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
+ READWRITE(network);
+ READWRITE(FLATDATA(netmask));
+ READWRITE(FLATDATA(valid));
+ }
};
/** A combination of a network address (CNetAddr) and a (TCP) port */
diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp
new file mode 100644
index 0000000000..ffe31d1942
--- /dev/null
+++ b/src/policy/fees.cpp
@@ -0,0 +1,530 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "policy/fees.h"
+
+#include "amount.h"
+#include "primitives/transaction.h"
+#include "streams.h"
+#include "txmempool.h"
+#include "util.h"
+
+void TxConfirmStats::Initialize(std::vector<double>& defaultBuckets,
+ unsigned int maxConfirms, double _decay, std::string _dataTypeString)
+{
+ decay = _decay;
+ dataTypeString = _dataTypeString;
+ for (unsigned int i = 0; i < defaultBuckets.size(); i++) {
+ buckets.push_back(defaultBuckets[i]);
+ bucketMap[defaultBuckets[i]] = i;
+ }
+ confAvg.resize(maxConfirms);
+ curBlockConf.resize(maxConfirms);
+ unconfTxs.resize(maxConfirms);
+ for (unsigned int i = 0; i < maxConfirms; i++) {
+ confAvg[i].resize(buckets.size());
+ curBlockConf[i].resize(buckets.size());
+ unconfTxs[i].resize(buckets.size());
+ }
+
+ oldUnconfTxs.resize(buckets.size());
+ curBlockTxCt.resize(buckets.size());
+ txCtAvg.resize(buckets.size());
+ curBlockVal.resize(buckets.size());
+ avg.resize(buckets.size());
+}
+
+// Zero out the data for the current block
+void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
+{
+ for (unsigned int j = 0; j < buckets.size(); j++) {
+ oldUnconfTxs[j] += unconfTxs[nBlockHeight%unconfTxs.size()][j];
+ unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
+ for (unsigned int i = 0; i < curBlockConf.size(); i++)
+ curBlockConf[i][j] = 0;
+ curBlockTxCt[j] = 0;
+ curBlockVal[j] = 0;
+ }
+}
+
+
+void TxConfirmStats::Record(int blocksToConfirm, double val)
+{
+ // blocksToConfirm is 1-based
+ if (blocksToConfirm < 1)
+ return;
+ unsigned int bucketindex = bucketMap.lower_bound(val)->second;
+ for (size_t i = blocksToConfirm; i <= curBlockConf.size(); i++) {
+ curBlockConf[i - 1][bucketindex]++;
+ }
+ curBlockTxCt[bucketindex]++;
+ curBlockVal[bucketindex] += val;
+}
+
+void TxConfirmStats::UpdateMovingAverages()
+{
+ for (unsigned int j = 0; j < buckets.size(); j++) {
+ for (unsigned int i = 0; i < confAvg.size(); i++)
+ confAvg[i][j] = confAvg[i][j] * decay + curBlockConf[i][j];
+ avg[j] = avg[j] * decay + curBlockVal[j];
+ txCtAvg[j] = txCtAvg[j] * decay + curBlockTxCt[j];
+ }
+}
+
+// returns -1 on error conditions
+double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
+ double successBreakPoint, bool requireGreater,
+ unsigned int nBlockHeight)
+{
+ // Counters for a bucket (or range of buckets)
+ double nConf = 0; // Number of tx's confirmed within the confTarget
+ double totalNum = 0; // Total number of tx's that were ever confirmed
+ int extraNum = 0; // Number of tx's still in mempool for confTarget or longer
+
+ int maxbucketindex = buckets.size() - 1;
+
+ // requireGreater means we are looking for the lowest fee/priority such that all higher
+ // values pass, so we start at maxbucketindex (highest fee) and look at succesively
+ // smaller buckets until we reach failure. Otherwise, we are looking for the highest
+ // fee/priority such that all lower values fail, and we go in the opposite direction.
+ unsigned int startbucket = requireGreater ? maxbucketindex : 0;
+ int step = requireGreater ? -1 : 1;
+
+ // We'll combine buckets until we have enough samples.
+ // The near and far variables will define the range we've combined
+ // The best variables are the last range we saw which still had a high
+ // enough confirmation rate to count as success.
+ // The cur variables are the current range we're counting.
+ unsigned int curNearBucket = startbucket;
+ unsigned int bestNearBucket = startbucket;
+ unsigned int curFarBucket = startbucket;
+ unsigned int bestFarBucket = startbucket;
+
+ bool foundAnswer = false;
+ unsigned int bins = unconfTxs.size();
+
+ // Start counting from highest(default) or lowest fee/pri transactions
+ for (int bucket = startbucket; bucket >= 0 && bucket <= maxbucketindex; bucket += step) {
+ curFarBucket = bucket;
+ nConf += confAvg[confTarget - 1][bucket];
+ totalNum += txCtAvg[bucket];
+ for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
+ extraNum += unconfTxs[(nBlockHeight - confct)%bins][bucket];
+ extraNum += oldUnconfTxs[bucket];
+ // If we have enough transaction data points in this range of buckets,
+ // we can test for success
+ // (Only count the confirmed data points, so that each confirmation count
+ // will be looking at the same amount of data and same bucket breaks)
+ if (totalNum >= sufficientTxVal / (1 - decay)) {
+ double curPct = nConf / (totalNum + extraNum);
+
+ // Check to see if we are no longer getting confirmed at the success rate
+ if (requireGreater && curPct < successBreakPoint)
+ break;
+ if (!requireGreater && curPct > successBreakPoint)
+ break;
+
+ // Otherwise update the cumulative stats, and the bucket variables
+ // and reset the counters
+ else {
+ foundAnswer = true;
+ nConf = 0;
+ totalNum = 0;
+ extraNum = 0;
+ bestNearBucket = curNearBucket;
+ bestFarBucket = curFarBucket;
+ curNearBucket = bucket + step;
+ }
+ }
+ }
+
+ double median = -1;
+ double txSum = 0;
+
+ // Calculate the "average" fee of the best bucket range that met success conditions
+ // Find the bucket with the median transaction and then report the average fee from that bucket
+ // This is a compromise between finding the median which we can't since we don't save all tx's
+ // and reporting the average which is less accurate
+ unsigned int minBucket = bestNearBucket < bestFarBucket ? bestNearBucket : bestFarBucket;
+ unsigned int maxBucket = bestNearBucket > bestFarBucket ? bestNearBucket : bestFarBucket;
+ for (unsigned int j = minBucket; j <= maxBucket; j++) {
+ txSum += txCtAvg[j];
+ }
+ if (foundAnswer && txSum != 0) {
+ txSum = txSum / 2;
+ for (unsigned int j = minBucket; j <= maxBucket; j++) {
+ if (txCtAvg[j] < txSum)
+ txSum -= txCtAvg[j];
+ else { // we're in the right bucket
+ median = avg[j] / txCtAvg[j];
+ break;
+ }
+ }
+ }
+
+ LogPrint("estimatefee", "%3d: For conf success %s %4.2f need %s %s: %12.5g from buckets %8g - %8g Cur Bucket stats %6.2f%% %8.1f/(%.1f+%d mempool)\n",
+ confTarget, requireGreater ? ">" : "<", successBreakPoint, dataTypeString,
+ requireGreater ? ">" : "<", median, buckets[minBucket], buckets[maxBucket],
+ 100 * nConf / (totalNum + extraNum), nConf, totalNum, extraNum);
+
+ return median;
+}
+
+void TxConfirmStats::Write(CAutoFile& fileout)
+{
+ fileout << decay;
+ fileout << buckets;
+ fileout << avg;
+ fileout << txCtAvg;
+ fileout << confAvg;
+}
+
+void TxConfirmStats::Read(CAutoFile& filein)
+{
+ // Read data file into temporary variables and do some very basic sanity checking
+ std::vector<double> fileBuckets;
+ std::vector<double> fileAvg;
+ std::vector<std::vector<double> > fileConfAvg;
+ std::vector<double> fileTxCtAvg;
+ double fileDecay;
+ size_t maxConfirms;
+ size_t numBuckets;
+
+ filein >> fileDecay;
+ if (fileDecay <= 0 || fileDecay >= 1)
+ throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
+ filein >> fileBuckets;
+ numBuckets = fileBuckets.size();
+ if (numBuckets <= 1 || numBuckets > 1000)
+ throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 fee/pri buckets");
+ filein >> fileAvg;
+ if (fileAvg.size() != numBuckets)
+ throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri average bucket count");
+ filein >> fileTxCtAvg;
+ if (fileTxCtAvg.size() != numBuckets)
+ throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
+ filein >> fileConfAvg;
+ maxConfirms = fileConfAvg.size();
+ if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) // one week
+ throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
+ for (unsigned int i = 0; i < maxConfirms; i++) {
+ if (fileConfAvg[i].size() != numBuckets)
+ throw std::runtime_error("Corrupt estimates file. Mismatch in fee/pri conf average bucket count");
+ }
+ // Now that we've processed the entire fee estimate data file and not
+ // thrown any errors, we can copy it to our data structures
+ decay = fileDecay;
+ buckets = fileBuckets;
+ avg = fileAvg;
+ confAvg = fileConfAvg;
+ txCtAvg = fileTxCtAvg;
+ bucketMap.clear();
+
+ // Resize the current block variables which aren't stored in the data file
+ // to match the number of confirms and buckets
+ curBlockConf.resize(maxConfirms);
+ for (unsigned int i = 0; i < maxConfirms; i++) {
+ curBlockConf[i].resize(buckets.size());
+ }
+ curBlockTxCt.resize(buckets.size());
+ curBlockVal.resize(buckets.size());
+
+ unconfTxs.resize(maxConfirms);
+ for (unsigned int i = 0; i < maxConfirms; i++) {
+ unconfTxs[i].resize(buckets.size());
+ }
+ oldUnconfTxs.resize(buckets.size());
+
+ for (unsigned int i = 0; i < buckets.size(); i++)
+ bucketMap[buckets[i]] = i;
+
+ LogPrint("estimatefee", "Reading estimates: %u %s buckets counting confirms up to %u blocks\n",
+ numBuckets, dataTypeString, maxConfirms);
+}
+
+unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
+{
+ unsigned int bucketindex = bucketMap.lower_bound(val)->second;
+ unsigned int blockIndex = nBlockHeight % unconfTxs.size();
+ unconfTxs[blockIndex][bucketindex]++;
+ LogPrint("estimatefee", "adding to %s", dataTypeString);
+ return bucketindex;
+}
+
+void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex)
+{
+ //nBestSeenHeight is not updated yet for the new block
+ int blocksAgo = nBestSeenHeight - entryHeight;
+ if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet
+ blocksAgo = 0;
+ if (blocksAgo < 0) {
+ LogPrint("estimatefee", "Blockpolicy error, blocks ago is negative for mempool tx\n");
+ return; //This can't happen because we call this with our best seen height, no entries can have higher
+ }
+
+ if (blocksAgo >= (int)unconfTxs.size()) {
+ if (oldUnconfTxs[bucketindex] > 0)
+ oldUnconfTxs[bucketindex]--;
+ else
+ LogPrint("estimatefee", "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
+ bucketindex);
+ }
+ else {
+ unsigned int blockIndex = entryHeight % unconfTxs.size();
+ if (unconfTxs[blockIndex][bucketindex] > 0)
+ unconfTxs[blockIndex][bucketindex]--;
+ else
+ LogPrint("estimatefee", "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
+ blockIndex, bucketindex);
+ }
+}
+
+void CBlockPolicyEstimator::removeTx(uint256 hash)
+{
+ std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
+ if (pos == mapMemPoolTxs.end()) {
+ LogPrint("estimatefee", "Blockpolicy error mempool tx %s not found for removeTx\n",
+ hash.ToString().c_str());
+ return;
+ }
+ TxConfirmStats *stats = pos->second.stats;
+ unsigned int entryHeight = pos->second.blockHeight;
+ unsigned int bucketIndex = pos->second.bucketIndex;
+
+ if (stats != NULL)
+ stats->removeTx(entryHeight, nBestSeenHeight, bucketIndex);
+ mapMemPoolTxs.erase(hash);
+}
+
+CBlockPolicyEstimator::CBlockPolicyEstimator(const CFeeRate& _minRelayFee)
+ : nBestSeenHeight(0)
+{
+ minTrackedFee = _minRelayFee < CFeeRate(MIN_FEERATE) ? CFeeRate(MIN_FEERATE) : _minRelayFee;
+ std::vector<double> vfeelist;
+ for (double bucketBoundary = minTrackedFee.GetFeePerK(); bucketBoundary <= MAX_FEERATE; bucketBoundary *= FEE_SPACING) {
+ vfeelist.push_back(bucketBoundary);
+ }
+ vfeelist.push_back(INF_FEERATE);
+ feeStats.Initialize(vfeelist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "FeeRate");
+
+ minTrackedPriority = AllowFreeThreshold() < MIN_PRIORITY ? MIN_PRIORITY : AllowFreeThreshold();
+ std::vector<double> vprilist;
+ for (double bucketBoundary = minTrackedPriority; bucketBoundary <= MAX_PRIORITY; bucketBoundary *= PRI_SPACING) {
+ vprilist.push_back(bucketBoundary);
+ }
+ vprilist.push_back(INF_PRIORITY);
+ priStats.Initialize(vprilist, MAX_BLOCK_CONFIRMS, DEFAULT_DECAY, "Priority");
+
+ feeUnlikely = CFeeRate(0);
+ feeLikely = CFeeRate(INF_FEERATE);
+ priUnlikely = 0;
+ priLikely = INF_PRIORITY;
+}
+
+bool CBlockPolicyEstimator::isFeeDataPoint(const CFeeRate &fee, double pri)
+{
+ if ((pri < minTrackedPriority && fee >= minTrackedFee) ||
+ (pri < priUnlikely && fee > feeLikely)) {
+ return true;
+ }
+ return false;
+}
+
+bool CBlockPolicyEstimator::isPriDataPoint(const CFeeRate &fee, double pri)
+{
+ if ((fee < minTrackedFee && pri >= minTrackedPriority) ||
+ (fee < feeUnlikely && pri > priLikely)) {
+ return true;
+ }
+ return false;
+}
+
+void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate)
+{
+ unsigned int txHeight = entry.GetHeight();
+ uint256 hash = entry.GetTx().GetHash();
+ if (mapMemPoolTxs[hash].stats != NULL) {
+ LogPrint("estimatefee", "Blockpolicy error mempool tx %s already being tracked\n",
+ hash.ToString().c_str());
+ return;
+ }
+
+ if (txHeight < nBestSeenHeight) {
+ // Ignore side chains and re-orgs; assuming they are random they don't
+ // affect the estimate. We'll potentially double count transactions in 1-block reorgs.
+ return;
+ }
+
+ // Only want to be updating estimates when our blockchain is synced,
+ // otherwise we'll miscalculate how many blocks its taking to get included.
+ if (!fCurrentEstimate)
+ return;
+
+ if (!entry.WasClearAtEntry()) {
+ // This transaction depends on other transactions in the mempool to
+ // be included in a block before it will be able to be included, so
+ // we shouldn't include it in our calculations
+ return;
+ }
+
+ // Fees are stored and reported as BTC-per-kb:
+ CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
+
+ // Want the priority of the tx at confirmation. However we don't know
+ // what that will be and its too hard to continue updating it
+ // so use starting priority as a proxy
+ double curPri = entry.GetPriority(txHeight);
+ mapMemPoolTxs[hash].blockHeight = txHeight;
+
+ LogPrint("estimatefee", "Blockpolicy mempool tx %s ", hash.ToString().substr(0,10));
+ // Record this as a priority estimate
+ if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
+ mapMemPoolTxs[hash].stats = &priStats;
+ mapMemPoolTxs[hash].bucketIndex = priStats.NewTx(txHeight, curPri);
+ }
+ // Record this as a fee estimate
+ else if (isFeeDataPoint(feeRate, curPri)) {
+ mapMemPoolTxs[hash].stats = &feeStats;
+ mapMemPoolTxs[hash].bucketIndex = feeStats.NewTx(txHeight, (double)feeRate.GetFeePerK());
+ }
+ else {
+ LogPrint("estimatefee", "not adding");
+ }
+ LogPrint("estimatefee", "\n");
+}
+
+void CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry)
+{
+ if (!entry.WasClearAtEntry()) {
+ // This transaction depended on other transactions in the mempool to
+ // be included in a block before it was able to be included, so
+ // we shouldn't include it in our calculations
+ return;
+ }
+
+ // How many blocks did it take for miners to include this transaction?
+ // blocksToConfirm is 1-based, so a transaction included in the earliest
+ // possible block has confirmation count of 1
+ int blocksToConfirm = nBlockHeight - entry.GetHeight();
+ if (blocksToConfirm <= 0) {
+ // This can't happen because we don't process transactions from a block with a height
+ // lower than our greatest seen height
+ LogPrint("estimatefee", "Blockpolicy error Transaction had negative blocksToConfirm\n");
+ return;
+ }
+
+ // Fees are stored and reported as BTC-per-kb:
+ CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
+
+ // Want the priority of the tx at confirmation. The priority when it
+ // entered the mempool could easily be very small and change quickly
+ double curPri = entry.GetPriority(nBlockHeight);
+
+ // Record this as a priority estimate
+ if (entry.GetFee() == 0 || isPriDataPoint(feeRate, curPri)) {
+ priStats.Record(blocksToConfirm, curPri);
+ }
+ // Record this as a fee estimate
+ else if (isFeeDataPoint(feeRate, curPri)) {
+ feeStats.Record(blocksToConfirm, (double)feeRate.GetFeePerK());
+ }
+}
+
+void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
+ std::vector<CTxMemPoolEntry>& entries, bool fCurrentEstimate)
+{
+ if (nBlockHeight <= nBestSeenHeight) {
+ // Ignore side chains and re-orgs; assuming they are random
+ // they don't affect the estimate.
+ // And if an attacker can re-org the chain at will, then
+ // you've got much bigger problems than "attacker can influence
+ // transaction fees."
+ return;
+ }
+ nBestSeenHeight = nBlockHeight;
+
+ // Only want to be updating estimates when our blockchain is synced,
+ // otherwise we'll miscalculate how many blocks its taking to get included.
+ if (!fCurrentEstimate)
+ return;
+
+ // Update the dynamic cutoffs
+ // a fee/priority is "likely" the reason your tx was included in a block if >85% of such tx's
+ // were confirmed in 2 blocks and is "unlikely" if <50% were confirmed in 10 blocks
+ LogPrint("estimatefee", "Blockpolicy recalculating dynamic cutoffs:\n");
+ priLikely = priStats.EstimateMedianVal(2, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBlockHeight);
+ if (priLikely == -1)
+ priLikely = INF_PRIORITY;
+
+ double feeLikelyEst = feeStats.EstimateMedianVal(2, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBlockHeight);
+ if (feeLikelyEst == -1)
+ feeLikely = CFeeRate(INF_FEERATE);
+ else
+ feeLikely = CFeeRate(feeLikelyEst);
+
+ priUnlikely = priStats.EstimateMedianVal(10, SUFFICIENT_PRITXS, UNLIKELY_PCT, false, nBlockHeight);
+ if (priUnlikely == -1)
+ priUnlikely = 0;
+
+ double feeUnlikelyEst = feeStats.EstimateMedianVal(10, SUFFICIENT_FEETXS, UNLIKELY_PCT, false, nBlockHeight);
+ if (feeUnlikelyEst == -1)
+ feeUnlikely = CFeeRate(0);
+ else
+ feeUnlikely = CFeeRate(feeUnlikelyEst);
+
+ // Clear the current block states
+ feeStats.ClearCurrent(nBlockHeight);
+ priStats.ClearCurrent(nBlockHeight);
+
+ // Repopulate the current block states
+ for (unsigned int i = 0; i < entries.size(); i++)
+ processBlockTx(nBlockHeight, entries[i]);
+
+ // Update all exponential averages with the current block states
+ feeStats.UpdateMovingAverages();
+ priStats.UpdateMovingAverages();
+
+ LogPrint("estimatefee", "Blockpolicy after updating estimates for %u confirmed entries, new mempool map size %u\n",
+ entries.size(), mapMemPoolTxs.size());
+}
+
+CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget)
+{
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > feeStats.GetMaxConfirms())
+ return CFeeRate(0);
+
+ double median = feeStats.EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+
+ if (median < 0)
+ return CFeeRate(0);
+
+ return CFeeRate(median);
+}
+
+double CBlockPolicyEstimator::estimatePriority(int confTarget)
+{
+ // Return failure if trying to analyze a target we're not tracking
+ if (confTarget <= 0 || (unsigned int)confTarget > priStats.GetMaxConfirms())
+ return -1;
+
+ return priStats.EstimateMedianVal(confTarget, SUFFICIENT_PRITXS, MIN_SUCCESS_PCT, true, nBestSeenHeight);
+}
+
+void CBlockPolicyEstimator::Write(CAutoFile& fileout)
+{
+ fileout << nBestSeenHeight;
+ feeStats.Write(fileout);
+ priStats.Write(fileout);
+}
+
+void CBlockPolicyEstimator::Read(CAutoFile& filein)
+{
+ int nFileBestSeenHeight;
+ filein >> nFileBestSeenHeight;
+ feeStats.Read(filein);
+ priStats.Read(filein);
+ nBestSeenHeight = nFileBestSeenHeight;
+}
diff --git a/src/policy/fees.h b/src/policy/fees.h
new file mode 100644
index 0000000000..15577d128a
--- /dev/null
+++ b/src/policy/fees.h
@@ -0,0 +1,276 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2015 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#ifndef BITCOIN_POLICYESTIMATOR_H
+#define BITCOIN_POLICYESTIMATOR_H
+
+#include "amount.h"
+#include "uint256.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+class CAutoFile;
+class CFeeRate;
+class CTxMemPoolEntry;
+
+/** \class CBlockPolicyEstimator
+ * The BlockPolicyEstimator is used for estimating the fee or priority needed
+ * for a transaction to be included in a block within a certain number of
+ * blocks.
+ *
+ * At a high level the algorithm works by grouping transactions into buckets
+ * based on having similar priorities or fees and then tracking how long it
+ * takes transactions in the various buckets to be mined. It operates under
+ * the assumption that in general transactions of higher fee/priority will be
+ * included in blocks before transactions of lower fee/priority. So for
+ * example if you wanted to know what fee you should put on a transaction to
+ * be included in a block within the next 5 blocks, you would start by looking
+ * at the bucket with with the highest fee transactions and verifying that a
+ * sufficiently high percentage of them were confirmed within 5 blocks and
+ * then you would look at the next highest fee bucket, and so on, stopping at
+ * the last bucket to pass the test. The average fee of transactions in this
+ * bucket will give you an indication of the lowest fee you can put on a
+ * transaction and still have a sufficiently high chance of being confirmed
+ * within your desired 5 blocks.
+ *
+ * When a transaction enters the mempool or is included within a block we
+ * decide whether it can be used as a data point for fee estimation, priority
+ * estimation or neither. If the value of exactly one of those properties was
+ * below the required minimum it can be used to estimate the other. In
+ * addition, if a priori our estimation code would indicate that the
+ * transaction would be much more quickly included in a block because of one
+ * of the properties compared to the other, we can also decide to use it as
+ * an estimate for that property.
+ *
+ * Here is a brief description of the implementation for fee estimation.
+ * When a transaction that counts for fee estimation enters the mempool, we
+ * track the height of the block chain at entry. Whenever a block comes in,
+ * we count the number of transactions in each bucket and the total amount of fee
+ * paid in each bucket. Then we calculate how many blocks Y it took each
+ * transaction to be mined and we track an array of counters in each bucket
+ * for how long it to took transactions to get confirmed from 1 to a max of 25
+ * and we increment all the counters from Y up to 25. This is because for any
+ * number Z>=Y the transaction was successfully mined within Z blocks. We
+ * want to save a history of this information, so at any time we have a
+ * counter of the total number of transactions that happened in a given fee
+ * bucket and the total number that were confirmed in each number 1-25 blocks
+ * or less for any bucket. We save this history by keeping an exponentially
+ * decaying moving average of each one of these stats. Furthermore we also
+ * keep track of the number unmined (in mempool) transactions in each bucket
+ * and for how many blocks they have been outstanding and use that to increase
+ * the number of transactions we've seen in that fee bucket when calculating
+ * an estimate for any number of confirmations below the number of blocks
+ * they've been outstanding.
+ */
+
+/**
+ * We will instantiate two instances of this class, one to track transactions
+ * that were included in a block due to fee, and one for tx's included due to
+ * priority. We will lump transactions into a bucket according to their approximate
+ * fee or priority and then track how long it took for those txs to be included in a block
+ *
+ * The tracking of unconfirmed (mempool) transactions is completely independent of the
+ * historical tracking of transactions that have been confirmed in a block.
+ */
+class TxConfirmStats
+{
+private:
+ //Define the buckets we will group transactions into (both fee buckets and priority buckets)
+ std::vector<double> buckets; // The upper-bound of the range for the bucket (inclusive)
+ std::map<double, unsigned int> bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
+
+ // For each bucket X:
+ // Count the total # of txs in each bucket
+ // Track the historical moving average of this total over blocks
+ std::vector<double> txCtAvg;
+ // and calcuate the total for the current block to update the moving average
+ std::vector<int> curBlockTxCt;
+
+ // Count the total # of txs confirmed within Y blocks in each bucket
+ // Track the historical moving average of theses totals over blocks
+ std::vector<std::vector<double> > confAvg; // confAvg[Y][X]
+ // and calcuate the totals for the current block to update the moving averages
+ std::vector<std::vector<int> > curBlockConf; // curBlockConf[Y][X]
+
+ // Sum the total priority/fee of all tx's in each bucket
+ // Track the historical moving average of this total over blocks
+ std::vector<double> avg;
+ // and calculate the total for the current block to update the moving average
+ std::vector<double> curBlockVal;
+
+ // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
+ // Combine the total value with the tx counts to calculate the avg fee/priority per bucket
+
+ std::string dataTypeString;
+ double decay;
+
+ // Mempool counts of outstanding transactions
+ // For each bucket X, track the number of transactions in the mempool
+ // that are unconfirmed for each possible confirmation value Y
+ std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
+ // transactions still unconfirmed after MAX_CONFIRMS for each bucket
+ std::vector<int> oldUnconfTxs;
+
+public:
+ /**
+ * Initialize the data structures. This is called by BlockPolicyEstimator's
+ * constructor with default values.
+ * @param defaultBuckets contains the upper limits for the bucket boundaries
+ * @param maxConfirms max number of confirms to track
+ * @param decay how much to decay the historical moving average per block
+ * @param dataTypeString for logging purposes
+ */
+ void Initialize(std::vector<double>& defaultBuckets, unsigned int maxConfirms, double decay, std::string dataTypeString);
+
+ /** Clear the state of the curBlock variables to start counting for the new block */
+ void ClearCurrent(unsigned int nBlockHeight);
+
+ /**
+ * Record a new transaction data point in the current block stats
+ * @param blocksToConfirm the number of blocks it took this transaction to confirm
+ * @param val either the fee or the priority when entered of the transaction
+ * @warning blocksToConfirm is 1-based and has to be >= 1
+ */
+ void Record(int blocksToConfirm, double val);
+
+ /** Record a new transaction entering the mempool*/
+ unsigned int NewTx(unsigned int nBlockHeight, double val);
+
+ /** Remove a transaction from mempool tracking stats*/
+ void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
+ unsigned int bucketIndex);
+
+ /** Update our estimates by decaying our historical moving average and updating
+ with the data gathered from the current block */
+ void UpdateMovingAverages();
+
+ /**
+ * Calculate a fee or priority estimate. Find the lowest value bucket (or range of buckets
+ * to make sure we have enough data points) whose transactions still have sufficient likelihood
+ * of being confirmed within the target number of confirmations
+ * @param confTarget target number of confirmations
+ * @param sufficientTxVal required average number of transactions per block in a bucket range
+ * @param minSuccess the success probability we require
+ * @param requireGreater return the lowest fee/pri such that all higher values pass minSuccess OR
+ * return the highest fee/pri such that all lower values fail minSuccess
+ * @param nBlockHeight the current block height
+ */
+ double EstimateMedianVal(int confTarget, double sufficientTxVal,
+ double minSuccess, bool requireGreater, unsigned int nBlockHeight);
+
+ /** Return the max number of confirms we're tracking */
+ unsigned int GetMaxConfirms() { return confAvg.size(); }
+
+ /** Write state of estimation data to a file*/
+ void Write(CAutoFile& fileout);
+
+ /**
+ * Read saved state of estimation data from a file and replace all internal data structures and
+ * variables with this state.
+ */
+ void Read(CAutoFile& filein);
+};
+
+
+
+/** Track confirm delays up to 25 blocks, can't estimate beyond that */
+static const unsigned int MAX_BLOCK_CONFIRMS = 25;
+
+/** Decay of .998 is a half-life of 346 blocks or about 2.4 days */
+static const double DEFAULT_DECAY = .998;
+
+/** Require greater than 85% of X fee transactions to be confirmed within Y blocks for X to be big enough */
+static const double MIN_SUCCESS_PCT = .85;
+static const double UNLIKELY_PCT = .5;
+
+/** Require an avg of 1 tx in the combined fee bucket per block to have stat significance */
+static const double SUFFICIENT_FEETXS = 1;
+
+/** Require only an avg of 1 tx every 5 blocks in the combined pri bucket (way less pri txs) */
+static const double SUFFICIENT_PRITXS = .2;
+
+// Minimum and Maximum values for tracking fees and priorities
+static const double MIN_FEERATE = 10;
+static const double MAX_FEERATE = 1e7;
+static const double INF_FEERATE = MAX_MONEY;
+static const double MIN_PRIORITY = 10;
+static const double MAX_PRIORITY = 1e16;
+static const double INF_PRIORITY = 1e9 * MAX_MONEY;
+
+// We have to lump transactions into buckets based on fee or priority, but we want to be able
+// to give accurate estimates over a large range of potential fees and priorities
+// Therefore it makes sense to exponentially space the buckets
+/** Spacing of FeeRate buckets */
+static const double FEE_SPACING = 1.1;
+
+/** Spacing of Priority buckets */
+static const double PRI_SPACING = 2;
+
+/**
+ * We want to be able to estimate fees or priorities that are needed on tx's to be included in
+ * a certain number of blocks. Every time a block is added to the best chain, this class records
+ * stats on the transactions included in that block
+ */
+class CBlockPolicyEstimator
+{
+public:
+ /** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
+ CBlockPolicyEstimator(const CFeeRate& minRelayFee);
+
+ /** Process all the transactions that have been included in a block */
+ void processBlock(unsigned int nBlockHeight,
+ std::vector<CTxMemPoolEntry>& entries, bool fCurrentEstimate);
+
+ /** Process a transaction confirmed in a block*/
+ void processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry& entry);
+
+ /** Process a transaction accepted to the mempool*/
+ void processTransaction(const CTxMemPoolEntry& entry, bool fCurrentEstimate);
+
+ /** Remove a transaction from the mempool tracking stats*/
+ void removeTx(uint256 hash);
+
+ /** Is this transaction likely included in a block because of its fee?*/
+ bool isFeeDataPoint(const CFeeRate &fee, double pri);
+
+ /** Is this transaction likely included in a block because of its priority?*/
+ bool isPriDataPoint(const CFeeRate &fee, double pri);
+
+ /** Return a fee estimate */
+ CFeeRate estimateFee(int confTarget);
+
+ /** Return a priority estimate */
+ double estimatePriority(int confTarget);
+
+ /** Write estimation data to a file */
+ void Write(CAutoFile& fileout);
+
+ /** Read estimation data from a file */
+ void Read(CAutoFile& filein);
+
+private:
+ CFeeRate minTrackedFee; //! Passed to constructor to avoid dependency on main
+ double minTrackedPriority; //! Set to AllowFreeThreshold
+ unsigned int nBestSeenHeight;
+ struct TxStatsInfo
+ {
+ TxConfirmStats *stats;
+ unsigned int blockHeight;
+ unsigned int bucketIndex;
+ TxStatsInfo() : stats(NULL), blockHeight(0), bucketIndex(0) {}
+ };
+
+ // map of txids to information about that transaction
+ std::map<uint256, TxStatsInfo> mapMemPoolTxs;
+
+ /** Classes to track historical data on transaction confirmations */
+ TxConfirmStats feeStats, priStats;
+
+ /** Breakpoints to help determine whether a transaction was confirmed by priority or Fee */
+ CFeeRate feeLikely, feeUnlikely;
+ double priLikely, priUnlikely;
+};
+#endif /*BITCOIN_POLICYESTIMATOR_H */
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
new file mode 100644
index 0000000000..169fef4af4
--- /dev/null
+++ b/src/policy/policy.cpp
@@ -0,0 +1,178 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+// NOTE: This file is intended to be customised by the end user, and includes only local node policy logic
+
+#include "policy/policy.h"
+
+#include "main.h"
+#include "tinyformat.h"
+#include "util.h"
+#include "utilstrencodings.h"
+
+#include <boost/foreach.hpp>
+
+ /**
+ * Check transaction inputs to mitigate two
+ * potential denial-of-service attacks:
+ *
+ * 1. scriptSigs with extra data stuffed into them,
+ * not consumed by scriptPubKey (or P2SH script)
+ * 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
+ * script can be anything; an attacker could use a very
+ * expensive-to-check-upon-redemption script like:
+ * DUP CHECKSIG DROP ... repeated 100 times... OP_1
+ */
+
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
+{
+ std::vector<std::vector<unsigned char> > vSolutions;
+ if (!Solver(scriptPubKey, whichType, vSolutions))
+ return false;
+
+ if (whichType == TX_MULTISIG)
+ {
+ unsigned char m = vSolutions.front()[0];
+ unsigned char n = vSolutions.back()[0];
+ // Support up to x-of-3 multisig txns as standard
+ if (n < 1 || n > 3)
+ return false;
+ if (m < 1 || m > n)
+ return false;
+ }
+
+ return whichType != TX_NONSTANDARD;
+}
+
+bool IsStandardTx(const CTransaction& tx, std::string& reason)
+{
+ if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
+ reason = "version";
+ return false;
+ }
+
+ // Extremely large transactions with lots of inputs can cost the network
+ // almost as much to process as they cost the sender in fees, because
+ // computing signature hashes is O(ninputs*txsize). Limiting transactions
+ // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
+ unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
+ if (sz >= MAX_STANDARD_TX_SIZE) {
+ reason = "tx-size";
+ return false;
+ }
+
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
+ // keys. (remember the 520 byte limit on redeemScript size) That works
+ // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627
+ // bytes of scriptSig, which we round off to 1650 bytes for some minor
+ // future-proofing. That's also enough to spend a 20-of-20
+ // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not
+ // considered standard)
+ if (txin.scriptSig.size() > 1650) {
+ reason = "scriptsig-size";
+ return false;
+ }
+ if (!txin.scriptSig.IsPushOnly()) {
+ reason = "scriptsig-not-pushonly";
+ return false;
+ }
+ }
+
+ unsigned int nDataOut = 0;
+ txnouttype whichType;
+ BOOST_FOREACH(const CTxOut& txout, tx.vout) {
+ if (!::IsStandard(txout.scriptPubKey, whichType)) {
+ reason = "scriptpubkey";
+ return false;
+ }
+
+ if (whichType == TX_NULL_DATA)
+ nDataOut++;
+ else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
+ reason = "bare-multisig";
+ return false;
+ } else if (txout.IsDust(::minRelayTxFee)) {
+ reason = "dust";
+ return false;
+ }
+ }
+
+ // only one OP_RETURN txout is permitted
+ if (nDataOut > 1) {
+ reason = "multi-op-return";
+ return false;
+ }
+
+ return true;
+}
+
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
+{
+ if (tx.IsCoinBase())
+ return true; // Coinbases don't use vin normally
+
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ {
+ const CTxOut& prev = mapInputs.GetOutputFor(tx.vin[i]);
+
+ std::vector<std::vector<unsigned char> > vSolutions;
+ txnouttype whichType;
+ // get the scriptPubKey corresponding to this input:
+ const CScript& prevScript = prev.scriptPubKey;
+ if (!Solver(prevScript, whichType, vSolutions))
+ return false;
+ int nArgsExpected = ScriptSigArgsExpected(whichType, vSolutions);
+ if (nArgsExpected < 0)
+ return false;
+
+ // Transactions with extra stuff in their scriptSigs are
+ // non-standard. Note that this EvalScript() call will
+ // be quick, because if there are any operations
+ // beside "push data" in the scriptSig
+ // IsStandardTx() will have already returned false
+ // and this method isn't called.
+ std::vector<std::vector<unsigned char> > stack;
+ if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker()))
+ return false;
+
+ if (whichType == TX_SCRIPTHASH)
+ {
+ if (stack.empty())
+ return false;
+ CScript subscript(stack.back().begin(), stack.back().end());
+ std::vector<std::vector<unsigned char> > vSolutions2;
+ txnouttype whichType2;
+ if (Solver(subscript, whichType2, vSolutions2))
+ {
+ int tmpExpected = ScriptSigArgsExpected(whichType2, vSolutions2);
+ if (tmpExpected < 0)
+ return false;
+ nArgsExpected += tmpExpected;
+ }
+ else
+ {
+ // Any other Script with less than 15 sigops OK:
+ unsigned int sigops = subscript.GetSigOpCount(true);
+ // ... extra data left on the stack after execution is OK, too:
+ return (sigops <= MAX_P2SH_SIGOPS);
+ }
+ }
+
+ if (stack.size() != (unsigned int)nArgsExpected)
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/policy/policy.h b/src/policy/policy.h
new file mode 100644
index 0000000000..1551aecde8
--- /dev/null
+++ b/src/policy/policy.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2014 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_POLICY_H
+#define BITCOIN_POLICY_H
+
+#include "consensus/consensus.h"
+#include "script/interpreter.h"
+#include "script/standard.h"
+
+#include <string>
+
+class CCoinsViewCache;
+
+/** Default for -blockmaxsize and -blockminsize, which control the range of sizes the mining code will create **/
+static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
+static const unsigned int DEFAULT_BLOCK_MIN_SIZE = 0;
+/** Default for -blockprioritysize, maximum space for zero/low-fee transactions **/
+static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
+/** The maximum size for transactions we're willing to relay/mine */
+static const unsigned int MAX_STANDARD_TX_SIZE = 100000;
+/** Maximum number of signature check operations in an IsStandard() P2SH script */
+static const unsigned int MAX_P2SH_SIGOPS = 15;
+/** The maximum number of sigops we're willing to relay/mine in a single tx */
+static const unsigned int MAX_STANDARD_TX_SIGOPS = MAX_BLOCK_SIGOPS/5;
+/**
+ * Standard script verification flags that standard transactions will comply
+ * with. However scripts violating these flags may still be present in valid
+ * blocks and we must accept those blocks.
+ */
+static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
+ SCRIPT_VERIFY_DERSIG |
+ SCRIPT_VERIFY_STRICTENC |
+ SCRIPT_VERIFY_MINIMALDATA |
+ SCRIPT_VERIFY_NULLDUMMY |
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
+ SCRIPT_VERIFY_CLEANSTACK |
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
+
+/** For convenience, standard but not mandatory verify flags. */
+static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
+
+bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
+ /**
+ * Check for standard transaction types
+ * @return True if all outputs (scriptPubKeys) use only standard transaction forms
+ */
+bool IsStandardTx(const CTransaction& tx, std::string& reason);
+ /**
+ * Check for standard transaction types
+ * @param[in] mapInputs Map of previous transactions that have outputs we're spending
+ * @return True if all inputs (scriptSigs) use only standard transaction forms
+ */
+bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs);
+
+#endif // BITCOIN_POLICY_H
diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h
index 6cfd93a9a1..2a457cdae7 100644
--- a/src/primitives/transaction.h
+++ b/src/primitives/transaction.h
@@ -141,10 +141,13 @@ public:
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
- // A typical txout is 34 bytes big, and will
+ // A typical spendable txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
- // so dust is a txout less than 546 satoshis
+ // so dust is a spendable txout less than 546 satoshis
// with default minRelayTxFee.
+ if (scriptPubKey.IsUnspendable())
+ return 0;
+
size_t nSize = GetSerializeSize(SER_DISK,0)+148u;
return 3*minRelayTxFee.GetFee(nSize);
}
diff --git a/src/protocol.h b/src/protocol.h
index b5e65032a2..50aeaf44ba 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -75,6 +75,10 @@ enum {
// Bitcoin Core does not support this but a patch set called Bitcoin XT does.
// See BIP 64 for details on how this is implemented.
NODE_GETUTXO = (1 << 1),
+ // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.
+ // Bitcoin Core nodes used to support this by default, without advertising this bit,
+ // but no longer do as of protocol version 70011 (= NO_BLOOM_VERSION)
+ NODE_BLOOM = (1 << 2),
// Bits 24-31 are reserved for temporary experiments. Just pick a bit that
// isn't getting used, or one not being used much, and notify the
diff --git a/src/qt/addressbookpage.cpp b/src/qt/addressbookpage.cpp
index 5485d89f3e..8bd1586446 100644
--- a/src/qt/addressbookpage.cpp
+++ b/src/qt/addressbookpage.cpp
@@ -14,14 +14,14 @@
#include "csvmodelwriter.h"
#include "editaddressdialog.h"
#include "guiutil.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include <QIcon>
#include <QMenu>
#include <QMessageBox>
#include <QSortFilterProxyModel>
-AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
+AddressBookPage::AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent) :
QDialog(parent),
ui(new Ui::AddressBookPage),
model(0),
@@ -30,17 +30,17 @@ AddressBookPage::AddressBookPage(Mode mode, Tabs tab, QWidget *parent) :
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->newAddress->setIcon(QIcon());
- ui->copyAddress->setIcon(QIcon());
- ui->deleteAddress->setIcon(QIcon());
- ui->exportButton->setIcon(QIcon());
-#else
- ui->newAddress->setIcon(SingleColorIcon(":/icons/add"));
- ui->copyAddress->setIcon(SingleColorIcon(":/icons/editcopy"));
- ui->deleteAddress->setIcon(SingleColorIcon(":/icons/remove"));
- ui->exportButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->newAddress->setIcon(QIcon());
+ ui->copyAddress->setIcon(QIcon());
+ ui->deleteAddress->setIcon(QIcon());
+ ui->exportButton->setIcon(QIcon());
+ } else {
+ ui->newAddress->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
+ ui->copyAddress->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
+ ui->deleteAddress->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
switch(mode)
{
@@ -254,8 +254,7 @@ void AddressBookPage::done(int retval)
// Figure out which address was selected, and return it
QModelIndexList indexes = table->selectionModel()->selectedRows(AddressTableModel::Address);
- foreach (QModelIndex index, indexes)
- {
+ Q_FOREACH (const QModelIndex& index, indexes) {
QVariant address = table->model()->data(index);
returnValue = address.toString();
}
diff --git a/src/qt/addressbookpage.h b/src/qt/addressbookpage.h
index 5105f09ced..92e6cab9ac 100644
--- a/src/qt/addressbookpage.h
+++ b/src/qt/addressbookpage.h
@@ -9,6 +9,7 @@
class AddressTableModel;
class OptionsModel;
+class PlatformStyle;
namespace Ui {
class AddressBookPage;
@@ -39,13 +40,13 @@ public:
ForEditing /**< Open address book for editing */
};
- explicit AddressBookPage(Mode mode, Tabs tab, QWidget *parent);
+ explicit AddressBookPage(const PlatformStyle *platformStyle, Mode mode, Tabs tab, QWidget *parent);
~AddressBookPage();
void setModel(AddressTableModel *model);
const QString &getReturnValue() const { return returnValue; }
-public slots:
+public Q_SLOTS:
void done(int retval);
private:
@@ -59,7 +60,7 @@ private:
QAction *deleteAction; // to be able to explicitly disable it
QString newAddressToSelect;
-private slots:
+private Q_SLOTS:
/** Delete currently selected address entry */
void on_deleteAddress_clicked();
/** Create a new address for receiving coins and / or add a new address book entry */
@@ -80,7 +81,7 @@ private slots:
/** New entry/entries were added to address table */
void selectNewAddress(const QModelIndex &parent, int begin, int /*end*/);
-signals:
+Q_SIGNALS:
void sendCoins(QString addr);
};
diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp
index 8e20836c65..c5ac07cfc2 100644
--- a/src/qt/addresstablemodel.cpp
+++ b/src/qt/addresstablemodel.cpp
@@ -450,5 +450,5 @@ int AddressTableModel::lookupAddress(const QString &address) const
void AddressTableModel::emitDataChanged(int idx)
{
- emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
+ Q_EMIT dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length()-1, QModelIndex()));
}
diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h
index 6b34b2eac2..2b7475c4e2 100644
--- a/src/qt/addresstablemodel.h
+++ b/src/qt/addresstablemodel.h
@@ -84,7 +84,7 @@ private:
/** Notify listeners that data changed. */
void emitDataChanged(int index);
-public slots:
+public Q_SLOTS:
/* Update address list from core.
*/
void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status);
diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h
index 74d54d18f7..d4d832825a 100644
--- a/src/qt/askpassphrasedialog.h
+++ b/src/qt/askpassphrasedialog.h
@@ -40,7 +40,7 @@ private:
WalletModel *model;
bool fCapsLock;
-private slots:
+private Q_SLOTS:
void textChanged();
protected:
diff --git a/src/qt/bantablemodel.cpp b/src/qt/bantablemodel.cpp
new file mode 100644
index 0000000000..33792af5ba
--- /dev/null
+++ b/src/qt/bantablemodel.cpp
@@ -0,0 +1,181 @@
+// Copyright (c) 2011-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.
+
+#include "bantablemodel.h"
+
+#include "clientmodel.h"
+#include "guiconstants.h"
+#include "guiutil.h"
+
+#include "sync.h"
+#include "utiltime.h"
+
+#include <QDebug>
+#include <QList>
+
+bool BannedNodeLessThan::operator()(const CCombinedBan& left, const CCombinedBan& right) const
+{
+ const CCombinedBan* pLeft = &left;
+ const CCombinedBan* pRight = &right;
+
+ if (order == Qt::DescendingOrder)
+ std::swap(pLeft, pRight);
+
+ switch(column)
+ {
+ case BanTableModel::Address:
+ return pLeft->subnet.ToString().compare(pRight->subnet.ToString()) < 0;
+ case BanTableModel::Bantime:
+ return pLeft->banEntry.nBanUntil < pRight->banEntry.nBanUntil;
+ }
+
+ return false;
+}
+
+// private implementation
+class BanTablePriv
+{
+public:
+ /** Local cache of peer information */
+ QList<CCombinedBan> cachedBanlist;
+ /** Column to sort nodes by */
+ int sortColumn;
+ /** Order (ascending or descending) to sort nodes by */
+ Qt::SortOrder sortOrder;
+
+ /** Pull a full list of banned nodes from CNode into our cache */
+ void refreshBanlist()
+ {
+ banmap_t banMap;
+ CNode::GetBanned(banMap);
+
+ cachedBanlist.clear();
+#if QT_VERSION >= 0x040700
+ cachedBanlist.reserve(banMap.size());
+#endif
+ for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ {
+ CCombinedBan banEntry;
+ banEntry.subnet = (*it).first;
+ banEntry.banEntry = (*it).second;
+ cachedBanlist.append(banEntry);
+ }
+
+ if (sortColumn >= 0)
+ // sort cachedBanlist (use stable sort to prevent rows jumping around unneceesarily)
+ qStableSort(cachedBanlist.begin(), cachedBanlist.end(), BannedNodeLessThan(sortColumn, sortOrder));
+ }
+
+ int size() const
+ {
+ return cachedBanlist.size();
+ }
+
+ CCombinedBan *index(int idx)
+ {
+ if (idx >= 0 && idx < cachedBanlist.size())
+ return &cachedBanlist[idx];
+
+ return 0;
+ }
+};
+
+BanTableModel::BanTableModel(ClientModel *parent) :
+ QAbstractTableModel(parent),
+ clientModel(parent)
+{
+ columns << tr("IP/Netmask") << tr("Banned Until");
+ priv = new BanTablePriv();
+ // default to unsorted
+ priv->sortColumn = -1;
+
+ // load initial data
+ refresh();
+}
+
+int BanTableModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return priv->size();
+}
+
+int BanTableModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return columns.length();;
+}
+
+QVariant BanTableModel::data(const QModelIndex &index, int role) const
+{
+ if(!index.isValid())
+ return QVariant();
+
+ CCombinedBan *rec = static_cast<CCombinedBan*>(index.internalPointer());
+
+ if (role == Qt::DisplayRole) {
+ switch(index.column())
+ {
+ case Address:
+ return QString::fromStdString(rec->subnet.ToString());
+ case Bantime:
+ QDateTime date = QDateTime::fromMSecsSinceEpoch(0);
+ date = date.addSecs(rec->banEntry.nBanUntil);
+ return date.toString(Qt::SystemLocaleLongDate);
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant BanTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if(orientation == Qt::Horizontal)
+ {
+ if(role == Qt::DisplayRole && section < columns.size())
+ {
+ return columns[section];
+ }
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags BanTableModel::flags(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return 0;
+
+ Qt::ItemFlags retval = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
+ return retval;
+}
+
+QModelIndex BanTableModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ CCombinedBan *data = priv->index(row);
+
+ if (data)
+ return createIndex(row, column, data);
+ return QModelIndex();
+}
+
+void BanTableModel::refresh()
+{
+ Q_EMIT layoutAboutToBeChanged();
+ priv->refreshBanlist();
+ Q_EMIT layoutChanged();
+}
+
+void BanTableModel::sort(int column, Qt::SortOrder order)
+{
+ priv->sortColumn = column;
+ priv->sortOrder = order;
+ refresh();
+}
+
+bool BanTableModel::shouldShow()
+{
+ if (priv->size() > 0)
+ return true;
+ return false;
+} \ No newline at end of file
diff --git a/src/qt/bantablemodel.h b/src/qt/bantablemodel.h
new file mode 100644
index 0000000000..c21dd04e31
--- /dev/null
+++ b/src/qt/bantablemodel.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2011-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_QT_BANTABLEMODEL_H
+#define BITCOIN_QT_BANTABLEMODEL_H
+
+#include "net.h"
+
+#include <QAbstractTableModel>
+#include <QStringList>
+
+class ClientModel;
+class BanTablePriv;
+
+struct CCombinedBan {
+ CSubNet subnet;
+ CBanEntry banEntry;
+};
+
+class BannedNodeLessThan
+{
+public:
+ BannedNodeLessThan(int nColumn, Qt::SortOrder fOrder) :
+ column(nColumn), order(fOrder) {}
+ bool operator()(const CCombinedBan& left, const CCombinedBan& right) const;
+
+private:
+ int column;
+ Qt::SortOrder order;
+};
+
+/**
+ Qt model providing information about connected peers, similar to the
+ "getpeerinfo" RPC call. Used by the rpc console UI.
+ */
+class BanTableModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ explicit BanTableModel(ClientModel *parent = 0);
+ void startAutoRefresh();
+ void stopAutoRefresh();
+
+ enum ColumnIndex {
+ Address = 0,
+ Bantime = 1
+ };
+
+ /** @name Methods overridden from QAbstractTableModel
+ @{*/
+ int rowCount(const QModelIndex &parent) const;
+ int columnCount(const QModelIndex &parent) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ void sort(int column, Qt::SortOrder order);
+ bool shouldShow();
+ /*@}*/
+
+public Q_SLOTS:
+ void refresh();
+
+private:
+ ClientModel *clientModel;
+ QStringList columns;
+ BanTablePriv *priv;
+};
+
+#endif // BITCOIN_QT_BANTABLEMODEL_H
diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp
index 018169cfdc..ea7f86d18e 100644
--- a/src/qt/bitcoin.cpp
+++ b/src/qt/bitcoin.cpp
@@ -8,12 +8,14 @@
#include "bitcoingui.h"
+#include "chainparams.h"
#include "clientmodel.h"
#include "guiconstants.h"
#include "guiutil.h"
#include "intro.h"
#include "networkstyle.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "splashscreen.h"
#include "utilitydialog.h"
#include "winshutdownmonitor.h"
@@ -24,8 +26,8 @@
#endif
#include "init.h"
-#include "main.h"
#include "rpcserver.h"
+#include "scheduler.h"
#include "ui_interface.h"
#include "util.h"
@@ -47,6 +49,7 @@
#include <QThread>
#include <QTimer>
#include <QTranslator>
+#include <QSslConfiguration>
#if defined(QT_STATICPLUGIN)
#include <QtPlugin>
@@ -57,7 +60,9 @@ Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#else
+#if QT_VERSION < 0x050400
Q_IMPORT_PLUGIN(AccessibleFactory)
+#endif
#if defined(QT_QPA_PLATFORM_XCB)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin);
#elif defined(QT_QPA_PLATFORM_WINDOWS)
@@ -167,17 +172,18 @@ class BitcoinCore: public QObject
public:
explicit BitcoinCore();
-public slots:
+public Q_SLOTS:
void initialize();
void shutdown();
-signals:
+Q_SIGNALS:
void initializeResult(int retval);
void shutdownResult(int retval);
void runawayException(const QString &message);
private:
boost::thread_group threadGroup;
+ CScheduler scheduler;
/// Pass fatal exception message to UI thread
void handleRunawayException(const std::exception *e);
@@ -213,13 +219,13 @@ public:
/// Get window identifier of QMainWindow (BitcoinGUI)
WId getMainWinId() const;
-public slots:
+public Q_SLOTS:
void initializeResult(int retval);
void shutdownResult(int retval);
/// Handle runaway exceptions. Shows a message box with the problem and quits the program.
void handleRunawayException(const QString &message);
-signals:
+Q_SIGNALS:
void requestedInitialize();
void requestedShutdown();
void stopThread();
@@ -236,6 +242,7 @@ private:
WalletModel *walletModel;
#endif
int returnValue;
+ const PlatformStyle *platformStyle;
void startThread();
};
@@ -250,7 +257,7 @@ BitcoinCore::BitcoinCore():
void BitcoinCore::handleRunawayException(const std::exception *e)
{
PrintExceptionContinue(e, "Runaway exception");
- emit runawayException(QString::fromStdString(strMiscWarning));
+ Q_EMIT runawayException(QString::fromStdString(strMiscWarning));
}
void BitcoinCore::initialize()
@@ -258,15 +265,8 @@ void BitcoinCore::initialize()
try
{
qDebug() << __func__ << ": Running AppInit2 in thread";
- int rv = AppInit2(threadGroup);
- if(rv)
- {
- /* Start a dummy RPC thread if no RPC thread is active yet
- * to handle timeouts.
- */
- StartDummyRPCThread();
- }
- emit initializeResult(rv);
+ int rv = AppInit2(threadGroup, scheduler);
+ Q_EMIT initializeResult(rv);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
@@ -279,11 +279,11 @@ void BitcoinCore::shutdown()
try
{
qDebug() << __func__ << ": Running Shutdown in thread";
- threadGroup.interrupt_all();
+ Interrupt(threadGroup);
threadGroup.join_all();
Shutdown();
qDebug() << __func__ << ": Shutdown finished";
- emit shutdownResult(1);
+ Q_EMIT shutdownResult(1);
} catch (const std::exception& e) {
handleRunawayException(&e);
} catch (...) {
@@ -305,6 +305,22 @@ BitcoinApplication::BitcoinApplication(int &argc, char **argv):
returnValue(0)
{
setQuitOnLastWindowClosed(false);
+
+ // 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);
+ platformStyle = PlatformStyle::instantiate(QString::fromStdString(platformName));
+ if (!platformStyle) // Fall back to "other" if specified name not found
+ platformStyle = PlatformStyle::instantiate("other");
+ assert(platformStyle);
}
BitcoinApplication::~BitcoinApplication()
@@ -312,7 +328,7 @@ BitcoinApplication::~BitcoinApplication()
if(coreThread)
{
qDebug() << __func__ << ": Stopping thread";
- emit stopThread();
+ Q_EMIT stopThread();
coreThread->wait();
qDebug() << __func__ << ": Stopped thread";
}
@@ -325,6 +341,8 @@ BitcoinApplication::~BitcoinApplication()
#endif
delete optionsModel;
optionsModel = 0;
+ delete platformStyle;
+ platformStyle = 0;
}
#ifdef ENABLE_WALLET
@@ -341,7 +359,7 @@ void BitcoinApplication::createOptionsModel()
void BitcoinApplication::createWindow(const NetworkStyle *networkStyle)
{
- window = new BitcoinGUI(networkStyle, 0);
+ window = new BitcoinGUI(platformStyle, networkStyle, 0);
pollShutdownTimer = new QTimer(window);
connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown()));
@@ -383,7 +401,7 @@ void BitcoinApplication::requestInitialize()
{
qDebug() << __func__ << ": Requesting initialize";
startThread();
- emit requestedInitialize();
+ Q_EMIT requestedInitialize();
}
void BitcoinApplication::requestShutdown()
@@ -406,7 +424,7 @@ void BitcoinApplication::requestShutdown()
ShutdownWindow::showShutdownWindow(window);
// Request shutdown from core thread
- emit requestedShutdown();
+ Q_EMIT requestedShutdown();
}
void BitcoinApplication::initializeResult(int retval)
@@ -416,6 +434,8 @@ void BitcoinApplication::initializeResult(int retval)
returnValue = retval ? 0 : 1;
if(retval)
{
+ // Log this only after AppInit2 finishes, as then logging setup is guaranteed complete
+ qWarning() << "Platform customization:" << platformStyle->getName();
#ifdef ENABLE_WALLET
PaymentServer::LoadRootCAs();
paymentServer->setOptionsModel(optionsModel);
@@ -427,7 +447,7 @@ void BitcoinApplication::initializeResult(int retval)
#ifdef ENABLE_WALLET
if(pwalletMain)
{
- walletModel = new WalletModel(pwalletMain, optionsModel);
+ walletModel = new WalletModel(platformStyle, pwalletMain, optionsModel);
window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel);
window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET);
@@ -446,7 +466,7 @@ void BitcoinApplication::initializeResult(int retval)
{
window->show();
}
- emit splashFinished(window);
+ Q_EMIT splashFinished(window);
#ifdef ENABLE_WALLET
// Now that initialization/startup is done, process any command-line
@@ -513,6 +533,13 @@ int main(int argc, char *argv[])
#ifdef Q_OS_MAC
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
#endif
+#if QT_VERSION >= 0x050500
+ // Because of the POODLE attack it is recommended to disable SSLv3 (https://disablessl3.com/),
+ // so set SSL protocols to TLS1.0+.
+ QSslConfiguration sslconf = QSslConfiguration::defaultConfiguration();
+ sslconf.setProtocol(QSsl::TlsV1_0OrLater);
+ QSslConfiguration::setDefaultConfiguration(sslconf);
+#endif
// Register meta types used for QMetaObject::invokeMethod
qRegisterMetaType< bool* >();
diff --git a/src/qt/bitcoin.qrc b/src/qt/bitcoin.qrc
index 63af146fd0..c899e95506 100644
--- a/src/qt/bitcoin.qrc
+++ b/src/qt/bitcoin.qrc
@@ -45,6 +45,7 @@
<file alias="about">res/icons/about.png</file>
<file alias="about_qt">res/icons/about_qt.png</file>
<file alias="verify">res/icons/verify.png</file>
+ <file alias="warning">res/icons/warning.png</file>
</qresource>
<qresource prefix="/movies">
<file alias="spinner-000">res/movies/spinner-000.png</file>
diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp
index d31a1e018b..d19b9fd4af 100644
--- a/src/qt/bitcoinamountfield.cpp
+++ b/src/qt/bitcoinamountfield.cpp
@@ -61,7 +61,7 @@ public:
void setValue(const CAmount& value)
{
lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways));
- emit valueChanged();
+ Q_EMIT valueChanged();
}
void stepBy(int steps)
@@ -184,7 +184,7 @@ protected:
return rv;
}
-signals:
+Q_SIGNALS:
void valueChanged();
};
diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h
index b047e6c51a..3703b1f8d7 100644
--- a/src/qt/bitcoinamountfield.h
+++ b/src/qt/bitcoinamountfield.h
@@ -56,7 +56,7 @@ public:
*/
QWidget *setupTabChain(QWidget *prev);
-signals:
+Q_SIGNALS:
void valueChanged();
protected:
@@ -67,7 +67,7 @@ private:
AmountSpinBox *amount;
QValueComboBox *unit;
-private slots:
+private Q_SLOTS:
void unitChanged(int idx);
};
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index 70bf894599..db9e558764 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -13,8 +13,8 @@
#include "openuridialog.h"
#include "optionsdialog.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "rpcconsole.h"
-#include "scicon.h"
#include "utilitydialog.h"
#ifdef ENABLE_WALLET
@@ -60,7 +60,7 @@
const QString BitcoinGUI::DEFAULT_WALLET = "~Default";
-BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
+BitcoinGUI::BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent) :
QMainWindow(parent),
clientModel(0),
walletFrame(0),
@@ -97,8 +97,10 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
trayIconMenu(0),
notificator(0),
rpcConsole(0),
+ helpMessageDialog(0),
prevBlocks(0),
- spinnerFrame(0)
+ spinnerFrame(0),
+ platformStyle(platformStyle)
{
GUIUtil::restoreWindowGeometry("nWindow", QSize(850, 550), this);
@@ -130,12 +132,13 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
setUnifiedTitleAndToolBarOnMac(true);
#endif
- rpcConsole = new RPCConsole(0);
+ rpcConsole = new RPCConsole(platformStyle, 0);
+ helpMessageDialog = new HelpMessageDialog(this, false);
#ifdef ENABLE_WALLET
if(enableWallet)
{
/** Create wallet frame and make it the central widget */
- walletFrame = new WalletFrame(this);
+ walletFrame = new WalletFrame(platformStyle, this);
setCentralWidget(walletFrame);
} else
#endif // ENABLE_WALLET
@@ -175,7 +178,7 @@ BitcoinGUI::BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent) :
QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocksLayout->setContentsMargins(3,0,3,0);
frameBlocksLayout->setSpacing(3);
- unitDisplayControl = new UnitDisplayStatusBarControl();
+ unitDisplayControl = new UnitDisplayStatusBarControl(platformStyle);
labelEncryptionIcon = new QLabel();
labelConnectionsIcon = new QLabel();
labelBlocksIcon = new QLabel();
@@ -247,36 +250,36 @@ void BitcoinGUI::createActions()
{
QActionGroup *tabGroup = new QActionGroup(this);
- overviewAction = new QAction(SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
+ overviewAction = new QAction(platformStyle->SingleColorIcon(":/icons/overview"), tr("&Overview"), this);
overviewAction->setStatusTip(tr("Show general overview of wallet"));
overviewAction->setToolTip(overviewAction->statusTip());
overviewAction->setCheckable(true);
overviewAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_1));
tabGroup->addAction(overviewAction);
- sendCoinsAction = new QAction(SingleColorIcon(":/icons/send"), tr("&Send"), this);
+ sendCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/send"), tr("&Send"), this);
sendCoinsAction->setStatusTip(tr("Send coins to a Bitcoin address"));
sendCoinsAction->setToolTip(sendCoinsAction->statusTip());
sendCoinsAction->setCheckable(true);
sendCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_2));
tabGroup->addAction(sendCoinsAction);
- sendCoinsMenuAction = new QAction(TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
+ sendCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/send"), sendCoinsAction->text(), this);
sendCoinsMenuAction->setStatusTip(sendCoinsAction->statusTip());
sendCoinsMenuAction->setToolTip(sendCoinsMenuAction->statusTip());
- receiveCoinsAction = new QAction(SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
+ receiveCoinsAction = new QAction(platformStyle->SingleColorIcon(":/icons/receiving_addresses"), tr("&Receive"), this);
receiveCoinsAction->setStatusTip(tr("Request payments (generates QR codes and bitcoin: URIs)"));
receiveCoinsAction->setToolTip(receiveCoinsAction->statusTip());
receiveCoinsAction->setCheckable(true);
receiveCoinsAction->setShortcut(QKeySequence(Qt::ALT + Qt::Key_3));
tabGroup->addAction(receiveCoinsAction);
- receiveCoinsMenuAction = new QAction(TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
+ receiveCoinsMenuAction = new QAction(platformStyle->TextColorIcon(":/icons/receiving_addresses"), receiveCoinsAction->text(), this);
receiveCoinsMenuAction->setStatusTip(receiveCoinsAction->statusTip());
receiveCoinsMenuAction->setToolTip(receiveCoinsMenuAction->statusTip());
- historyAction = new QAction(SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
+ historyAction = new QAction(platformStyle->SingleColorIcon(":/icons/history"), tr("&Transactions"), this);
historyAction->setStatusTip(tr("Browse transaction history"));
historyAction->setToolTip(historyAction->statusTip());
historyAction->setCheckable(true);
@@ -300,46 +303,46 @@ void BitcoinGUI::createActions()
connect(historyAction, SIGNAL(triggered()), this, SLOT(gotoHistoryPage()));
#endif // ENABLE_WALLET
- quitAction = new QAction(TextColorIcon(":/icons/quit"), tr("E&xit"), this);
+ quitAction = new QAction(platformStyle->TextColorIcon(":/icons/quit"), tr("E&xit"), this);
quitAction->setStatusTip(tr("Quit application"));
quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
quitAction->setMenuRole(QAction::QuitRole);
- aboutAction = new QAction(TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this);
+ aboutAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&About Bitcoin Core"), this);
aboutAction->setStatusTip(tr("Show information about Bitcoin Core"));
aboutAction->setMenuRole(QAction::AboutRole);
- aboutQtAction = new QAction(TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
+ aboutQtAction = new QAction(platformStyle->TextColorIcon(":/icons/about_qt"), tr("About &Qt"), this);
aboutQtAction->setStatusTip(tr("Show information about Qt"));
aboutQtAction->setMenuRole(QAction::AboutQtRole);
- optionsAction = new QAction(TextColorIcon(":/icons/options"), tr("&Options..."), this);
+ optionsAction = new QAction(platformStyle->TextColorIcon(":/icons/options"), tr("&Options..."), this);
optionsAction->setStatusTip(tr("Modify configuration options for Bitcoin Core"));
optionsAction->setMenuRole(QAction::PreferencesRole);
- toggleHideAction = new QAction(TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
+ toggleHideAction = new QAction(platformStyle->TextColorIcon(":/icons/about"), tr("&Show / Hide"), this);
toggleHideAction->setStatusTip(tr("Show or hide the main Window"));
- encryptWalletAction = new QAction(TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
+ encryptWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/lock_closed"), tr("&Encrypt Wallet..."), this);
encryptWalletAction->setStatusTip(tr("Encrypt the private keys that belong to your wallet"));
encryptWalletAction->setCheckable(true);
- backupWalletAction = new QAction(TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
+ backupWalletAction = new QAction(platformStyle->TextColorIcon(":/icons/filesave"), tr("&Backup Wallet..."), this);
backupWalletAction->setStatusTip(tr("Backup wallet to another location"));
- changePassphraseAction = new QAction(TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
+ changePassphraseAction = new QAction(platformStyle->TextColorIcon(":/icons/key"), tr("&Change Passphrase..."), this);
changePassphraseAction->setStatusTip(tr("Change the passphrase used for wallet encryption"));
- signMessageAction = new QAction(TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
+ signMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/edit"), tr("Sign &message..."), this);
signMessageAction->setStatusTip(tr("Sign messages with your Bitcoin addresses to prove you own them"));
- verifyMessageAction = new QAction(TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
+ verifyMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/verify"), tr("&Verify message..."), this);
verifyMessageAction->setStatusTip(tr("Verify messages to ensure they were signed with specified Bitcoin addresses"));
- openRPCConsoleAction = new QAction(TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
+ openRPCConsoleAction = new QAction(platformStyle->TextColorIcon(":/icons/debugwindow"), tr("&Debug window"), this);
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
- usedSendingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
+ usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses..."), this);
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
- usedReceivingAddressesAction = new QAction(TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
+ usedReceivingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Receiving addresses..."), this);
usedReceivingAddressesAction->setStatusTip(tr("Show the list of used receiving addresses and labels"));
- openAction = new QAction(TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
+ openAction = new QAction(platformStyle->TextColorIcon(":/icons/open"), tr("Open &URI..."), this);
openAction->setStatusTip(tr("Open a bitcoin: URI or payment request"));
- showHelpMessageAction = new QAction(TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
+ showHelpMessageAction = new QAction(platformStyle->TextColorIcon(":/icons/info"), tr("&Command-line options"), this);
showHelpMessageAction->setMenuRole(QAction::NoRole);
showHelpMessageAction->setStatusTip(tr("Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options"));
@@ -414,6 +417,7 @@ void BitcoinGUI::createToolBars()
if(walletFrame)
{
QToolBar *toolbar = addToolBar(tr("Tabs toolbar"));
+ toolbar->setMovable(false);
toolbar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolbar->addAction(overviewAction);
toolbar->addAction(sendCoinsAction);
@@ -588,9 +592,7 @@ void BitcoinGUI::aboutClicked()
void BitcoinGUI::showHelpMessageClicked()
{
- HelpMessageDialog *help = new HelpMessageDialog(this, false);
- help->setAttribute(Qt::WA_DeleteOnClose);
- help->show();
+ helpMessageDialog->show();
}
#ifdef ENABLE_WALLET
@@ -599,7 +601,7 @@ void BitcoinGUI::openClicked()
OpenURIDialog dlg(this);
if(dlg.exec())
{
- emit receivedURI(dlg.getURI());
+ Q_EMIT receivedURI(dlg.getURI());
}
}
@@ -649,7 +651,7 @@ void BitcoinGUI::setNumConnections(int count)
case 7: case 8: case 9: icon = ":/icons/connect_3"; break;
default: icon = ":/icons/connect_4"; break;
}
- labelConnectionsIcon->setPixmap(SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelConnectionsIcon->setPixmap(platformStyle->SingleColorIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelConnectionsIcon->setToolTip(tr("%n active connection(s) to Bitcoin network", "", count));
}
@@ -690,7 +692,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
if(secs < 90*60)
{
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
- labelBlocksIcon->setPixmap(SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
+ labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/synced").pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
#ifdef ENABLE_WALLET
if(walletFrame)
@@ -736,7 +738,7 @@ void BitcoinGUI::setNumBlocks(int count, const QDateTime& blockDate)
tooltip = tr("Catching up...") + QString("<br>") + tooltip;
if(count != prevBlocks)
{
- labelBlocksIcon->setPixmap(SingleColorIcon(QString(
+ labelBlocksIcon->setPixmap(platformStyle->SingleColorIcon(QString(
":/movies/spinner-%1").arg(spinnerFrame, 3, 10, QChar('0')))
.pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES;
@@ -885,9 +887,9 @@ void BitcoinGUI::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls())
{
- foreach(const QUrl &uri, event->mimeData()->urls())
+ Q_FOREACH(const QUrl &uri, event->mimeData()->urls())
{
- emit receivedURI(uri.toString());
+ Q_EMIT receivedURI(uri.toString());
}
}
event->acceptProposedAction();
@@ -930,7 +932,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
case WalletModel::Unlocked:
labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_open").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>unlocked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
@@ -938,7 +940,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
case WalletModel::Locked:
labelEncryptionIcon->show();
- labelEncryptionIcon->setPixmap(SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
+ labelEncryptionIcon->setPixmap(platformStyle->SingleColorIcon(":/icons/lock_closed").pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
@@ -1040,7 +1042,7 @@ void BitcoinGUI::unsubscribeFromCoreSignals()
uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3));
}
-UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
+UnitDisplayStatusBarControl::UnitDisplayStatusBarControl(const PlatformStyle *platformStyle) :
optionsModel(0),
menu(0)
{
@@ -1049,13 +1051,13 @@ UnitDisplayStatusBarControl::UnitDisplayStatusBarControl() :
QList<BitcoinUnits::Unit> units = BitcoinUnits::availableUnits();
int max_width = 0;
const QFontMetrics fm(font());
- foreach (const BitcoinUnits::Unit unit, units)
+ Q_FOREACH (const BitcoinUnits::Unit unit, units)
{
max_width = qMax(max_width, fm.width(BitcoinUnits::name(unit)));
}
setMinimumSize(max_width, 0);
setAlignment(Qt::AlignRight | Qt::AlignVCenter);
- setStyleSheet(QString("QLabel { color : %1 }").arg(SingleColor().name()));
+ setStyleSheet(QString("QLabel { color : %1 }").arg(platformStyle->SingleColor().name()));
}
/** So that it responds to button clicks */
@@ -1068,7 +1070,7 @@ void UnitDisplayStatusBarControl::mousePressEvent(QMouseEvent *event)
void UnitDisplayStatusBarControl::createContextMenu()
{
menu = new QMenu();
- foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
QAction *menuAction = new QAction(QString(BitcoinUnits::name(u)), this);
menuAction->setData(QVariant(u));
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 494541f002..f1b7a502ba 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -22,11 +22,13 @@ class ClientModel;
class NetworkStyle;
class Notificator;
class OptionsModel;
+class PlatformStyle;
class RPCConsole;
class SendCoinsRecipient;
class UnitDisplayStatusBarControl;
class WalletFrame;
class WalletModel;
+class HelpMessageDialog;
class CWallet;
@@ -47,7 +49,7 @@ class BitcoinGUI : public QMainWindow
public:
static const QString DEFAULT_WALLET;
- explicit BitcoinGUI(const NetworkStyle *networkStyle, QWidget *parent = 0);
+ explicit BitcoinGUI(const PlatformStyle *platformStyle, const NetworkStyle *networkStyle, QWidget *parent = 0);
~BitcoinGUI();
/** Set the client model.
@@ -112,11 +114,14 @@ private:
QMenu *trayIconMenu;
Notificator *notificator;
RPCConsole *rpcConsole;
+ HelpMessageDialog *helpMessageDialog;
/** Keep track of previous number of blocks, to detect progress */
int prevBlocks;
int spinnerFrame;
+ const PlatformStyle *platformStyle;
+
/** Create the main UI actions. */
void createActions();
/** Create the menu bar and sub-menus. */
@@ -136,11 +141,11 @@ private:
/** Disconnect core signals from GUI client */
void unsubscribeFromCoreSignals();
-signals:
+Q_SIGNALS:
/** Signal raised when a URI was entered or dragged to the GUI */
void receivedURI(const QString &uri);
-public slots:
+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 */
@@ -168,7 +173,7 @@ public slots:
void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address, const QString& label);
#endif // ENABLE_WALLET
-private slots:
+private Q_SLOTS:
#ifdef ENABLE_WALLET
/** Switch to overview (home) page */
void gotoOverviewPage();
@@ -215,7 +220,7 @@ class UnitDisplayStatusBarControl : public QLabel
Q_OBJECT
public:
- explicit UnitDisplayStatusBarControl();
+ explicit UnitDisplayStatusBarControl(const PlatformStyle *platformStyle);
/** Lets the control know about the Options Model (and its signals) */
void setOptionsModel(OptionsModel *optionsModel);
@@ -232,7 +237,7 @@ private:
/** Creates context menu, its actions, and wires up all the relevant signals for mouse events. */
void createContextMenu();
-private slots:
+private Q_SLOTS:
/** When Display Units are changed on OptionsModel it will refresh the display text of the control on the status bar */
void updateDisplayUnit(int newUnits);
/** Tells underlying optionsModel to update its current display unit. */
diff --git a/src/qt/bitcoinstrings.cpp b/src/qt/bitcoinstrings.cpp
index d14343717a..b259d038f2 100644
--- a/src/qt/bitcoinstrings.cpp
+++ b/src/qt/bitcoinstrings.cpp
@@ -275,6 +275,7 @@ QT_TRANSLATE_NOOP("bitcoin-core", "RPC server options:"),
QT_TRANSLATE_NOOP("bitcoin-core", "RPC support for HTTP persistent connections (default: %d)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly drop 1 of every <n> network messages"),
QT_TRANSLATE_NOOP("bitcoin-core", "Randomly fuzz 1 of every <n> network messages"),
+QT_TRANSLATE_NOOP("bitcoin-core", "Rebuild block chain index from current blk000??.dat files on startup"),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay and mine data carrier transactions (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Relay non-P2SH multisig (default: %u)"),
QT_TRANSLATE_NOOP("bitcoin-core", "Rescan the block chain for missing wallet transactions"),
diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp
index 8e29cdeb06..0900a35cc4 100644
--- a/src/qt/clientmodel.cpp
+++ b/src/qt/clientmodel.cpp
@@ -4,6 +4,7 @@
#include "clientmodel.h"
+#include "bantablemodel.h"
#include "guiconstants.h"
#include "peertablemodel.h"
@@ -11,7 +12,6 @@
#include "chainparams.h"
#include "checkpoints.h"
#include "clientversion.h"
-#include "main.h"
#include "net.h"
#include "ui_interface.h"
#include "util.h"
@@ -27,6 +27,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
QObject(parent),
optionsModel(optionsModel),
peerTableModel(0),
+ banTableModel(0),
cachedNumBlocks(0),
cachedBlockDate(QDateTime()),
cachedReindexing(0),
@@ -34,6 +35,7 @@ ClientModel::ClientModel(OptionsModel *optionsModel, QObject *parent) :
pollTimer(0)
{
peerTableModel = new PeerTableModel(this);
+ banTableModel = new BanTableModel(this);
pollTimer = new QTimer(this);
connect(pollTimer, SIGNAL(timeout()), this, SLOT(updateTimer()));
pollTimer->start(MODEL_UPDATE_DELAY);
@@ -53,9 +55,9 @@ int ClientModel::getNumConnections(unsigned int flags) const
return vNodes.size();
int nNum = 0;
- BOOST_FOREACH(CNode* pnode, vNodes)
- if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
- nNum++;
+ BOOST_FOREACH(const CNode* pnode, vNodes)
+ if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT))
+ nNum++;
return nNum;
}
@@ -117,15 +119,15 @@ void ClientModel::updateTimer()
cachedReindexing = fReindex;
cachedImporting = fImporting;
- emit numBlocksChanged(newNumBlocks, newBlockDate);
+ Q_EMIT numBlocksChanged(newNumBlocks, newBlockDate);
}
- emit bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
+ Q_EMIT bytesChanged(getTotalBytesRecv(), getTotalBytesSent());
}
void ClientModel::updateNumConnections(int numConnections)
{
- emit numConnectionsChanged(numConnections);
+ Q_EMIT numConnectionsChanged(numConnections);
}
void ClientModel::updateAlert(const QString &hash, int status)
@@ -138,11 +140,11 @@ void ClientModel::updateAlert(const QString &hash, int status)
CAlert alert = CAlert::getAlertByHash(hash_256);
if(!alert.IsNull())
{
- emit message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
+ Q_EMIT message(tr("Network Alert"), QString::fromStdString(alert.strStatusBar), CClientUIInterface::ICON_ERROR);
}
}
- emit alertsChanged(getStatusBarWarnings());
+ Q_EMIT alertsChanged(getStatusBarWarnings());
}
bool ClientModel::inInitialBlockDownload() const
@@ -177,11 +179,21 @@ PeerTableModel *ClientModel::getPeerTableModel()
return peerTableModel;
}
+BanTableModel *ClientModel::getBanTableModel()
+{
+ return banTableModel;
+}
+
QString ClientModel::formatFullVersion() const
{
return QString::fromStdString(FormatFullVersion());
}
+QString ClientModel::formatSubVersion() const
+{
+ return QString::fromStdString(strSubVersion);
+}
+
QString ClientModel::formatBuildDate() const
{
return QString::fromStdString(CLIENT_DATE);
@@ -202,6 +214,11 @@ QString ClientModel::formatClientStartupTime() const
return QDateTime::fromTime_t(nClientStartupTime).toString();
}
+void ClientModel::updateBanlist()
+{
+ banTableModel->refresh();
+}
+
// Handlers for core signals
static void ShowProgress(ClientModel *clientmodel, const std::string &title, int nProgress)
{
@@ -226,12 +243,19 @@ static void NotifyAlertChanged(ClientModel *clientmodel, const uint256 &hash, Ch
Q_ARG(int, status));
}
+static void BannedListChanged(ClientModel *clientmodel)
+{
+ qDebug() << QString("%1: Requesting update for peer banlist").arg(__func__);
+ QMetaObject::invokeMethod(clientmodel, "updateBanlist", Qt::QueuedConnection);
+}
+
void ClientModel::subscribeToCoreSignals()
{
// Connect signals to client
uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.connect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.connect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.BannedListChanged.connect(boost::bind(BannedListChanged, this));
}
void ClientModel::unsubscribeFromCoreSignals()
@@ -240,4 +264,5 @@ void ClientModel::unsubscribeFromCoreSignals()
uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2));
uiInterface.NotifyNumConnectionsChanged.disconnect(boost::bind(NotifyNumConnectionsChanged, this, _1));
uiInterface.NotifyAlertChanged.disconnect(boost::bind(NotifyAlertChanged, this, _1, _2));
+ uiInterface.BannedListChanged.disconnect(boost::bind(BannedListChanged, this));
}
diff --git a/src/qt/clientmodel.h b/src/qt/clientmodel.h
index 214701810c..627bdf862d 100644
--- a/src/qt/clientmodel.h
+++ b/src/qt/clientmodel.h
@@ -9,6 +9,7 @@
#include <QDateTime>
class AddressTableModel;
+class BanTableModel;
class OptionsModel;
class PeerTableModel;
class TransactionTableModel;
@@ -44,6 +45,7 @@ public:
OptionsModel *getOptionsModel();
PeerTableModel *getPeerTableModel();
+ BanTableModel *getBanTableModel();
//! Return number of connections, default is in- and outbound (total)
int getNumConnections(unsigned int flags = CONNECTIONS_ALL) const;
@@ -63,6 +65,7 @@ public:
QString getStatusBarWarnings() const;
QString formatFullVersion() const;
+ QString formatSubVersion() const;
QString formatBuildDate() const;
bool isReleaseVersion() const;
QString clientName() const;
@@ -71,6 +74,7 @@ public:
private:
OptionsModel *optionsModel;
PeerTableModel *peerTableModel;
+ BanTableModel *banTableModel;
int cachedNumBlocks;
QDateTime cachedBlockDate;
@@ -82,7 +86,7 @@ private:
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
-signals:
+Q_SIGNALS:
void numConnectionsChanged(int count);
void numBlocksChanged(int count, const QDateTime& blockDate);
void alertsChanged(const QString &warnings);
@@ -94,10 +98,11 @@ signals:
// Show progress dialog e.g. for verifychain
void showProgress(const QString &title, int nProgress);
-public slots:
+public Q_SLOTS:
void updateTimer();
void updateNumConnections(int numConnections);
void updateAlert(const QString &hash, int status);
+ void updateBanlist();
};
#endif // BITCOIN_QT_CLIENTMODEL_H
diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp
index 7531fbddcb..51008ad2de 100644
--- a/src/qt/coincontroldialog.cpp
+++ b/src/qt/coincontroldialog.cpp
@@ -9,12 +9,13 @@
#include "bitcoinunits.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
+#include "txmempool.h"
#include "walletmodel.h"
#include "coincontrol.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "wallet/wallet.h"
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
@@ -30,15 +31,15 @@
#include <QTreeWidget>
#include <QTreeWidgetItem>
-using namespace std;
QList<CAmount> CoinControlDialog::payAmounts;
CCoinControl* CoinControlDialog::coinControl = new CCoinControl();
bool CoinControlDialog::fSubtractFeeFromAmount = false;
-CoinControlDialog::CoinControlDialog(QWidget *parent) :
+CoinControlDialog::CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::CoinControlDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
@@ -118,7 +119,7 @@ CoinControlDialog::CoinControlDialog(QWidget *parent) :
// (un)select all
connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked()));
- // change coin control first column label due Qt4 bug.
+ // change coin control first column label due Qt4 bug.
// see https://github.com/bitcoin/bitcoin/issues/5716
ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString());
@@ -280,7 +281,7 @@ void CoinControlDialog::lockCoin()
COutPoint outpt(uint256S(contextMenuItem->text(COLUMN_TXHASH).toStdString()), contextMenuItem->text(COLUMN_VOUT_INDEX).toUInt());
model->lockCoin(outpt);
contextMenuItem->setDisabled(true);
- contextMenuItem->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed"));
+ contextMenuItem->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
updateLabelLocked();
}
@@ -442,7 +443,7 @@ QString CoinControlDialog::getPriorityLabel(double dPriority, double mempoolEsti
// shows count of locked unspent outputs
void CoinControlDialog::updateLabelLocked()
{
- vector<COutPoint> vOutpts;
+ std::vector<COutPoint> vOutpts;
model->listLockedCoins(vOutpts);
if (vOutpts.size() > 0)
{
@@ -461,13 +462,13 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
CAmount nPayAmount = 0;
bool fDust = false;
CMutableTransaction txDummy;
- foreach(const CAmount &amount, CoinControlDialog::payAmounts)
+ Q_FOREACH(const CAmount &amount, CoinControlDialog::payAmounts)
{
nPayAmount += amount;
if (amount > 0)
{
- CTxOut txout(amount, (CScript)vector<unsigned char>(24, 0));
+ CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout);
if (txout.IsDust(::minRelayTxFee))
fDust = true;
@@ -487,13 +488,12 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
int nQuantityUncompressed = 0;
bool fAllowFree = false;
- vector<COutPoint> vCoinControl;
- vector<COutput> vOutputs;
+ std::vector<COutPoint> vCoinControl;
+ std::vector<COutput> vOutputs;
coinControl->ListSelected(vCoinControl);
model->getOutputs(vCoinControl, vOutputs);
- BOOST_FOREACH(const COutput& out, vOutputs)
- {
+ BOOST_FOREACH(const COutput& out, vOutputs) {
// unselect already spent, very unlikely scenario, this could happen
// when selected are spent elsewhere, like rpc or another computer
uint256 txhash = out.tx->GetHash();
@@ -569,7 +569,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
// Never create dust outputs; if we would, just add the dust to the fee.
if (nChange > 0 && nChange < CENT)
{
- CTxOut txout(nChange, (CScript)vector<unsigned char>(24, 0));
+ CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
if (txout.IsDust(::minRelayTxFee))
{
if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
@@ -688,11 +688,10 @@ void CoinControlDialog::updateView()
int nDisplayUnit = model->getOptionsModel()->getDisplayUnit();
double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget);
- map<QString, vector<COutput> > mapCoins;
+ std::map<QString, std::vector<COutput> > mapCoins;
model->listCoins(mapCoins);
- BOOST_FOREACH(PAIRTYPE(QString, vector<COutput>) coins, mapCoins)
- {
+ BOOST_FOREACH(const PAIRTYPE(QString, std::vector<COutput>)& coins, mapCoins) {
QTreeWidgetItem *itemWalletAddress = new QTreeWidgetItem();
itemWalletAddress->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked);
QString sWalletAddress = coins.first;
@@ -719,8 +718,7 @@ void CoinControlDialog::updateView()
double dPrioritySum = 0;
int nChildren = 0;
int nInputSum = 0;
- BOOST_FOREACH(const COutput& out, coins.second)
- {
+ BOOST_FOREACH(const COutput& out, coins.second) {
int nInputSize = 0;
nSum += out.tx->vout[out.i].nValue;
nChildren++;
@@ -794,7 +792,7 @@ void CoinControlDialog::updateView()
COutPoint outpt(txhash, out.i);
coinControl->UnSelect(outpt); // just to be sure
itemOutput->setDisabled(true);
- itemOutput->setIcon(COLUMN_CHECKBOX, SingleColorIcon(":/icons/lock_closed"));
+ itemOutput->setIcon(COLUMN_CHECKBOX, platformStyle->SingleColorIcon(":/icons/lock_closed"));
}
// set checkbox
diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h
index 5ec382838f..8ff1eac709 100644
--- a/src/qt/coincontroldialog.h
+++ b/src/qt/coincontroldialog.h
@@ -16,6 +16,7 @@
#include <QString>
#include <QTreeWidgetItem>
+class PlatformStyle;
class WalletModel;
class CCoinControl;
@@ -32,7 +33,7 @@ class CoinControlDialog : public QDialog
Q_OBJECT
public:
- explicit CoinControlDialog(QWidget *parent = 0);
+ explicit CoinControlDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~CoinControlDialog();
void setModel(WalletModel *model);
@@ -57,6 +58,8 @@ private:
QAction *lockAction;
QAction *unlockAction;
+ const PlatformStyle *platformStyle;
+
QString strPad(QString, int, QString);
void sortView(int, Qt::SortOrder);
void updateView();
@@ -102,7 +105,7 @@ private:
return column;
}
-private slots:
+private Q_SLOTS:
void showMenu(const QPoint &);
void copyAmount();
void copyLabel();
diff --git a/src/qt/editaddressdialog.h b/src/qt/editaddressdialog.h
index 13c6da8eda..d59fce2d41 100644
--- a/src/qt/editaddressdialog.h
+++ b/src/qt/editaddressdialog.h
@@ -40,7 +40,7 @@ public:
QString getAddress() const;
void setAddress(const QString &address);
-public slots:
+public Q_SLOTS:
void accept();
private:
diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 55c4f5ac58..22c67b8040 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>560</width>
- <height>400</height>
+ <height>440</height>
</rect>
</property>
<property name="windowTitle">
@@ -298,6 +298,193 @@
</layout>
</item>
<item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2_Network">
+ <item>
+ <widget class="QLabel" name="proxyActiveNets">
+ <property name="text">
+ <string>Used for reaching peers via:</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="proxyReachIPv4">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="proxyReachIPv4Label">
+ <property name="text">
+ <string>IPv4</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="proxyReachIPv6">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="proxyReachIPv6Label">
+ <property name="text">
+ <string>IPv6</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="proxyReachTor">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip">
+ <string>Shows, if the supplied default SOCKS5 proxy is used to reach peers via this network type.</string>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="proxyReachTorLabel">
+ <property name="text">
+ <string>Tor</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2_Network">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="connectSocksTor">
+ <property name="toolTip">
+ <string>Connect to the Bitcoin network through a separate SOCKS5 proxy for Tor hidden services.</string>
+ </property>
+ <property name="text">
+ <string>Use separate SOCKS5 proxy to reach peers via Tor hidden services:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3_Network">
+ <item>
+ <widget class="QLabel" name="proxyIpTorLabel">
+ <property name="text">
+ <string>Proxy &amp;IP:</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="buddy">
+ <cstring>proxyIpTor</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QValidatedLineEdit" name="proxyIpTor">
+ <property name="minimumSize">
+ <size>
+ <width>140</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>140</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="proxyPortTorLabel">
+ <property name="text">
+ <string>&amp;Port:</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="buddy">
+ <cstring>proxyPortTor</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="proxyPortTor">
+ <property name="minimumSize">
+ <size>
+ <width>55</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>55</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="toolTip">
+ <string>Port of the proxy (e.g. 9050)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4_Network">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
<spacer name="verticalSpacer_Network">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui
index 53d416ef38..6d792d1475 100644
--- a/src/qt/forms/overviewpage.ui
+++ b/src/qt/forms/overviewpage.ui
@@ -59,21 +59,35 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="labelWalletStatus">
- <property name="cursor">
- <cursorShape>WhatsThisCursor</cursorShape>
+ <widget class="QPushButton" name="labelWalletStatus">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>16777215</height>
+ </size>
</property>
<property name="toolTip">
<string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
</property>
- <property name="styleSheet">
- <string notr="true">QLabel { color: red; }</string>
- </property>
<property name="text">
- <string notr="true">(out of sync)</string>
+ <string/>
</property>
- <property name="alignment">
- <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/warning</normaloff>
+ <disabledoff>:/icons/warning</disabledoff>:/icons/warning</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>24</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
</property>
</widget>
</item>
@@ -431,21 +445,35 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="labelTransactionsStatus">
- <property name="cursor">
- <cursorShape>WhatsThisCursor</cursorShape>
+ <widget class="QPushButton" name="labelTransactionsStatus">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>30</width>
+ <height>16777215</height>
+ </size>
</property>
<property name="toolTip">
<string>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</string>
</property>
- <property name="styleSheet">
- <string notr="true">QLabel { color: red; }</string>
- </property>
<property name="text">
- <string notr="true">(out of sync)</string>
+ <string/>
</property>
- <property name="alignment">
- <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ <property name="icon">
+ <iconset resource="../bitcoin.qrc">
+ <normaloff>:/icons/warning</normaloff>
+ <disabledoff>:/icons/warning</disabledoff>:/icons/warning</iconset>
+ </property>
+ <property name="iconSize">
+ <size>
+ <width>24</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
</property>
</widget>
</item>
diff --git a/src/qt/forms/rpcconsole.ui b/src/qt/forms/rpcconsole.ui
index c1eb185501..4117da57f5 100644
--- a/src/qt/forms/rpcconsole.ui
+++ b/src/qt/forms/rpcconsole.ui
@@ -87,6 +87,32 @@
</widget>
</item>
<item row="3" column="0">
+ <widget class="QLabel" name="labelClientUserAgent">
+ <property name="text">
+ <string>User Agent</string>
+ </property>
+ <property name="indent">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLabel" name="clientUserAgent">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
<widget class="QLabel" name="label_14">
<property name="text">
<string>Using OpenSSL version</string>
@@ -96,7 +122,7 @@
</property>
</widget>
</item>
- <item row="3" column="1">
+ <item row="4" column="1">
<widget class="QLabel" name="openSSLVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -112,7 +138,7 @@
</property>
</widget>
</item>
- <item row="4" column="0">
+ <item row="5" column="0">
<widget class="QLabel" name="label_berkeleyDBVersion">
<property name="text">
<string>Using BerkeleyDB version</string>
@@ -122,7 +148,7 @@
</property>
</widget>
</item>
- <item row="4" column="1">
+ <item row="5" column="1">
<widget class="QLabel" name="berkeleyDBVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -138,14 +164,14 @@
</property>
</widget>
</item>
- <item row="5" column="0">
+ <item row="6" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Build date</string>
</property>
</widget>
</item>
- <item row="5" column="1">
+ <item row="6" column="1">
<widget class="QLabel" name="buildDate">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -161,14 +187,14 @@
</property>
</widget>
</item>
- <item row="6" column="0">
+ <item row="7" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Startup time</string>
</property>
</widget>
</item>
- <item row="6" column="1">
+ <item row="7" column="1">
<widget class="QLabel" name="startupTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -184,7 +210,7 @@
</property>
</widget>
</item>
- <item row="7" column="0">
+ <item row="8" column="0">
<widget class="QLabel" name="label_11">
<property name="font">
<font>
@@ -197,14 +223,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
- <item row="8" column="1">
+ <item row="9" column="1">
<widget class="QLabel" name="networkName">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -220,14 +246,14 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Number of connections</string>
</property>
</widget>
</item>
- <item row="9" column="1">
+ <item row="10" column="1">
<widget class="QLabel" name="numberOfConnections">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -243,7 +269,7 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_10">
<property name="font">
<font>
@@ -256,14 +282,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Current number of blocks</string>
</property>
</widget>
</item>
- <item row="11" column="1">
+ <item row="12" column="1">
<widget class="QLabel" name="numberOfBlocks">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -279,14 +305,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Last block time</string>
</property>
</widget>
</item>
- <item row="12" column="1">
+ <item row="13" column="1">
<widget class="QLabel" name="lastBlockTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -302,7 +328,7 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -315,7 +341,7 @@
</property>
</spacer>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
<widget class="QLabel" name="labelDebugLogfile">
<property name="font">
<font>
@@ -328,7 +354,7 @@
</property>
</widget>
</item>
- <item row="15" column="0">
+ <item row="16" column="0">
<widget class="QPushButton" name="openDebugLogfileButton">
<property name="toolTip">
<string>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</string>
@@ -341,7 +367,7 @@
</property>
</widget>
</item>
- <item row="16" column="0">
+ <item row="17" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -687,17 +713,85 @@
</attribute>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" rowspan="2">
- <widget class="QTableView" name="peerWidget">
- <property name="horizontalScrollBarPolicy">
- <enum>Qt::ScrollBarAsNeeded</enum>
- </property>
- <property name="sortingEnabled">
- <bool>true</bool>
+ <layout class="QVBoxLayout" name="verticalLayout_101">
+ <property name="spacing">
+ <number>0</number>
</property>
- <attribute name="horizontalHeaderHighlightSections">
- <bool>false</bool>
- </attribute>
- </widget>
+ <item>
+ <widget class="QTableView" name="peerWidget">
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="banHeading">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>300</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>12</pointsize>
+ </font>
+ </property>
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>Banned peers</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::NoTextInteraction</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTableView" name="banlistWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="horizontalScrollBarPolicy">
+ <enum>Qt::ScrollBarAsNeeded</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
</item>
<item row="0" column="1">
<widget class="QLabel" name="peerHeading">
@@ -745,13 +839,36 @@
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
+ <widget class="QLabel" name="label_30">
+ <property name="text">
+ <string>Whitelisted</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QLabel" name="peerWhitelisted">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
<widget class="QLabel" name="label_23">
<property name="text">
<string>Direction</string>
</property>
</widget>
</item>
- <item row="0" column="2">
+ <item row="1" column="2">
<widget class="QLabel" name="peerDirection">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -767,14 +884,14 @@
</property>
</widget>
</item>
- <item row="1" column="0">
+ <item row="2" column="0">
<widget class="QLabel" name="label_21">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
- <item row="1" column="2">
+ <item row="2" column="2">
<widget class="QLabel" name="peerVersion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -790,14 +907,14 @@
</property>
</widget>
</item>
- <item row="2" column="0">
+ <item row="3" column="0">
<widget class="QLabel" name="label_28">
<property name="text">
<string>User Agent</string>
</property>
</widget>
</item>
- <item row="2" column="2">
+ <item row="3" column="2">
<widget class="QLabel" name="peerSubversion">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -813,14 +930,14 @@
</property>
</widget>
</item>
- <item row="3" column="0">
+ <item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Services</string>
</property>
</widget>
</item>
- <item row="3" column="2">
+ <item row="4" column="2">
<widget class="QLabel" name="peerServices">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -839,7 +956,7 @@
<item row="5" column="0">
<widget class="QLabel" name="label_29">
<property name="text">
- <string>Starting Height</string>
+ <string>Starting Block</string>
</property>
</widget>
</item>
@@ -862,7 +979,7 @@
<item row="6" column="0">
<widget class="QLabel" name="label_27">
<property name="text">
- <string>Sync Height</string>
+ <string>Synced Headers</string>
</property>
</widget>
</item>
@@ -883,13 +1000,36 @@
</widget>
</item>
<item row="7" column="0">
+ <widget class="QLabel" name="label_25">
+ <property name="text">
+ <string>Synced Blocks</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="2">
+ <widget class="QLabel" name="peerCommonHeight">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Ban Score</string>
</property>
</widget>
</item>
- <item row="7" column="2">
+ <item row="8" column="2">
<widget class="QLabel" name="peerBanScore">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -905,14 +1045,14 @@
</property>
</widget>
</item>
- <item row="8" column="0">
+ <item row="9" column="0">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Connection Time</string>
</property>
</widget>
</item>
- <item row="8" column="2">
+ <item row="9" column="2">
<widget class="QLabel" name="peerConnTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -928,14 +1068,14 @@
</property>
</widget>
</item>
- <item row="9" column="0">
+ <item row="10" column="0">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Last Send</string>
</property>
</widget>
</item>
- <item row="9" column="2">
+ <item row="10" column="2">
<widget class="QLabel" name="peerLastSend">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -951,14 +1091,14 @@
</property>
</widget>
</item>
- <item row="10" column="0">
+ <item row="11" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Last Receive</string>
</property>
</widget>
</item>
- <item row="10" column="2">
+ <item row="11" column="2">
<widget class="QLabel" name="peerLastRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -974,14 +1114,14 @@
</property>
</widget>
</item>
- <item row="11" column="0">
+ <item row="12" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Bytes Sent</string>
</property>
</widget>
</item>
- <item row="11" column="2">
+ <item row="12" column="2">
<widget class="QLabel" name="peerBytesSent">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -997,14 +1137,14 @@
</property>
</widget>
</item>
- <item row="12" column="0">
+ <item row="13" column="0">
<widget class="QLabel" name="label_20">
<property name="text">
<string>Bytes Received</string>
</property>
</widget>
</item>
- <item row="12" column="2">
+ <item row="13" column="2">
<widget class="QLabel" name="peerBytesRecv">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1020,14 +1160,14 @@
</property>
</widget>
</item>
- <item row="13" column="0">
+ <item row="14" column="0">
<widget class="QLabel" name="label_26">
<property name="text">
<string>Ping Time</string>
</property>
</widget>
</item>
- <item row="13" column="2">
+ <item row="14" column="2">
<widget class="QLabel" name="peerPingTime">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1043,14 +1183,40 @@
</property>
</widget>
</item>
- <item row="14" column="0">
+ <item row="15" column="0">
+ <widget class="QLabel" name="peerPingWaitLabel">
+ <property name="toolTip">
+ <string>The duration of a currently outstanding ping.</string>
+ </property>
+ <property name="text">
+ <string>Ping Wait</string>
+ </property>
+ </widget>
+ </item>
+ <item row="15" column="2">
+ <widget class="QLabel" name="peerPingWait">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>N/A</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::PlainText</enum>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item row="16" column="0">
<widget class="QLabel" name="label_timeoffset">
<property name="text">
<string>Time Offset</string>
</property>
</widget>
</item>
- <item row="14" column="2">
+ <item row="16" column="2">
<widget class="QLabel" name="timeoffset">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
@@ -1066,7 +1232,7 @@
</property>
</widget>
</item>
- <item row="15" column="1">
+ <item row="17" column="1">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/qt/forms/sendcoinsentry.ui b/src/qt/forms/sendcoinsentry.ui
index 48d0dd093c..df06f36833 100644
--- a/src/qt/forms/sendcoinsentry.ui
+++ b/src/qt/forms/sendcoinsentry.ui
@@ -21,15 +21,21 @@
<string>This is a normal payment.</string>
</property>
<property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Sunken</enum>
+ <enum>QFrame::NoFrame</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
- <property name="spacing">
+ <property name="topMargin">
+ <number>8</number>
+ </property>
+ <property name="bottomMargin">
+ <number>4</number>
+ </property>
+ <property name="horizontalSpacing">
<number>12</number>
</property>
+ <property name="verticalSpacing">
+ <number>8</number>
+ </property>
<item row="0" column="0">
<widget class="QLabel" name="payToLabel">
<property name="text">
@@ -193,6 +199,13 @@
</property>
</widget>
</item>
+ <item row="4" column="0" colspan="2">
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
<widget class="QFrame" name="SendCoins_UnauthenticatedPaymentRequest">
@@ -618,10 +631,7 @@
<bool>true</bool>
</property>
<property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Sunken</enum>
+ <enum>QFrame::NoFrame</enum>
</property>
<layout class="QGridLayout" name="gridLayout_is">
<property name="spacing">
@@ -1150,10 +1160,7 @@
<bool>true</bool>
</property>
<property name="frameShape">
- <enum>QFrame::StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>QFrame::Sunken</enum>
+ <enum>QFrame::NoFrame</enum>
</property>
<layout class="QGridLayout" name="gridLayout_s">
<property name="spacing">
diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h
index a0a2993ea3..7d3e48ff32 100644
--- a/src/qt/guiconstants.h
+++ b/src/qt/guiconstants.h
@@ -42,7 +42,7 @@ static const int MAX_URI_LENGTH = 255;
#define EXPORT_IMAGE_SIZE 256
/* Number of frames in spinner animation */
-#define SPINNER_FRAMES 35
+#define SPINNER_FRAMES 36
#define QAPP_ORG_NAME "Bitcoin"
#define QAPP_ORG_DOMAIN "bitcoin.org"
diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp
index 4a1f728e18..8917f77f22 100644
--- a/src/qt/guiutil.cpp
+++ b/src/qt/guiutil.cpp
@@ -11,7 +11,7 @@
#include "primitives/transaction.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "protocol.h"
#include "script/script.h"
#include "script/standard.h"
@@ -265,6 +265,19 @@ void copyEntryData(QAbstractItemView *view, int column, int role)
}
}
+QString getEntryData(QAbstractItemView *view, int column, int role)
+{
+ if(!view || !view->selectionModel())
+ return QString();
+ QModelIndexList selection = view->selectionModel()->selectedRows(column);
+
+ if(!selection.isEmpty()) {
+ // Return first item
+ return (selection.at(0).data(role).toString());
+ }
+ return QString();
+}
+
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir,
const QString &filter,
QString *selectedSuffixOut)
@@ -391,7 +404,7 @@ void SubstituteFonts(const QString& language)
{
#if defined(Q_OS_MAC)
// Background:
-// OSX's default font changed in 10.9 and QT is unable to find it with its
+// OSX's default font changed in 10.9 and Qt is unable to find it with its
// usual fallback methods when building against the 10.7 sdk or lower.
// The 10.8 SDK added a function to let it find the correct fallback font.
// If this fallback is not properly loaded, some characters may fail to
diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h
index bcbb540c37..0ac3db6327 100644
--- a/src/qt/guiutil.h
+++ b/src/qt/guiutil.h
@@ -64,6 +64,14 @@ namespace GUIUtil
*/
void copyEntryData(QAbstractItemView *view, int column, int role=Qt::EditRole);
+ /** Return a field of the currently selected entry as a QString. Does nothing if nothing
+ is selected.
+ @param[in] column Data column to extract from the model
+ @param[in] role Data role to extract from the model
+ @see TransactionView::copyLabel, TransactionView::copyAmount, TransactionView::copyAddress
+ */
+ QString getEntryData(QAbstractItemView *view, int column, int role);
+
void setClipboard(const QString& str);
/** Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix
@@ -161,7 +169,7 @@ namespace GUIUtil
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode);
void resizeColumn(int nColumnIndex, int width);
- private slots:
+ private Q_SLOTS:
void on_sectionResized(int logicalIndex, int oldSize, int newSize);
void on_geometriesChanged();
};
@@ -205,7 +213,7 @@ namespace GUIUtil
#else
typedef QProgressBar ProgressBar;
#endif
-
+
} // namespace GUIUtil
#endif // BITCOIN_QT_GUIUTIL_H
diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp
index 9f72602b4d..4ab87e0f32 100644
--- a/src/qt/intro.cpp
+++ b/src/qt/intro.cpp
@@ -6,7 +6,6 @@
#include "ui_intro.h"
#include "guiutil.h"
-#include "scicon.h"
#include "util.h"
@@ -42,10 +41,10 @@ public:
ST_ERROR
};
-public slots:
+public Q_SLOTS:
void check();
-signals:
+Q_SIGNALS:
void reply(int status, const QString &message, quint64 available);
private:
@@ -102,7 +101,7 @@ void FreespaceChecker::check()
replyStatus = ST_ERROR;
replyMessage = tr("Cannot create data directory here.");
}
- emit reply(replyStatus, replyMessage, freeBytesAvailable);
+ Q_EMIT reply(replyStatus, replyMessage, freeBytesAvailable);
}
@@ -121,7 +120,7 @@ Intro::~Intro()
{
delete ui;
/* Ensure thread is finished before it is deleted */
- emit stopThread();
+ Q_EMIT stopThread();
thread->wait();
}
@@ -168,7 +167,7 @@ void Intro::pickDataDirectory()
/* If current default data directory does not exist, let the user choose one */
Intro intro;
intro.setDataDirectory(dataDir);
- intro.setWindowIcon(SingleColorIcon(":icons/bitcoin"));
+ intro.setWindowIcon(QIcon(":icons/bitcoin"));
while(true)
{
@@ -277,7 +276,7 @@ void Intro::checkPath(const QString &dataDir)
if(!signalled)
{
signalled = true;
- emit requestCheck();
+ Q_EMIT requestCheck();
}
mutex.unlock();
}
diff --git a/src/qt/intro.h b/src/qt/intro.h
index c9735615b6..50783f7225 100644
--- a/src/qt/intro.h
+++ b/src/qt/intro.h
@@ -43,14 +43,14 @@ public:
*/
static QString getDefaultDataDirectory();
-signals:
+Q_SIGNALS:
void requestCheck();
void stopThread();
-public slots:
+public Q_SLOTS:
void setStatus(int status, const QString &message, quint64 bytesAvailable);
-private slots:
+private Q_SLOTS:
void on_dataDirectory_textChanged(const QString &arg1);
void on_ellipsisButton_clicked();
void on_dataDirDefault_clicked();
diff --git a/src/qt/locale/bitcoin_ar.ts b/src/qt/locale/bitcoin_ar.ts
index a2e4c376b8..235b22cd1f 100644
--- a/src/qt/locale/bitcoin_ar.ts
+++ b/src/qt/locale/bitcoin_ar.ts
@@ -765,11 +765,7 @@
<source>Your current total balance</source>
<translation>رصيدك الكلي الحالي</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>خارج المزامنه</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
</context>
diff --git a/src/qt/locale/bitcoin_be_BY.ts b/src/qt/locale/bitcoin_be_BY.ts
index a94f3c6f7d..b727b75566 100644
--- a/src/qt/locale/bitcoin_be_BY.ts
+++ b/src/qt/locale/bitcoin_be_BY.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>Правы клік, каб рэдагаваць адрас ці метку</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>Стварыць новы адрас</translation>
</message>
@@ -62,10 +66,26 @@
<translation>адрасы Прымання</translation>
</message>
<message>
+ <source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
+ <translation>Тут знаходзяцца Біткойн-адрасы для высылання плацяжоў. Заўсёды спраўджвайце колькасць і адрас прызначэння перад здзяйсненнем транзакцыі.</translation>
+ </message>
+ <message>
+ <source>These are your Bitcoin addresses for receiving payments. It is recommended to use a new receiving address for each transaction.</source>
+ <translation>Тут знаходзяцца Біткойн-адрасы для прымання плацяжоў. Пажадана выкарыстоўваць новы адрас для кожнай транзакцыі.</translation>
+ </message>
+ <message>
+ <source>Copy &amp;Label</source>
+ <translation>Капіяваць Метку</translation>
+ </message>
+ <message>
<source>&amp;Edit</source>
<translation>Рэдагаваць</translation>
</message>
<message>
+ <source>Export Address List</source>
+ <translation>Экспартаваць Спіс Адрасоў</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Коскамі падзелены файл (*.csv)</translation>
</message>
@@ -73,12 +93,16 @@
<source>Exporting Failed</source>
<translation>Экспартаванне няўдалае</translation>
</message>
- </context>
+ <message>
+ <source>There was an error trying to save the address list to %1. Please try again.</source>
+ <translation>Адбылася памылка падчас спробы захаваць адрас у %1. Паспрабуйце зноў.</translation>
+ </message>
+</context>
<context>
<name>AddressTableModel</name>
<message>
<source>Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
</message>
<message>
<source>Address</source>
@@ -92,6 +116,10 @@
<context>
<name>AskPassphraseDialog</name>
<message>
+ <source>Passphrase Dialog</source>
+ <translation>Дыялог сакрэтнай фразы</translation>
+ </message>
+ <message>
<source>Enter passphrase</source>
<translation>Увядзіце кодавую фразу</translation>
</message>
@@ -140,6 +168,14 @@
<translation>Ці ўпэўненыя вы, што жадаеце зашыфраваць свой гаманец?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Bitcoin Core зараз будзе зачынены, каб фіналізаваць працэс шыфравання. Памятайце, што шыфраванне вашага гаманца не гарантуе абсалютную абарону ад магчымасці крадзяжу біткойнаў шкоднымі праграмамі, якія могуць інфікаваць ваш камп'ютар.</translation>
+ </message>
+ <message>
+ <source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
+ <translation>ВАЖНА: Усе папярэднія копіі гаманца варта замяніць новым зашыфраваным файлам. У мэтах бяспекі папярэднія копіі незашыфраванага файла-гаманца стануць неўжывальнымі, калі вы станеце карыстацца новым зашыфраваным гаманцом.</translation>
+ </message>
+ <message>
<source>Warning: The Caps Lock key is on!</source>
<translation>Увага: Caps Lock уключаны!</translation>
</message>
@@ -148,6 +184,14 @@
<translation>Гаманец зашыфраваны</translation>
</message>
<message>
+ <source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
+ <translation>Увядзіце новы пароль для гаманца.&lt;br/&gt;Парольная фраза павинна складацца&lt;b&gt; не меньш чым з дзесяці сімвалаў&lt;/b&gt;, ці &lt;b&gt;больш чым з васьмі слоў&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Увядзіце стары пароль і новы пароль для гаманца.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Шыфраванне гаманца няўдалае</translation>
</message>
@@ -231,10 +275,42 @@
<translation>Зашыфраваць Гаманец...</translation>
</message>
<message>
+ <source>&amp;Backup Wallet...</source>
+ <translation>Стварыць копію гаманца...</translation>
+ </message>
+ <message>
+ <source>&amp;Change Passphrase...</source>
+ <translation>&amp;Change Passphrase...</translation>
+ </message>
+ <message>
+ <source>&amp;Sending addresses...</source>
+ <translation>Адрасы дасылання...</translation>
+ </message>
+ <message>
+ <source>&amp;Receiving addresses...</source>
+ <translation>Адрасы прымання...</translation>
+ </message>
+ <message>
<source>Open &amp;URI...</source>
<translation>Адчыниць &amp;URI...</translation>
</message>
<message>
+ <source>Bitcoin Core client</source>
+ <translation>Bitcoin Core кліент</translation>
+ </message>
+ <message>
+ <source>Importing blocks from disk...</source>
+ <translation>Імпартуюцца блокі з дыску...</translation>
+ </message>
+ <message>
+ <source>Reindexing blocks on disk...</source>
+ <translation>Пераіндэксацыя блокаў на дыску...</translation>
+ </message>
+ <message>
+ <source>Send coins to a Bitcoin address</source>
+ <translation>Даслаць манеты на Біткойн-адрас</translation>
+ </message>
+ <message>
<source>Backup wallet to another location</source>
<translation>Зрабіце копію гаманца ў іншае месца</translation>
</message>
@@ -247,6 +323,18 @@
<translation>Вакно адладкі</translation>
</message>
<message>
+ <source>Open debugging and diagnostic console</source>
+ <translation>Адкрыць кансоль дыягностыкі і адладкі</translation>
+ </message>
+ <message>
+ <source>&amp;Verify message...</source>
+ <translation>Праверыць паведамленне...</translation>
+ </message>
+ <message>
+ <source>Bitcoin</source>
+ <translation>Біткойн</translation>
+ </message>
+ <message>
<source>Wallet</source>
<translation>Гаманец</translation>
</message>
@@ -259,6 +347,10 @@
<translation>Атрымаць</translation>
</message>
<message>
+ <source>Show information about Bitcoin Core</source>
+ <translation>Паказаць інфармацыю аб Bitcoin Core</translation>
+ </message>
+ <message>
<source>&amp;Show / Hide</source>
<translation>&amp;Паказаць / Схаваць</translation>
</message>
@@ -271,6 +363,14 @@
<translation>Зашыфраваць прыватныя ключы, якия належаць вашаму гаманцу</translation>
</message>
<message>
+ <source>Sign messages with your Bitcoin addresses to prove you own them</source>
+ <translation>Падпісаць паведамленне з дапамогай Біткойн-адраса каб даказаць, што яно належыць вам</translation>
+ </message>
+ <message>
+ <source>Verify messages to ensure they were signed with specified Bitcoin addresses</source>
+ <translation>Спраўдзіць паведамленне з дапамогай Біткойн-адраса каб даказаць, што яно належыць вам</translation>
+ </message>
+ <message>
<source>&amp;File</source>
<translation>Ф&amp;айл</translation>
</message>
@@ -283,10 +383,98 @@
<translation>Дапамога</translation>
</message>
<message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>Request payments (generates QR codes and bitcoin: URIs)</source>
+ <translation>Запатрабаваць плацёж (генеруецца QR-код для біткойн URI)</translation>
+ </message>
+ <message>
+ <source>&amp;About Bitcoin Core</source>
+ <translation>Аб Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>Modify configuration options for Bitcoin Core</source>
+ <translation>Мадыфікаваць опцыі канфігурацыі Bitcoin Core</translation>
+ </message>
+ <message>
+ <source>Show the list of used sending addresses and labels</source>
+ <translation>Паказаць спіс адрасоў і метак для дасылання</translation>
+ </message>
+ <message>
+ <source>Show the list of used receiving addresses and labels</source>
+ <translation>Паказаць спіс адрасоў і метак для прымання</translation>
+ </message>
+ <message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Адкрыць біткойн: URI ці запыт плацяжу</translation>
+ </message>
+ <message>
+ <source>&amp;Command-line options</source>
+ <translation>Опцыі каманднага радка</translation>
+ </message>
+ <message>
+ <source>Show the Bitcoin Core help message to get a list with possible Bitcoin command-line options</source>
+ <translation>Паказваць даведку Bitcoin Core каб атрымаць спіс магчымых опцый каманднага радка</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n active connection(s) to Bitcoin network</source>
+ <translation><numerusform>%n актыўнае злучэнне з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform><numerusform>%n актыўных злучэнняў з сецівам Bitcoin</numerusform></translation>
+ </message>
+ <message>
+ <source>No block source available...</source>
+ <translation>Крыніца блокаў недасяжная...</translation>
+ </message>
+ <message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Апрацаваны %n блок гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокі гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокаў гісторыі транзакцый.</numerusform><numerusform>Апрацавана %n блокаў гісторыі транзакцый.</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n hour(s)</source>
+ <translation><numerusform>%n гадзіна</numerusform><numerusform>%n гадзіны</numerusform><numerusform>%n гадзін</numerusform><numerusform>%n гадзін</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n day(s)</source>
+ <translation><numerusform>%n дзень</numerusform><numerusform>%n дні</numerusform><numerusform>%n дзён</numerusform><numerusform>%n дзён</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>%n week(s)</source>
+ <translation><numerusform>%n тыдзень</numerusform><numerusform>%n тыдні</numerusform><numerusform>%n тыдняў</numerusform><numerusform>%n тыдняў</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 and %2</source>
+ <translation>%1 і %2</translation>
+ </message>
+ <message numerus="yes">
+ <source>%n year(s)</source>
+ <translation><numerusform>%n год</numerusform><numerusform>%n гады</numerusform><numerusform>%n гадоў</numerusform><numerusform>%n гадоў</numerusform></translation>
+ </message>
+ <message>
+ <source>%1 behind</source>
+ <translation>%1 таму</translation>
+ </message>
+ <message>
+ <source>Last received block was generated %1 ago.</source>
+ <translation>Апошні прыняты блок генераваны %1 таму.</translation>
+ </message>
+ <message>
+ <source>Transactions after this will not yet be visible.</source>
+ <translation>Транзакцыи пасля гэтай не будуць бачныя.</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Памылка</translation>
</message>
<message>
+ <source>Warning</source>
+ <translation>Увага</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Інфармацыя</translation>
+ </message>
+ <message>
<source>Up to date</source>
<translation>Сінхранізавана</translation>
</message>
@@ -295,6 +483,36 @@
<translation>Наганяем...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>Дата: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Колькасць: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Тып: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Метка: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Адрас: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Дасланыя транзакцыі</translation>
</message>
@@ -313,26 +531,82 @@
</context>
<context>
<name>ClientModel</name>
- </context>
+ <message>
+ <source>Network Alert</source>
+ <translation>Трывога Сеціва</translation>
+ </message>
+</context>
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Quantity:</source>
+ <translation>Колькасць:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Байтаў:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>Колькасць:</translation>
</message>
<message>
+ <source>Priority:</source>
+ <translation>Прыярытэт:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Камісія:</translation>
+ </message>
+ <message>
+ <source>Dust:</source>
+ <translation>Пыл:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Пасля камісіі:</translation>
+ </message>
+ <message>
+ <source>(un)select all</source>
+ <translation>(не)выбраць ўсё</translation>
+ </message>
+ <message>
+ <source>Tree mode</source>
+ <translation>Рэжым дрэва</translation>
+ </message>
+ <message>
+ <source>List mode</source>
+ <translation>Рэжым спіса</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>Колькасць</translation>
</message>
<message>
+ <source>Received with label</source>
+ <translation>Прыняць праз метку</translation>
+ </message>
+ <message>
+ <source>Received with address</source>
+ <translation>Прыняць праз адрас</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Дата</translation>
</message>
<message>
+ <source>Confirmations</source>
+ <translation>Пацверджанняў</translation>
+ </message>
+ <message>
<source>Confirmed</source>
<translation>Пацверджана</translation>
</message>
<message>
+ <source>Priority</source>
+ <translation>Прыярытэт</translation>
+ </message>
+ <message>
<source>Copy address</source>
<translation>Капіяваць адрас</translation>
</message>
@@ -349,6 +623,90 @@
<translation>Капіяваць ID транзакцыі</translation>
</message>
<message>
+ <source>Lock unspent</source>
+ <translation>Замкнуць непатрачанае</translation>
+ </message>
+ <message>
+ <source>Unlock unspent</source>
+ <translation>Адамкнуць непатрачанае</translation>
+ </message>
+ <message>
+ <source>Copy quantity</source>
+ <translation>Капіяваць колькасць</translation>
+ </message>
+ <message>
+ <source>Copy fee</source>
+ <translation>Капіяваць камісію</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Капіяваць з выняткам камісіі</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Капіяваць байты</translation>
+ </message>
+ <message>
+ <source>Copy priority</source>
+ <translation>Капіяваць прыярытэт</translation>
+ </message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Капіяваць пыл</translation>
+ </message>
+ <message>
+ <source>highest</source>
+ <translation>найвышэйшы</translation>
+ </message>
+ <message>
+ <source>higher</source>
+ <translation>вышэйшы</translation>
+ </message>
+ <message>
+ <source>high</source>
+ <translation>высокі</translation>
+ </message>
+ <message>
+ <source>medium-high</source>
+ <translation>вышэй сярэдняга</translation>
+ </message>
+ <message>
+ <source>medium</source>
+ <translation>сярэдні</translation>
+ </message>
+ <message>
+ <source>low-medium</source>
+ <translation>ніжэй сярэдняга</translation>
+ </message>
+ <message>
+ <source>low</source>
+ <translation>нізкі</translation>
+ </message>
+ <message>
+ <source>lower</source>
+ <translation>ніжэйшы</translation>
+ </message>
+ <message>
+ <source>lowest</source>
+ <translation>найніжэйшы</translation>
+ </message>
+ <message>
+ <source>yes</source>
+ <translation>так</translation>
+ </message>
+ <message>
+ <source>no</source>
+ <translation>не</translation>
+ </message>
+ <message>
+ <source>This means a fee of at least %1 per kB is required.</source>
+ <translation>Гэта значыць патрэбную камісію мінімум %1 на Кб.</translation>
+ </message>
+ <message>
+ <source>Transactions with higher priority are more likely to get included into a block.</source>
+ <translation>Транзакцыя большага прыярытэту больш прываблівая для ўключэння ў блок.</translation>
+ </message>
+ <message>
<source>(no label)</source>
<translation>непазначаны</translation>
</message>
@@ -361,7 +719,7 @@
</message>
<message>
<source>&amp;Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
</message>
<message>
<source>&amp;Address</source>
@@ -398,10 +756,26 @@
</context>
<context>
<name>FreespaceChecker</name>
+ <message>
+ <source>A new data directory will be created.</source>
+ <translation>Будзе створаны новы каталог з данымі.</translation>
+ </message>
+ <message>
+ <source>name</source>
+ <translation>імя</translation>
+ </message>
+ <message>
+ <source>Directory already exists. Add %1 if you intend to create a new directory here.</source>
+ <translation>Каталог ужо існуе. Дадайце %1 калі вы збіраецеся стварыць тут новы каталог.</translation>
+ </message>
</context>
<context>
<name>HelpMessageDialog</name>
<message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
<source>(%1-bit)</source>
<translation>(%1-біт)</translation>
</message>
@@ -410,19 +784,51 @@
<translation>Аб Bitcoin Core</translation>
</message>
<message>
+ <source>Command-line options</source>
+ <translation>Опцыі каманднага радка</translation>
+ </message>
+ <message>
<source>Usage:</source>
<translation>Ужыванне:</translation>
</message>
- </context>
+ <message>
+ <source>command-line options</source>
+ <translation>опцыі каманднага радка</translation>
+ </message>
+</context>
<context>
<name>Intro</name>
<message>
+ <source>Welcome</source>
+ <translation>Вітаем</translation>
+ </message>
+ <message>
+ <source>Welcome to Bitcoin Core.</source>
+ <translation>Вітаем у Bitcoin Core.</translation>
+ </message>
+ <message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
<source>Error</source>
<translation>Памылка</translation>
</message>
- </context>
+ <message numerus="yes">
+ <source>%n GB of free space available</source>
+ <translation><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform><numerusform>%n Гб вольнага месца даступна</numerusform></translation>
+ </message>
+ <message numerus="yes">
+ <source>(of %n GB needed)</source>
+ <translation><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform><numerusform>(з %n Гб патрэбна)</numerusform></translation>
+ </message>
+</context>
<context>
<name>OpenURIDialog</name>
+ <message>
+ <source>Open URI</source>
+ <translation>Адкрыць URI</translation>
+ </message>
</context>
<context>
<name>OptionsDialog</name>
@@ -430,6 +836,10 @@
<source>Options</source>
<translation>Опцыі</translation>
</message>
+ <message>
+ <source>MB</source>
+ <translation>Мб</translation>
+ </message>
</context>
<context>
<name>OverviewPage</name>
@@ -461,7 +871,7 @@
<name>ReceiveCoinsDialog</name>
<message>
<source>&amp;Label:</source>
- <translation>Пазнака:</translation>
+ <translation>Метка:</translation>
</message>
<message>
<source>Copy label</source>
@@ -484,7 +894,11 @@
</message>
<message>
<source>Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Паведамленне</translation>
</message>
</context>
<context>
@@ -495,7 +909,11 @@
</message>
<message>
<source>Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
+ </message>
+ <message>
+ <source>Message</source>
+ <translation>Паведамленне</translation>
</message>
<message>
<source>Amount</source>
@@ -513,14 +931,38 @@
<translation>Даслаць Манеты</translation>
</message>
<message>
+ <source>Quantity:</source>
+ <translation>Колькасць:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>Байтаў:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>Колькасць:</translation>
</message>
<message>
+ <source>Priority:</source>
+ <translation>Прыярытэт:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>Камісія:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>Пасля камісіі:</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>Даслаць адразу некалькім атрымальнікам</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>Пыл:</translation>
+ </message>
+ <message>
<source>Balance:</source>
<translation>Баланс:</translation>
</message>
@@ -533,10 +975,30 @@
<translation>Пацвердзіць дасыланне манет</translation>
</message>
<message>
+ <source>Copy quantity</source>
+ <translation>Капіяваць колькасць</translation>
+ </message>
+ <message>
<source>Copy amount</source>
<translation>Капіяваць колькасць</translation>
</message>
<message>
+ <source>Copy fee</source>
+ <translation>Капіяваць камісію</translation>
+ </message>
+ <message>
+ <source>Copy after fee</source>
+ <translation>Капіяваць з выняткам камісіі</translation>
+ </message>
+ <message>
+ <source>Copy bytes</source>
+ <translation>Капіяваць байты</translation>
+ </message>
+ <message>
+ <source>Copy priority</source>
+ <translation>Капіяваць прыярытэт</translation>
+ </message>
+ <message>
<source>The amount to pay must be larger than 0.</source>
<translation>Велічыня плацяжу мае быць больш за 0.</translation>
</message>
@@ -544,6 +1006,10 @@
<source>(no label)</source>
<translation>непазначаны</translation>
</message>
+ <message>
+ <source>Copy dust</source>
+ <translation>Капіяваць пыл</translation>
+ </message>
</context>
<context>
<name>SendCoinsEntry</name>
@@ -561,7 +1027,7 @@
</message>
<message>
<source>&amp;Label:</source>
- <translation>Пазнака:</translation>
+ <translation>Метка:</translation>
</message>
<message>
<source>Alt+A</source>
@@ -575,7 +1041,11 @@
<source>Alt+P</source>
<translation>Alt+P</translation>
</message>
- </context>
+ <message>
+ <source>Memo:</source>
+ <translation>Памятка:</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
</context>
@@ -597,6 +1067,10 @@
<context>
<name>SplashScreen</name>
<message>
+ <source>Bitcoin Core</source>
+ <translation>Bitcoin Core</translation>
+ </message>
+ <message>
<source>The Bitcoin Core developers</source>
<translation>Распрацоўнікі Bitcoin Core</translation>
</message>
@@ -607,10 +1081,18 @@
</context>
<context>
<name>TrafficGraphWidget</name>
- </context>
+ <message>
+ <source>KB/s</source>
+ <translation>Кб/с</translation>
+ </message>
+</context>
<context>
<name>TransactionDesc</name>
<message>
+ <source>%1/offline</source>
+ <translation>%1/offline</translation>
+ </message>
+ <message>
<source>%1/unconfirmed</source>
<translation>%1/непацверджана</translation>
</message>
@@ -619,10 +1101,22 @@
<translation>%1 пацверджанняў</translation>
</message>
<message>
+ <source>Status</source>
+ <translation>Статус</translation>
+ </message>
+ <message>
<source>Date</source>
<translation>Дата</translation>
</message>
<message>
+ <source>Message</source>
+ <translation>Паведамленне</translation>
+ </message>
+ <message>
+ <source>Comment</source>
+ <translation>Каментар</translation>
+ </message>
+ <message>
<source>Transaction ID</source>
<translation>ID</translation>
</message>
@@ -674,7 +1168,7 @@
</message>
<message>
<source>Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
</message>
<message>
<source>Received with</source>
@@ -817,7 +1311,7 @@
</message>
<message>
<source>Label</source>
- <translation>Пазнака</translation>
+ <translation>Метка</translation>
</message>
<message>
<source>Address</source>
@@ -883,14 +1377,106 @@
<translation>Ужываць тэставае сеціва</translation>
</message>
<message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>Ці жадаеце вы перабудаваць зараз базу звестак блокаў?</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation>Памылка ініцыялізацыі базвы звестак блокаў</translation>
+ </message>
+ <message>
+ <source>Error initializing wallet database environment %s!</source>
+ <translation>Памалка ініцыялізацыі асяроддзя базы звестак гаманца %s!</translation>
+ </message>
+ <message>
+ <source>Error loading block database</source>
+ <translation>Памылка загрузкі базвы звестак блокаў</translation>
+ </message>
+ <message>
+ <source>Error opening block database</source>
+ <translation>Памылка адчынення базы звестак блокаў</translation>
+ </message>
+ <message>
+ <source>Error: A fatal internal error occured, see debug.log for details</source>
+ <translation>Памылка: здарылася Фатальная унутраная памылка, глядзі debug.log для падрабязнасцяў</translation>
+ </message>
+ <message>
+ <source>Error: Disk space is low!</source>
+ <translation>Памылка: Замала вольнага месца на дыску!</translation>
+ </message>
+ <message>
+ <source>Importing...</source>
+ <translation>Імпартаванне...</translation>
+ </message>
+ <message>
+ <source>Not enough file descriptors available.</source>
+ <translation>Не хапае файлавых дэскрыптараў.</translation>
+ </message>
+ <message>
+ <source>Use UPnP to map the listening port (default: %u)</source>
+ <translation>Use UPnP to map the listening port (default: %u)</translation>
+ </message>
+ <message>
+ <source>Verifying blocks...</source>
+ <translation>Праверка блокаў...</translation>
+ </message>
+ <message>
+ <source>Verifying wallet...</source>
+ <translation>Праверка гаманца...</translation>
+ </message>
+ <message>
+ <source>Wallet options:</source>
+ <translation>Опцыі гаманца:</translation>
+ </message>
+ <message>
+ <source>Imports blocks from external blk000??.dat file</source>
+ <translation>Імпартаванне блокаў з вонкавага blk000??.dat файла</translation>
+ </message>
+ <message>
+ <source>Activating best chain...</source>
+ <translation>Актывацыя лепшага ланцуга...</translation>
+ </message>
+ <message>
+ <source>Information</source>
+ <translation>Інфармацыя</translation>
+ </message>
+ <message>
+ <source>RPC server options:</source>
+ <translation>Опцыі RPC сервера:</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Слаць trace/debug звесткі ў кансоль замест файла debug.log</translation>
</message>
<message>
+ <source>Signing transaction failed</source>
+ <translation>Памылка подпісу транзакцыі</translation>
+ </message>
+ <message>
+ <source>Start minimized</source>
+ <translation>Стартаваць ммінімізаванай</translation>
+ </message>
+ <message>
+ <source>This is experimental software.</source>
+ <translation>Гэта эксперыментальная праграма.</translation>
+ </message>
+ <message>
+ <source>Transaction amount too small</source>
+ <translation>Транзакцыя занадта малая</translation>
+ </message>
+ <message>
+ <source>Transaction too large</source>
+ <translation>Транзакцыя занадта вялікая</translation>
+ </message>
+ <message>
<source>Username for JSON-RPC connections</source>
<translation>Імя карыстальника для JSON-RPC злучэнняў</translation>
</message>
<message>
+ <source>Warning</source>
+ <translation>Увага</translation>
+ </message>
+ <message>
<source>Password for JSON-RPC connections</source>
<translation>Пароль для JSON-RPC злучэнняў</translation>
</message>
@@ -935,6 +1521,10 @@
<translation>Загружаем гаманец...</translation>
</message>
<message>
+ <source>Cannot downgrade wallet</source>
+ <translation>Немагчыма рэгрэсаваць гаманец</translation>
+ </message>
+ <message>
<source>Rescanning...</source>
<translation>Перасканаванне...</translation>
</message>
diff --git a/src/qt/locale/bitcoin_bg.ts b/src/qt/locale/bitcoin_bg.ts
index 5d2995802e..c86fdd42dd 100644
--- a/src/qt/locale/bitcoin_bg.ts
+++ b/src/qt/locale/bitcoin_bg.ts
@@ -387,6 +387,10 @@
<translation>Покажи списък с използваните адреси и имена.</translation>
</message>
<message>
+ <source>Open a bitcoin: URI or payment request</source>
+ <translation>Отворете биткойн: URI или заявка за плащане</translation>
+ </message>
+ <message>
<source>&amp;Command-line options</source>
<translation>&amp;Налични команди</translation>
</message>
@@ -481,6 +485,10 @@
<translation>Такса:</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>Прах:</translation>
+ </message>
+ <message>
<source>After Fee:</source>
<translation>След прилагане на ДДС</translation>
</message>
@@ -573,6 +581,10 @@
<translation>Копиране на приоритет</translation>
</message>
<message>
+ <source>Copy dust</source>
+ <translation>Копирай прахта:</translation>
+ </message>
+ <message>
<source>Copy change</source>
<translation>Копирай рестото</translation>
</message>
@@ -629,6 +641,10 @@
<translation>не</translation>
</message>
<message>
+ <source>This means a fee of at least %1 per kB is required.</source>
+ <translation>Това означава че се изисква такса от поне %1 на килобайт.</translation>
+ </message>
+ <message>
<source>Can vary +/- 1 byte per input.</source>
<translation>Може да варира с +-1 байт</translation>
</message>
@@ -803,10 +819,22 @@
<translation>Мегабайта</translation>
</message>
<message>
+ <source>Accept connections from outside</source>
+ <translation>Приемай връзки отвън</translation>
+ </message>
+ <message>
+ <source>Allow incoming connections</source>
+ <translation>Позволи входящите връзки</translation>
+ </message>
+ <message>
<source>IP address of the proxy (e.g. IPv4: 127.0.0.1 / IPv6: ::1)</source>
<translation>IP адрес на прокси (напр. за IPv4: 127.0.0.1 / за IPv6: ::1)</translation>
</message>
<message>
+ <source>Third party transaction URLs</source>
+ <translation>URL адреси на трети страни</translation>
+ </message>
+ <message>
<source>Reset all client options to default.</source>
<translation>Възстановете всички настройки по подразбиране.</translation>
</message>
@@ -891,6 +919,10 @@
<translation>Изберете единиците, показвани по подразбиране в интерфейса.</translation>
</message>
<message>
+ <source>Whether to show coin control features or not.</source>
+ <translation>Дали да покаже възможностите за контрол на монетите или не.</translation>
+ </message>
+ <message>
<source>&amp;OK</source>
<translation>ОК</translation>
</message>
@@ -934,6 +966,10 @@
<translation>Текущата информация на екрана може да не е актуална. Вашият портфейл ще се синхронизира автоматично с мрежата на Биткоин, щом поне една връзката с нея се установи; този процес все още не е приключил.</translation>
</message>
<message>
+ <source>Watch-only:</source>
+ <translation>В наблюдателен режим:</translation>
+ </message>
+ <message>
<source>Available:</source>
<translation>Налично:</translation>
</message>
@@ -950,6 +986,10 @@
<translation>Неразвит:</translation>
</message>
<message>
+ <source>Mined balance that has not yet matured</source>
+ <translation>Миниран баланс,който все още не се е развил</translation>
+ </message>
+ <message>
<source>Balances</source>
<translation>Баланс</translation>
</message>
@@ -969,22 +1009,50 @@
<source>Recent transactions</source>
<translation>Скорошни транзакции</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>несинхронизиран</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
+ <source>URI handling</source>
+ <translation>Справяне с URI</translation>
+ </message>
+ <message>
+ <source>Invalid payment address %1</source>
+ <translation>Невалиден адрес на плащане %1</translation>
+ </message>
+ <message>
+ <source>Payment request rejected</source>
+ <translation>Заявката за плащане беше отхвърлена</translation>
+ </message>
+ <message>
+ <source>Payment request network doesn't match client network.</source>
+ <translation>Мрежата от която се извършва заявката за плащане не съвпада с мрежата на клиента.</translation>
+ </message>
+ <message>
<source>Requested payment amount of %1 is too small (considered dust).</source>
<translation>Заявената сума за плащане: %1 е твърде малка (счита се за отпадък)</translation>
</message>
<message>
+ <source>Payment request error</source>
+ <translation>Възникна грешка по време назаявката за плащане</translation>
+ </message>
+ <message>
+ <source>Cannot start bitcoin: click-to-pay handler</source>
+ <translation>Биткойн не можe да се стартира: click-to-pay handler</translation>
+ </message>
+ <message>
+ <source>Payment request file handling</source>
+ <translation>Файл за справяне със заявки</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Възстановяване на сума от %1</translation>
</message>
<message>
+ <source>Payment request DoS protection</source>
+ <translation>Дос защита на заявката за плащане</translation>
+ </message>
+ <message>
<source>Error communicating with %1: %2</source>
<translation>Грешка при комуникацията с %1: %2</translation>
</message>
@@ -1019,6 +1087,14 @@
<translation>Сума</translation>
</message>
<message>
+ <source>Enter a Bitcoin address (e.g. %1)</source>
+ <translation>Въведете Биткойн адрес (например: %1)</translation>
+ </message>
+ <message>
+ <source>%1 d</source>
+ <translation>%1 ден</translation>
+ </message>
+ <message>
<source>%1 h</source>
<translation>%1 час</translation>
</message>
@@ -1149,6 +1225,30 @@
<translation>Услуги</translation>
</message>
<message>
+ <source>Starting Height</source>
+ <translation>Стартова височина</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>Продължителност на връзката</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation>Изпратени за последно</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation>Получени за последно</translation>
+ </message>
+ <message>
+ <source>Bytes Sent</source>
+ <translation>Изпратени байтове</translation>
+ </message>
+ <message>
+ <source>Bytes Received</source>
+ <translation>Получени байтове</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Време за отговор</translation>
</message>
@@ -1220,7 +1320,31 @@
<source>%1 GB</source>
<translation>%1 Гигабайт</translation>
</message>
- </context>
+ <message>
+ <source>via %1</source>
+ <translation>посредством %1</translation>
+ </message>
+ <message>
+ <source>never</source>
+ <translation>Никога</translation>
+ </message>
+ <message>
+ <source>Inbound</source>
+ <translation>Входящи</translation>
+ </message>
+ <message>
+ <source>Outbound</source>
+ <translation>Изходящи</translation>
+ </message>
+ <message>
+ <source>Unknown</source>
+ <translation>Неизвестен</translation>
+ </message>
+ <message>
+ <source>Fetching...</source>
+ <translation>Прихващане...</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -1409,6 +1533,14 @@
<translation>Ако тази опция е активирана,но адресът на промяна е празен или невалиден,промяната ще бъде изпратена на новосъздаден адрес.</translation>
</message>
<message>
+ <source>Transaction Fee:</source>
+ <translation>Такса за транзакцията:</translation>
+ </message>
+ <message>
+ <source>Choose...</source>
+ <translation>Избери...</translation>
+ </message>
+ <message>
<source>per kilobyte</source>
<translation>за килобайт</translation>
</message>
@@ -1421,10 +1553,22 @@
<translation>Препоръчителна:</translation>
</message>
<message>
+ <source>Custom:</source>
+ <translation>По избор:</translation>
+ </message>
+ <message>
<source>Confirmation time:</source>
<translation>Време за потвърждение:</translation>
</message>
<message>
+ <source>normal</source>
+ <translation>нормален</translation>
+ </message>
+ <message>
+ <source>fast</source>
+ <translation>бърз</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>Изпращане към повече от един получател</translation>
</message>
@@ -1437,6 +1581,10 @@
<translation>Изчисти всички полета от формуляра.</translation>
</message>
<message>
+ <source>Dust:</source>
+ <translation>Прах:</translation>
+ </message>
+ <message>
<source>Clear &amp;All</source>
<translation>&amp;Изчисти</translation>
</message>
@@ -1525,6 +1673,10 @@
<translation>Внимание:Неизвестен адрес за промяна</translation>
</message>
<message>
+ <source>Copy dust</source>
+ <translation>Копирай прахта:</translation>
+ </message>
+ <message>
<source>Are you sure you want to send?</source>
<translation>Наистина ли искате да изпратите?</translation>
</message>
@@ -1583,7 +1735,11 @@
<source>Pay To:</source>
<translation>Плащане на:</translation>
</message>
- </context>
+ <message>
+ <source>Memo:</source>
+ <translation>Бележка:</translation>
+ </message>
+</context>
<context>
<name>ShutdownWindow</name>
<message>
@@ -2167,14 +2323,30 @@
<translation>Внимание: -paytxfee е с мното голяма зададена стойност! Това е транзакционната такса, която ще платите ако направите транзакция.</translation>
</message>
<message>
+ <source>Whitelist peers connecting from the given netmask or IP address. Can be specified multiple times.</source>
+ <translation>Сложете в бял списък пиъри,свързващи се от дадената интернет маска или айпи адрес.Може да бъде заложено неколкократно.</translation>
+ </message>
+ <message>
<source>(default: 1)</source>
<translation>(по подразбиране 1)</translation>
</message>
<message>
+ <source>&lt;category&gt; can be:</source>
+ <translation>&lt;category&gt; може да бъде:</translation>
+ </message>
+ <message>
<source>Connection options:</source>
<translation>Настройки на връзката:</translation>
</message>
<message>
+ <source>Do you want to rebuild the block database now?</source>
+ <translation>Желаете ли да пресъздадете базата данни с блокове сега?</translation>
+ </message>
+ <message>
+ <source>Error initializing block database</source>
+ <translation>Грешка в пускането на базата данни с блокове</translation>
+ </message>
+ <message>
<source>Error: Disk space is low!</source>
<translation>Грешка: мястото на диска е малко!</translation>
</message>
@@ -2199,6 +2371,14 @@
<translation>Настройки на портфейла:</translation>
</message>
<message>
+ <source>Set the number of threads for coin generation if enabled (-1 = all cores, default: %d)</source>
+ <translation>Заложете броя на нишки за генерация на монети ако е включено(-1 = всички ядра, по подразбиране: %d)</translation>
+ </message>
+ <message>
+ <source>Warning: -maxtxfee is set very high! Fees this large could be paid on a single transaction.</source>
+ <translation>Внимание: -maxtxfee има много висока стойност! Толкова високи такси могат да бъдат заплатени на една транзакция.</translation>
+ </message>
+ <message>
<source>Choose data directory on startup (default: 0)</source>
<translation>Изберете директория при стартиране на програмата.( настройка по подразбиране:0)</translation>
</message>
@@ -2303,6 +2483,14 @@
<translation>Назовете конфигурационен файл(по подразбиране %s)</translation>
</message>
<message>
+ <source>Specify connection timeout in milliseconds (minimum: 1, default: %d)</source>
+ <translation>Задайте време на изключване при проблеми със свързването в милисекунди(минимум:1, по подразбиране %d)</translation>
+ </message>
+ <message>
+ <source>Specify pid file (default: %s)</source>
+ <translation>Задайте pid файл(по подразбиране: %s)</translation>
+ </message>
+ <message>
<source>Invalid amount for -paytxfee=&lt;amount&gt;: '%s'</source>
<translation>Невалидна сума за -paytxfee=&lt;amount&gt;: '%s'</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ca.ts b/src/qt/locale/bitcoin_ca.ts
index 37d1dfc9eb..f7d97eb061 100644
--- a/src/qt/locale/bitcoin_ca.ts
+++ b/src/qt/locale/bitcoin_ca.ts
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Balanç total actual en adreces de només lectura</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>Fora de sincronia</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_ca@valencia.ts b/src/qt/locale/bitcoin_ca@valencia.ts
index 0a52b1bc9a..c68cfb686a 100644
--- a/src/qt/locale/bitcoin_ca@valencia.ts
+++ b/src/qt/locale/bitcoin_ca@valencia.ts
@@ -1073,10 +1073,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Balanç total actual en adreces de només lectura</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>Fora de sincronia</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_ca_ES.ts b/src/qt/locale/bitcoin_ca_ES.ts
index 3baa6e00cd..cd6aa96d34 100644
--- a/src/qt/locale/bitcoin_ca_ES.ts
+++ b/src/qt/locale/bitcoin_ca_ES.ts
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Balanç total actual en adreces de només lectura</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>Fora de sincronia</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_cs.ts b/src/qt/locale/bitcoin_cs.ts
index b4d9ca146d..47464b7a53 100644
--- a/src/qt/locale/bitcoin_cs.ts
+++ b/src/qt/locale/bitcoin_cs.ts
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Aktuální stav účtu sledovaných adres</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nesynchronizováno</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_da.ts b/src/qt/locale/bitcoin_da.ts
index 6979124615..1467791047 100644
--- a/src/qt/locale/bitcoin_da.ts
+++ b/src/qt/locale/bitcoin_da.ts
@@ -1211,10 +1211,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Nuværende totalsaldo på kigge-adresser</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>ikke synkroniseret</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -2922,7 +2918,7 @@
</message>
<message>
<source>Do you want to rebuild the block database now?</source>
- <translation>Ønsker du at genbygge blokdatabasen nu?</translation>
+ <translation>Ønsker du at genopbygge blokdatabasen nu?</translation>
</message>
<message>
<source>Error initializing block database</source>
@@ -3162,7 +3158,7 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
</message>
<message>
<source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
- <translation>Du er nødt til at genbygge databasen ved hjælp af -reindex for at gå tilbage til ikke-beskåret tilstand. Dette vil downloade hele blokkæden igen</translation>
+ <translation>Du er nødt til at genopbygge databasen ved hjælp af -reindex for at gå tilbage til ikke-beskåret tilstand. Dette vil downloade hele blokkæden igen</translation>
</message>
<message>
<source>(default: %u)</source>
@@ -3281,6 +3277,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Slør tilfældigt 1 ud af hver &lt;n&gt; netværksbeskeder</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Genopbyg blokkædeindeks fra nuværende blk000??.dat-filer ved opstart</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Send sporings-/fejlsøgningsinformation til konsollen i stedet for debug.log filen</translation>
</message>
diff --git a/src/qt/locale/bitcoin_de.ts b/src/qt/locale/bitcoin_de.ts
index 928b72fae8..ab0367dbab 100644
--- a/src/qt/locale/bitcoin_de.ts
+++ b/src/qt/locale/bitcoin_de.ts
@@ -168,6 +168,10 @@
<translation>Sind Sie sich sicher, dass Sie Ihre Wallet verschlüsseln möchten?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Bitcoin Core wird jetzt beendet, um den Verschlüsselungsprozess abzuschließen. Vergessen Sie nicht, dass eine Wallet-Verschlüsselung nicht vollständig vor Diebstahl Ihrer Bitcoins durch Schadsoftware schützen kann, die Ihren Computer infiziert.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>WICHTIG: Alle vorherigen Wallet-Sicherungen sollten durch die neu erzeugte, verschlüsselte Wallet ersetzt werden. Aus Sicherheitsgründen werden vorherige Sicherungen der unverschlüsselten Wallet nutzlos, sobald Sie die neue, verschlüsselte Wallet verwenden.</translation>
</message>
@@ -184,6 +188,10 @@
<translation>Geben Sie die neue Passphrase für die Wallet ein.&lt;br&gt;Bitte benutzen Sie eine Passphrase bestehend aus &lt;b&gt;zehn oder mehr zufälligen Zeichen&lt;/b&gt; oder &lt;b&gt;acht oder mehr Wörtern&lt;/b&gt;.</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Geben Sie die alte und neue Wallet-Passphrase ein.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Wallet-Verschlüsselung fehlgeschlagen</translation>
</message>
@@ -392,7 +400,7 @@
</message>
<message>
<source>Modify configuration options for Bitcoin Core</source>
- <translation>Konfigurationsoptionen für Bitcoin Core ändern</translation>
+ <translation>Konfiguration von Bitcoin Core bearbeiten</translation>
</message>
<message>
<source>Show the list of used sending addresses and labels</source>
@@ -423,6 +431,10 @@
<translation>Keine Blockquelle verfügbar...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>%n Block des Transaktionsverlaufs verarbeitet.</numerusform><numerusform>%n Blöcke des Transaktionsverlaufs verarbeitet.</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n Stunde</numerusform><numerusform>%n Stunden</numerusform></translation>
</message>
@@ -703,6 +715,18 @@
<translation>keine</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>Diese Bezeichnung wird rot, wenn die Transaktion größer als 1000 Byte ist.</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>Diese Bezeichnung wird rot, wenn die Priorität niedriger als "mittel" ist.</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>Diese Bezeichnung wird rot, wenn irgendein Empfänger einen Betrag kleiner als %1 erhält.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>Kann pro Eingabe um +/- %1 Satoshi(s) abweichen.</translation>
</message>
@@ -953,6 +977,14 @@
<translation>IP-Adresse des Proxies (z.B. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Minimiert die Anwendung anstatt sie zu beenden wenn das Fenster geschlossen wird. Wenn dies aktiviert ist, müssen Sie die Anwendung über "Beenden" im Menü schließen.</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>Legt die Sprache der Benutzeroberfläche fest. Diese Einstellung wird erst nach einem Neustart von Bitcoin Core aktiv.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>Externe URLs (z.B. ein Block-Explorer), die im Kontextmenü des Transaktionsverlaufs eingefügt werden. In der URL wird %s durch den Transaktionshash ersetzt. Bei Angabe mehrerer URLs müssen diese durch "|" voneinander getrennt werden.</translation>
</message>
@@ -978,11 +1010,11 @@
</message>
<message>
<source>Automatically start Bitcoin Core after logging in to the system.</source>
- <translation>Bitcoin Core nach dem Anmelden am System automatisch starten.</translation>
+ <translation>Bitcoin Core nach der Anmeldung am System automatisch starten.</translation>
</message>
<message>
<source>&amp;Start Bitcoin Core on system login</source>
- <translation>Bitcoin Core bei der Systemanmeldung &amp;starten</translation>
+ <translation>&amp;Bitcoin Core nach Systemanmeldung starten</translation>
</message>
<message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
@@ -1098,7 +1130,7 @@
</message>
<message>
<source>Client will be shut down. Do you want to proceed?</source>
- <translation>Client wird heruntergefahren. Möchten Sie den Vorgang fortsetzen?</translation>
+ <translation>Client wird beendet. Möchten Sie den Vorgang fortsetzen?</translation>
</message>
<message>
<source>This change would require a client restart.</source>
@@ -1183,10 +1215,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Aktueller Gesamtbetrag in beobachteten Adressen aus obigen Kategorien</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nicht synchron</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1239,10 +1267,18 @@
<translation>Zahlungsanforderungsdatei kann nicht gelesen werden! Dies kann durch eine ungültige Zahlungsanforderungsdatei verursacht werden.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Zahlungsanforderung abgelaufen.</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>Unverifizierte Zahlungsanforderungen an benutzerdefinierte Zahlungsskripte werden nicht unterstützt.</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>Ungültige Zahlungsanforderung.</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Rücküberweisung von %1</translation>
</message>
@@ -1407,6 +1443,10 @@
<translation>Aktuelle Anzahl Blöcke</translation>
</message>
<message>
+ <source>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Öffnet die "Bitcoin Core"-Debugprotokolldatei aus dem aktuellen Datenverzeichnis. Dies kann bei großen Protokolldateien einige Sekunden dauern.</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Empfangen</translation>
</message>
@@ -1524,7 +1564,7 @@
</message>
<message>
<source>Welcome to the Bitcoin Core RPC console.</source>
- <translation>Willkommen in der Bitcoin Core RPC-Konsole.</translation>
+ <translation>Willkommen in der "Bitcoin Core"-RPC-Konsole.</translation>
</message>
<message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
@@ -1971,10 +2011,26 @@
<translation>Eine höhere Gebühr als %1 wird als unsinnig hohe Gebühr angesehen.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Zahlungsanforderung abgelaufen.</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Block.</numerusform><numerusform>Voraussichtlicher Beginn der Bestätigung innerhalb von %n Blöcken.</numerusform></translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>Nur die minimale Gebühr in Höhe von %1 zahlen</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Die Zahlungsadresse ist ungültig, bitte nochmals überprüfen.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Doppelte Adresse entdeckt: Adressen dürfen jeweils nur einmal vorkommen.</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Warnung: Ungültige Bitcoin-Adresse</translation>
</message>
@@ -2046,14 +2102,26 @@
<translation>Diesen Eintrag entfernen</translation>
</message>
<message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>Die Gebühr wird vom zu überweisenden Betrag abgezogen. Der Empfänger wird also weniger Bitcoins erhalten, als Sie im Betrags-Feld eingegeben haben. Falls mehrere Empfänger ausgewählt wurden, wird die Gebühr gleichmäßig verteilt.</translation>
+ </message>
+ <message>
<source>S&amp;ubtract fee from amount</source>
- <translation>Gebühr von Betrag ab&amp;ziehen</translation>
+ <translation>Gebühr vom Betrag ab&amp;ziehen</translation>
</message>
<message>
<source>Message:</source>
<translation>Nachricht:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Dies ist keine beglaubigte Zahlungsanforderung.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Dies ist eine beglaubigte Zahlungsanforderung.</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation>Adressbezeichnung eingeben, die dann zusammen mit der Adresse der Liste bereits verwendeter Adressen hinzugefügt wird.</translation>
</message>
@@ -2092,6 +2160,10 @@
<translation>Nachricht &amp;signieren</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>Sie können Nachrichten/Vereinbarungen mit Hilfe Ihrer Adressen signieren, um zu beweisen, dass Sie Bitcoins empfangen können, die an diese Adressen überwiesen werden. Seien Sie vorsichtig und signieren Sie nichts Vages oder Willkürliches, um Ihre Indentität vor Phishingangriffen zu schützen. Signieren Sie nur vollständig-detaillierte Aussagen, mit denen Sie auch einverstanden sind.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>Die Bitcoin-Adresse mit der die Nachricht signiert wird</translation>
</message>
@@ -2144,6 +2216,10 @@
<translation>Nachricht &amp;verifizieren</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>Geben Sie die Zahlungsadresse des Empfängers, Nachricht (achten Sie darauf Zeilenumbrüche, Leerzeichen, Tabulatoren usw. exakt zu kopieren) und Signatur unten ein, um die Nachricht zu verifizieren. Vorsicht, interpretieren Sie nicht mehr in die Signatur hinein, als in der signierten Nachricht selber enthalten ist, um nicht von einem Man-in-the-middle-Angriff hinters Licht geführt zu werden. Beachten Sie dass dies nur beweißt, dass die signierende Partei über diese Adresse Überweisungen empfangen kann.</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>Die Bitcoin-Adresse mit der die Nachricht signiert wurde</translation>
</message>
@@ -2495,6 +2571,10 @@
<translation>Zeigt an, ob eine beobachtete Adresse in diese Transaktion involviert ist.</translation>
</message>
<message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Benutzerdefinierte Absicht bzw. Verwendungszweck der Transaktion</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>Der Betrag, der dem Kontostand abgezogen oder hinzugefügt wurde.</translation>
</message>
@@ -2737,6 +2817,10 @@
<translation>An die angegebene Adresse binden und immer abhören. Für IPv6 "[Host]:Port"-Notation verwenden</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>Durchgehend die Anzahl freier Transaktionen auf &lt;n&gt; * 1000 Byte pro Minute begrenzen (Standard: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Alle Wallet-Transaktionen löschen und nur diese Teilbereiche der Blockkette durch -rescan beim Starten wiederherstellen</translation>
</message>
@@ -2757,6 +2841,14 @@
<translation>In diesem Modus legt -genproclimit fest, wie viele Blöcke sofort erzeugt werden.</translation>
</message>
<message>
+ <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source>
+ <translation>Maximale Gesamtgebühren je Wallet-Transaktion, ein zu niedriger Wert kann große Transaktionen abbrechen (Standard: %s)</translation>
+ </message>
+ <message>
+ <source>Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
+ <translation>Speicherplatzanforderung durch kürzen (löschen) alter Blöcke reduzieren. Dieser Modus deaktiviert die Wallet-Unterstützung und ist nicht mit -txindex kompatibel. Warnung: Die Umkehr dieser Einstellung erfordert das erneute Herunterladen der gesamten Blockkette. (Standard: 0 = deaktiviert das Kürzen von Blöcken, &gt;%u = Zielgröße in MiB, die für Blockdateien verwendet werden darf)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Maximale Anzahl an Skript-Verifizierungs-Threads festlegen (%u bis %d, 0 = automatisch, &lt;0 = so viele Kerne frei lassen, Standard: %d)</translation>
</message>
@@ -2885,6 +2977,14 @@
<translation>Nur zu Knoten des Netzwerktyps &lt;net&gt; verbinden (ipv4, ipv6 oder onion)</translation>
</message>
<message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>Kürzungsmodus kann nicht mit einem negativen Wert konfiguriert werden.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>Kürzungsmodus ist nicht mit -txindex kompatibel.</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Größe des Datenbankcaches in Megabyte festlegen (%d bis %d, Standard: %d)</translation>
</message>
@@ -2921,6 +3021,10 @@
<translation>Wallet-Optionen:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>Warnung: Diese Version is veraltet, Aktualisierung erforderlich!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um -txindex zu verändern</translation>
</message>
@@ -2953,6 +3057,10 @@
<translation>Neue Dateien mit Standard-Systemrechten erzeugen, anstatt mit umask 077 (nur mit deaktivierter Walletfunktion nutzbar)</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Eigene IP-Adressen ermitteln (Standard: 1, wenn abgehört wird und nicht -externalip oder -proxy)</translation>
+ </message>
+ <message>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation>Fehler: Abhören nach eingehenden Verbindungen fehlgeschlagen (listen meldete Fehler %s)</translation>
</message>
@@ -2985,10 +3093,22 @@
<translation>Maximale Datengröße in "Data Carrier"-Transaktionen die weitergeleitet und erarbeitet werden (Standard: %u)</translation>
</message>
<message>
+ <source>Prune configured below the minimum of %d MB. Please use a higher number.</source>
+ <translation>Kürzungsmodus wurde kleiner als das Minimum in Höhe von %d MiB konfiguriert. Bitte verwenden Sie einen größeren Wert.</translation>
+ </message>
+ <message>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
<translation>Adressen von Gegenstellen via DNS-Namensauflösung finden, falls zu wenige Adressen verfügbar sind (Standard: 1, außer bei -connect)</translation>
</message>
<message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>Zufällige Anmeldedaten für jede Proxyverbindung verwenden. Dies aktiviert Tor-Datenflussisolation (Standard: %u)</translation>
+ </message>
+ <message>
+ <source>Require high priority for relaying free or low-fee transactions (default: %u)</source>
+ <translation>Hohe Priorität zum Weiterleiten von freien bzw. Transaktionen mit niedrigen Gebühren voraussetzen (Standard: %u)</translation>
+ </message>
+ <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Maximale Größe in Byte von "high-priority/low-fee"-Transaktionen festlegen (Standard: %d)</translation>
</message>
@@ -2997,6 +3117,10 @@
<translation>Maximale Anzahl an Threads zur Bitcoinerzeugung, wenn aktiviert, festlegen (-1 = alle Kerne, Standard: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Der Transaktionsbetrag ist zum senden zu niedrig, nachdem die Gebühr abgezogen wurde.</translation>
+ </message>
+ <message>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation>Dieses Produkt enthält Software, die vom OpenSSL-Projekt zur Verwendung im OpenSSL-Toolkit &lt;https://www.openssl.org/&gt; entwickelt wird, sowie von Eric Young geschriebene kryptographische Software und von Thomas Bernard geschriebene UPnP-Software.</translation>
</message>
@@ -3037,6 +3161,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Erlaubte Gegenstellen werden nicht für DoS-Attacken gesperrt und ihre Transkationen werden immer weitergeleitet, auch wenn sie sich bereits im Speicherpool befinden, was z.B. für Gateways sinnvoll ist.</translation>
</message>
<message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>Sie müssen die Datenbank mit Hilfe von -reindex neu aufbauen, um zum ungekürzten Modus zurückzukehren. Dies erfordert, dass die gesamte Blockkette erneut heruntergeladen wird.</translation>
+ </message>
+ <message>
<source>(default: %u)</source>
<translation>(Standard: %u)</translation>
</message>
@@ -3045,6 +3173,18 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Öffentliche REST-Anfragen annehmen (Standard: %u)</translation>
</message>
<message>
+ <source>Activating best chain...</source>
+ <translation>Aktiviere beste Blockkette...</translation>
+ </message>
+ <message>
+ <source>Allow self signed root certificates (default: 0)</source>
+ <translation>Selbstunterschriebene Stammzertifikate erlauben (Standard: 0)</translation>
+ </message>
+ <message>
+ <source>Can't run with a wallet in prune mode.</source>
+ <translation>Eine Wallet kann im Kürzungsmodus nicht verwendet werden.</translation>
+ </message>
+ <message>
<source>Cannot resolve -whitebind address: '%s'</source>
<translation>Kann Adresse in -whitebind nicht auflösen: '%s'</translation>
</message>
@@ -3141,6 +3281,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Zufällig eine von &lt;n&gt; Netzwerknachrichten verwürfeln</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Blockkettenindex aus aktuellen Dateien blk000??.dat beim Starten wiederaufbauen</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Rückverfolgungs- und Debuginformationen an die Konsole senden, anstatt sie in debug.log zu schreiben</translation>
</message>
@@ -3177,6 +3321,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Minimiert starten</translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>Der Transaktionsbetrag ist zu niedrig, um die Gebühr zu bezahlen.</translation>
+ </message>
+ <message>
<source>This is experimental software.</source>
<translation>Dies ist experimentelle Software.</translation>
</message>
@@ -3361,6 +3509,10 @@ Beispiel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Maximal &lt;n&gt; Verbindungen zu Gegenstellen aufrechterhalten (Standard: %u)</translation>
</message>
<message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>Die Wallet soll Transaktionen übertragen/broadcasten</translation>
+ </message>
+ <message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation>Maximale Größe des Empfangspuffers pro Verbindung, &lt;n&gt; * 1000 Byte (Standard: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_el_GR.ts b/src/qt/locale/bitcoin_el_GR.ts
index 5cabe43032..a4c95857ba 100644
--- a/src/qt/locale/bitcoin_el_GR.ts
+++ b/src/qt/locale/bitcoin_el_GR.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>Δεξί-κλικ για επεξεργασία της διεύθυνσης ή της ετικέτας</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>Δημιουργία νέας διεύθυνσης</translation>
</message>
@@ -881,10 +885,18 @@
<translation>Διεύθυνση IP του διαμεσολαβητή (π.χ. 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
+ <translation>URLs από τρίτους (π.χ. ένας εξερευνητής μπλοκ) τα οποία εμφανίζονται στην καρτέλα συναλλαγών ως στοιχεία μενού. Το %s στα URL αντικαθιστάται από την τιμή της κατατεμαχισμένης συναλλαγής.</translation>
+ </message>
+ <message>
<source>Third party transaction URLs</source>
<translation>Διευθύνσεις τρίτων συναλλαγών.</translation>
</message>
<message>
+ <source>Active command-line options that override above options:</source>
+ <translation>Ενεργές επιλογές γραμμής-εντολών που παρακάμπτουν τις παραπάνω επιλογές:</translation>
+ </message>
+ <message>
<source>Reset all client options to default.</source>
<translation>Επαναφορα όλων των επιλογων του πελάτη σε default.</translation>
</message>
@@ -897,6 +909,10 @@
<translation>&amp;Δίκτυο</translation>
</message>
<message>
+ <source>(0 = auto, &lt;0 = leave that many cores free)</source>
+ <translation>(0 = αυτόματο, &lt;0 = ελεύθεροι πυρήνες)</translation>
+ </message>
+ <message>
<source>W&amp;allet</source>
<translation>Π&amp;ορτοφόλι</translation>
</message>
@@ -909,6 +925,14 @@
<translation>Επιλογή κατα πόσο να αναδείχνονται οι δυνατότητες ελέγχου κερμάτων.</translation>
</message>
<message>
+ <source>If you disable the spending of unconfirmed change, the change from a transaction cannot be used until that transaction has at least one confirmation. This also affects how your balance is computed.</source>
+ <translation>Εάν απενεργοποιήσετε το ξόδεμα μη επικυρωμένων ρέστων, τα ρέστα από μια συναλλαγή δεν μπορούν να χρησιμοποιηθούν έως ότου αυτή η συναλλαγή έχει έστω μια επικύρωση. Αυτό επίσης επηρεάζει το πως υπολογίζεται το υπόλοιπό σας.</translation>
+ </message>
+ <message>
+ <source>&amp;Spend unconfirmed change</source>
+ <translation>&amp;Ξόδεμα μη επικυρωμένων ρέστων</translation>
+ </message>
+ <message>
<source>Automatically open the Bitcoin client port on the router. This only works when your router supports UPnP and it is enabled.</source>
<translation>Αυτόματο άνοιγμα των θυρών Bitcoin στον δρομολογητή. Λειτουργεί μόνο αν ο δρομολογητής σας υποστηρίζει τη λειτουργία UPnP.</translation>
</message>
@@ -1057,6 +1081,10 @@
<translation>Το τρέχον συνολικό υπόλοιπο</translation>
</message>
<message>
+ <source>Your current balance in watch-only addresses</source>
+ <translation>Το τρέχον υπόλοιπο σας σε διευθύνσεις παρακολούθησης μόνο</translation>
+ </message>
+ <message>
<source>Spendable:</source>
<translation>Ξοδεμένα:</translation>
</message>
@@ -1065,8 +1093,16 @@
<translation>Πρόσφατες συναλλαγές</translation>
</message>
<message>
- <source>out of sync</source>
- <translation>εκτός συγχρονισμού</translation>
+ <source>Unconfirmed transactions to watch-only addresses</source>
+ <translation>Μη επικυρωμένες συναλλαγές σε διευθύνσεις παρακολούθησης μόνο</translation>
+ </message>
+ <message>
+ <source>Mined balance in watch-only addresses that has not yet matured</source>
+ <translation>Εξορυγμένο υπόλοιπο σε διευθύνσεις παρακολούθησης μόνο που δεν έχει ωριμάσει ακόμα</translation>
+ </message>
+ <message>
+ <source>Current total balance in watch-only addresses</source>
+ <translation>Το τρέχον συνολικό υπόλοιπο σε διευθύνσεις παρακολούθησης μόνο</translation>
</message>
</context>
<context>
@@ -1088,6 +1124,10 @@
<translation>Η αίτηση πληρωμής δεν έχει αρχίζει ακόμα.</translation>
</message>
<message>
+ <source>Requested payment amount of %1 is too small (considered dust).</source>
+ <translation>Το ζητούμενο ποσό πληρωμής του %1 είναι πολύ μικρό (θεωρείται σκόνη)</translation>
+ </message>
+ <message>
<source>Payment request error</source>
<translation>Σφάλμα αιτήματος πληρωμής</translation>
</message>
@@ -1108,6 +1148,18 @@
<translation>Επιστροφή ποσού από %1</translation>
</message>
<message>
+ <source>Error communicating with %1: %2</source>
+ <translation>Σφάλμα επικοινωνίας με %1: %2</translation>
+ </message>
+ <message>
+ <source>Payment request cannot be parsed!</source>
+ <translation>Η αίτηση πληρωμής δεν μπορεί να αναλυθεί!</translation>
+ </message>
+ <message>
+ <source>Bad response from server %1</source>
+ <translation>Κακή απάντηση από διακομιστή %1</translation>
+ </message>
+ <message>
<source>Payment acknowledged</source>
<translation>Πληρωμή αναγνωρίστηκε</translation>
</message>
@@ -1212,6 +1264,10 @@
<translation>Χρησιμοποιηση της OpenSSL εκδοσης</translation>
</message>
<message>
+ <source>Using BerkeleyDB version</source>
+ <translation>Χρήση BerkeleyDB έκδοσης</translation>
+ </message>
+ <message>
<source>Startup time</source>
<translation>Χρόνος εκκίνησης</translation>
</message>
@@ -1240,6 +1296,18 @@
<translation>Παραλήφθησαν</translation>
</message>
<message>
+ <source>Sent</source>
+ <translation>Αποστολή</translation>
+ </message>
+ <message>
+ <source>&amp;Peers</source>
+ <translation>&amp;Χρήστες</translation>
+ </message>
+ <message>
+ <source>Select a peer to view detailed information.</source>
+ <translation>Επιλέξτε ένα χρήστη για να δείτε αναλυτικές πληροφορίες.</translation>
+ </message>
+ <message>
<source>Version</source>
<translation>Έκδοση</translation>
</message>
@@ -1248,6 +1316,38 @@
<translation>Υπηρεσίες</translation>
</message>
<message>
+ <source>Starting Height</source>
+ <translation>Αρχικό ύψος</translation>
+ </message>
+ <message>
+ <source>Sync Height</source>
+ <translation>Ύψος συγχονισμού</translation>
+ </message>
+ <message>
+ <source>Ban Score</source>
+ <translation>Σκορ αποκλησμού</translation>
+ </message>
+ <message>
+ <source>Connection Time</source>
+ <translation>Χρόνος σύνδεσης</translation>
+ </message>
+ <message>
+ <source>Last Send</source>
+ <translation>Τελευταία αποστολή</translation>
+ </message>
+ <message>
+ <source>Last Receive</source>
+ <translation>Τελευταία λήψη</translation>
+ </message>
+ <message>
+ <source>Bytes Sent</source>
+ <translation>Σταλθέντα bytes</translation>
+ </message>
+ <message>
+ <source>Bytes Received</source>
+ <translation>Ληφθέντα bytes</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Χρόνος καθυστέρησης</translation>
</message>
@@ -1339,7 +1439,11 @@
<source>Unknown</source>
<translation>Άγνωστο(α)</translation>
</message>
- </context>
+ <message>
+ <source>Fetching...</source>
+ <translation>Ανάκτηση...</translation>
+ </message>
+</context>
<context>
<name>ReceiveCoinsDialog</name>
<message>
@@ -1355,6 +1459,10 @@
<translation>&amp;Μήνυμα:</translation>
</message>
<message>
+ <source>R&amp;euse an existing receiving address (not recommended)</source>
+ <translation>Ε&amp;παναχρησιμοποίηση υπάρχουσας διεύθυνσης λήψης (δεν συνιστάται)</translation>
+ </message>
+ <message>
<source>Clear all fields of the form.</source>
<translation>Καθαρισμός όλων των πεδίων της φόρμας.</translation>
</message>
@@ -1371,6 +1479,10 @@
<translation>Εμφάνιση</translation>
</message>
<message>
+ <source>Remove the selected entries from the list</source>
+ <translation>Αφαίρεση επιλεγμένων καταχωρίσεων από τη λίστα</translation>
+ </message>
+ <message>
<source>Remove</source>
<translation>Αφαίρεση</translation>
</message>
@@ -1398,10 +1510,18 @@
<translation>Αντιγραφη της επιλεγμενης διεύθυνσης στο πρόχειρο του συστηματος</translation>
</message>
<message>
+ <source>Copy &amp;Address</source>
+ <translation>Αντιγραφή &amp;Διεύθυνσης</translation>
+ </message>
+ <message>
<source>&amp;Save Image...</source>
<translation>&amp;Αποθήκευση εικόνας...</translation>
</message>
<message>
+ <source>Request payment to %1</source>
+ <translation>Αίτηση πληρωμής για %1</translation>
+ </message>
+ <message>
<source>Payment information</source>
<translation>Πληροφορίες πληρωμής</translation>
</message>
@@ -1476,6 +1596,10 @@
<translation>Χαρακτηρηστικά επιλογής κερμάτων</translation>
</message>
<message>
+ <source>Inputs...</source>
+ <translation>Εισροές...</translation>
+ </message>
+ <message>
<source>automatically selected</source>
<translation>επιλεγμένο αυτόματα</translation>
</message>
@@ -1512,6 +1636,14 @@
<translation>Ρέστα:</translation>
</message>
<message>
+ <source>If this is activated, but the change address is empty or invalid, change will be sent to a newly generated address.</source>
+ <translation>Όταν ενεργό, αλλά η διεύθυνση ρέστων είναι κενή ή άκυρη, τα ρέστα θα σταλούν σε μία πρόσφατα δημιουργημένη διεύθυνση.</translation>
+ </message>
+ <message>
+ <source>Custom change address</source>
+ <translation>Προσαρμοσμένη διεύθυνση ρέστων</translation>
+ </message>
+ <message>
<source>Transaction Fee:</source>
<translation>Τέλος συναλλαγής:</translation>
</message>
@@ -1520,10 +1652,34 @@
<translation>Επιλογή...</translation>
</message>
<message>
+ <source>per kilobyte</source>
+ <translation>ανά kilobyte</translation>
+ </message>
+ <message>
+ <source>Recommended:</source>
+ <translation>Προτεινόμενο: </translation>
+ </message>
+ <message>
+ <source>Custom:</source>
+ <translation>Προσαρμογή:</translation>
+ </message>
+ <message>
+ <source>Confirmation time:</source>
+ <translation>Χρόνος επικύρωσης:</translation>
+ </message>
+ <message>
+ <source>normal</source>
+ <translation>κανονικό</translation>
+ </message>
+ <message>
<source>fast</source>
<translation>Γρήγορο</translation>
</message>
<message>
+ <source>(confirmation may take longer)</source>
+ <translation>(η επικύρωση ίσως χρειαστεί περισσότερο χρόνο)</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>Αποστολή σε πολλούς αποδέκτες ταυτόχρονα</translation>
</message>
@@ -1659,6 +1815,14 @@
<translation>Επιλογή διεύθυνσης που έχει ήδη χρησιμοποιηθεί</translation>
</message>
<message>
+ <source>This is a normal payment.</source>
+ <translation>Αυτή είναι μια απλή πληρωμή.</translation>
+ </message>
+ <message>
+ <source>The Bitcoin address to send the payment to</source>
+ <translation>Η διεύθυνση Bitcoin που θα σταλεί η πληρωμή</translation>
+ </message>
+ <message>
<source>Alt+A</source>
<translation>Alt+A</translation>
</message>
@@ -1679,6 +1843,10 @@
<translation>Μήνυμα:</translation>
</message>
<message>
+ <source>Enter a label for this address to add it to the list of used addresses</source>
+ <translation>Εισάγεται μία ετικέτα για αυτή την διεύθυνση για να προστεθεί στη λίστα με τις χρησιμοποιημένες διευθύνσεις</translation>
+ </message>
+ <message>
<source>Pay To:</source>
<translation>Πληρωμή σε:</translation>
</message>
@@ -2191,6 +2359,10 @@
<translation>Επιτυχής εξαγωγή</translation>
</message>
<message>
+ <source>The transaction history was successfully saved to %1.</source>
+ <translation>Το ιστορικό συναλλαγών αποθηκεύτηκε επιτυχώς στο %1.</translation>
+ </message>
+ <message>
<source>Comma separated file (*.csv)</source>
<translation>Αρχείο οριοθετημένο με κόμματα (*.csv)</translation>
</message>
@@ -2229,7 +2401,11 @@
</context>
<context>
<name>UnitDisplayStatusBarControl</name>
- </context>
+ <message>
+ <source>Unit to show amounts in. Click to select another unit.</source>
+ <translation>Μονάδα μέτρησης προβολής ποσών. Κάντε κλικ για επιλογή άλλης μονάδας.</translation>
+ </message>
+</context>
<context>
<name>WalletFrame</name>
<message>
@@ -2267,6 +2443,10 @@
<translation>Αποτυχία κατά τη δημιουργία αντιγράφου</translation>
</message>
<message>
+ <source>There was an error trying to save the wallet data to %1.</source>
+ <translation>Παρουσιάστηκε σφάλμα κατά την αποθήκευση των δεδομένων πορτοφολιού στο %1.</translation>
+ </message>
+ <message>
<source>The wallet data was successfully saved to %1.</source>
<translation>Τα δεδομένα πορτοφολιού αποθηκεύτηκαν με επιτυχία στο %1.</translation>
</message>
@@ -2314,6 +2494,10 @@
<translation>Αποθηκευση σε συγκεκριμένη διεύθυνση. Χρησιμοποιήστε τα πλήκτρα [Host] : συμβολισμός θύρα για IPv6</translation>
</message>
<message>
+ <source>Enter regression test mode, which uses a special chain in which blocks can be solved instantly.</source>
+ <translation>Εισαγωγή δοκιμαστικής λειτουργίας παλινδρόμησης, που χρησιμοποιεί μια ειδική αλυσίδα στην οποία τα μπλοκ επιλύονται στιγμιαία.</translation>
+ </message>
+ <message>
<source>Execute command when a wallet transaction changes (%s in cmd is replaced by TxID)</source>
<translation>Εκτέλεσε την εντολή όταν το καλύτερο μπλοκ αλλάξει(%s στην εντολή αντικαθίσταται από το hash του μπλοκ)</translation>
</message>
@@ -2402,10 +2586,18 @@
<translation>Δεν ειναι αρκετες περιγραφες αρχείων διαθέσιμες.</translation>
</message>
<message>
+ <source>Only connect to nodes in network &lt;net&gt; (ipv4, ipv6 or onion)</source>
+ <translation>Μόνο σύνδεση σε κόμβους του δικτύου &lt;net&gt; (ipv4, ipv6 ή onion)</translation>
+ </message>
+ <message>
<source>Specify wallet file (within data directory)</source>
<translation>Επιλέξτε αρχείο πορτοφολιού (μέσα απο κατάλογο δεδομένων)</translation>
</message>
<message>
+ <source>This is intended for regression testing tools and app development.</source>
+ <translation>Αυτό προορίζεται για εργαλεία δοκιμών παλινδρόμησης και την ανάπτυξη εφαρμογών.</translation>
+ </message>
+ <message>
<source>Verifying blocks...</source>
<translation>Επαλήθευση των μπλοκ... </translation>
</message>
@@ -2414,6 +2606,10 @@
<translation>Επαλήθευση πορτοφολιου... </translation>
</message>
<message>
+ <source>Wallet %s resides outside data directory %s</source>
+ <translation>Το πορτοφόλι %s βρίσκεται έξω από το φάκελο δεδομένων %s</translation>
+ </message>
+ <message>
<source>Wallet options:</source>
<translation>Επιλογές πορτοφολιού:</translation>
</message>
@@ -2426,6 +2622,10 @@
<translation>Αδυναμία κλειδώματος του φακέλου δεδομένων %s. Πιθανώς το Bitcoin να είναι ήδη ενεργό.</translation>
</message>
<message>
+ <source>Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin Core will not work properly.</source>
+ <translation>Προειδοποίηση: Παρακαλώ ελέγξτε ότι η ημερομηνία και ώρα του υπολογιστή σας είναι σωστά ρυθμισμένες! Εάν το ρολόι σας είναι λάθος το Bitcoin Core δεν θα λειτουργήσει σωστά. </translation>
+ </message>
+ <message>
<source>Choose data directory on startup (default: 0)</source>
<translation>Επιλογή φακέλου δεδομένων στην εκκίνηση (προεπιλεγμένο: 0)</translation>
</message>
@@ -2442,6 +2642,10 @@
<translation>Σφάλμα φόρτωσης wallet.dat: Το Πορτοφόλι απαιτεί μια νεότερη έκδοση του Bitcoin</translation>
</message>
<message>
+ <source>Error reading from database, shutting down.</source>
+ <translation>Σφάλμα ανάγνωσης από τη βάση δεδομένων, γίνεται τερματισμός.</translation>
+ </message>
+ <message>
<source>Error: Unsupported argument -tor found, use -onion.</source>
<translation>Σφάλμα: Μη συμβατή παράμετρος -tor. Χρησιμοποιήσε την παράμετρο -onion</translation>
</message>
@@ -2450,6 +2654,10 @@
<translation>Πληροφορία</translation>
</message>
<message>
+ <source>Initialization sanity check failed. Bitcoin Core is shutting down.</source>
+ <translation>Η εκκίνηση ελέγχου ορθότητας απέτυχε. Γίνεται τερματισμός του Bitcoin Core.</translation>
+ </message>
+ <message>
<source>Invalid amount for -minrelaytxfee=&lt;amount&gt;: '%s'</source>
<translation>Μη έγκυρο ποσό για την παράμετρο -paytxfee=&lt;amount&gt;: '%s'</translation>
</message>
@@ -2458,10 +2666,18 @@
<translation>Μη έγκυρο ποσό για την παράμετρο -paytxfee=&lt;amount&gt;: '%s'</translation>
</message>
<message>
+ <source>Node relay options:</source>
+ <translation>Επιλογές αναμετάδοσης κόμβου: </translation>
+ </message>
+ <message>
<source>RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)</source>
<translation>Ρυθμίσεις SSL: (ανατρέξτε στο Bitcoin Wiki για οδηγίες ρυθμίσεων SSL)</translation>
</message>
<message>
+ <source>RPC server options:</source>
+ <translation>Επιλογές διακομιστή RPC:</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Αποστολή πληροφοριών εντοπισμού σφαλμάτων στην κονσόλα αντί του αρχείου debug.log</translation>
</message>
@@ -2474,6 +2690,10 @@
<translation>Όρισε γλώσσα, για παράδειγμα "de_DE"(προεπιλογή:τοπικές ρυθμίσεις)</translation>
</message>
<message>
+ <source>Show all debugging options (usage: --help -help-debug)</source>
+ <translation>Προβολή όλων των επιλογών εντοπισμού σφαλμάτων (χρήση: --help -help-debug)</translation>
+ </message>
+ <message>
<source>Show splash screen on startup (default: 1)</source>
<translation>Εμφάνισε την οθόνη εκκίνησης κατά την εκκίνηση(προεπιλογή:1)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_en.ts b/src/qt/locale/bitcoin_en.ts
index 8dfef68373..90a13feaca 100644
--- a/src/qt/locale/bitcoin_en.ts
+++ b/src/qt/locale/bitcoin_en.ts
@@ -1459,13 +1459,13 @@
<translation>Form</translation>
</message>
<message>
- <location line="+53"/>
- <location line="+372"/>
+ <location line="+59"/>
+ <location line="+386"/>
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</translation>
</message>
<message>
- <location line="-133"/>
+ <location line="-139"/>
<source>Watch-only:</source>
<translation type="unfinished"></translation>
</message>
@@ -1500,12 +1500,12 @@
<translation>Mined balance that has not yet matured</translation>
</message>
<message>
- <location line="-163"/>
+ <location line="-177"/>
<source>Balances</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+147"/>
+ <location line="+161"/>
<source>Total:</source>
<translation>Total:</translation>
</message>
@@ -1544,12 +1544,6 @@
<source>Current total balance in watch-only addresses</source>
<translation type="unfinished"></translation>
</message>
- <message>
- <location filename="../overviewpage.cpp" line="+133"/>
- <location line="+1"/>
- <source>out of sync</source>
- <translation>out of sync</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -2648,14 +2642,14 @@
<context>
<name>SendCoinsEntry</name>
<message>
- <location filename="../forms/sendcoinsentry.ui" line="+149"/>
- <location line="+535"/>
- <location line="+536"/>
+ <location filename="../forms/sendcoinsentry.ui" line="+155"/>
+ <location line="+539"/>
+ <location line="+533"/>
<source>A&amp;mount:</source>
<translation>A&amp;mount:</translation>
</message>
<message>
- <location line="-1184"/>
+ <location line="-1185"/>
<source>Pay &amp;To:</source>
<translation>Pay &amp;To:</translation>
</message>
@@ -2675,12 +2669,12 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-40"/>
+ <location line="-46"/>
<source>This is a normal payment.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+33"/>
+ <location line="+39"/>
<source>The Bitcoin address to send the payment to</source>
<translation type="unfinished"></translation>
</message>
@@ -2701,13 +2695,13 @@
</message>
<message>
<location line="+7"/>
- <location line="+544"/>
- <location line="+536"/>
+ <location line="+548"/>
+ <location line="+533"/>
<source>Remove this entry</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1020"/>
+ <location line="-1021"/>
<source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
<translation type="unfinished"></translation>
</message>
@@ -2722,17 +2716,17 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+436"/>
+ <location line="+443"/>
<source>This is an unauthenticated payment request.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+532"/>
+ <location line="+529"/>
<source>This is an authenticated payment request.</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-1005"/>
+ <location line="-1009"/>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation type="unfinished"></translation>
</message>
@@ -2742,14 +2736,14 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+444"/>
- <location line="+532"/>
+ <location line="+448"/>
+ <location line="+529"/>
<source>Pay To:</source>
<translation type="unfinished"></translation>
</message>
<message>
- <location line="-498"/>
- <location line="+536"/>
+ <location line="-495"/>
+ <location line="+533"/>
<source>Memo:</source>
<translation type="unfinished"></translation>
</message>
@@ -3589,27 +3583,27 @@
<translation>Options:</translation>
</message>
<message>
- <location line="+34"/>
+ <location line="+35"/>
<source>Specify data directory</source>
<translation>Specify data directory</translation>
</message>
<message>
- <location line="-93"/>
+ <location line="-94"/>
<source>Connect to a node to retrieve peer addresses, and disconnect</source>
<translation>Connect to a node to retrieve peer addresses, and disconnect</translation>
</message>
<message>
- <location line="+96"/>
+ <location line="+97"/>
<source>Specify your own public address</source>
<translation>Specify your own public address</translation>
</message>
<message>
- <location line="-116"/>
+ <location line="-117"/>
<source>Accept command line and JSON-RPC commands</source>
<translation>Accept command line and JSON-RPC commands</translation>
</message>
<message>
- <location line="+94"/>
+ <location line="+95"/>
<source>Run in the background as a daemon and accept commands</source>
<translation>Run in the background as a daemon and accept commands</translation>
</message>
@@ -3619,7 +3613,7 @@
<translation>Use the test network</translation>
</message>
<message>
- <location line="-135"/>
+ <location line="-136"/>
<source>Accept connections from outside (default: 1 if no -proxy or -connect)</source>
<translation>Accept connections from outside (default: 1 if no -proxy or -connect)</translation>
</message>
@@ -3839,7 +3833,7 @@
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+17"/>
+ <location line="+18"/>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation type="unfinished"></translation>
</message>
@@ -3894,7 +3888,7 @@
<translation>You need to rebuild the database using -reindex to change -txindex</translation>
</message>
<message>
- <location line="-98"/>
+ <location line="-99"/>
<source>Imports blocks from external blk000??.dat file</source>
<translation>Imports blocks from external blk000??.dat file</translation>
</message>
@@ -4194,6 +4188,11 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
+ <location line="+1"/>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
<location line="+7"/>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Send trace/debug info to console instead of debug.log file</translation>
@@ -4324,7 +4323,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>wallet.dat corrupt, salvage failed</translation>
</message>
<message>
- <location line="-70"/>
+ <location line="-71"/>
<source>Password for JSON-RPC connections</source>
<translation>Password for JSON-RPC connections</translation>
</message>
@@ -4334,7 +4333,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Execute command when the best block changes (%s in cmd is replaced by block hash)</translation>
</message>
<message>
- <location line="+257"/>
+ <location line="+258"/>
<source>Upgrade wallet to latest format</source>
<translation>Upgrade wallet to latest format</translation>
</message>
@@ -4354,7 +4353,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>This help message</translation>
</message>
<message>
- <location line="-115"/>
+ <location line="-116"/>
<source>Allow DNS lookups for -addnode, -seednode and -connect</source>
<translation>Allow DNS lookups for -addnode, -seednode and -connect</translation>
</message>
@@ -4504,7 +4503,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation type="unfinished"></translation>
</message>
<message>
- <location line="+8"/>
+ <location line="+9"/>
<source>Relay and mine data carrier transactions (default: %u)</source>
<translation type="unfinished"></translation>
</message>
@@ -4584,7 +4583,7 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Unknown network specified in -onlynet: &apos;%s&apos;</translation>
</message>
<message>
- <location line="-118"/>
+ <location line="-119"/>
<source>Cannot resolve -bind address: &apos;%s&apos;</source>
<translation>Cannot resolve -bind address: &apos;%s&apos;</translation>
</message>
@@ -4629,12 +4628,12 @@ for example: alertnotify=echo %%s | mail -s &quot;Bitcoin Alert&quot; admin@foo.
<translation>Cannot write default address</translation>
</message>
<message>
- <location line="+76"/>
+ <location line="+77"/>
<source>Rescanning...</source>
<translation>Rescanning...</translation>
</message>
<message>
- <location line="-63"/>
+ <location line="-64"/>
<source>Done loading</source>
<translation>Done loading</translation>
</message>
diff --git a/src/qt/locale/bitcoin_eo.ts b/src/qt/locale/bitcoin_eo.ts
index fbfac8fc10..007acbc495 100644
--- a/src/qt/locale/bitcoin_eo.ts
+++ b/src/qt/locale/bitcoin_eo.ts
@@ -949,11 +949,7 @@
<source>Your current total balance</source>
<translation>via aktuala totala saldo</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nesinkronigita</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_es.ts b/src/qt/locale/bitcoin_es.ts
index 2e1b7dd278..17ec4dca5d 100644
--- a/src/qt/locale/bitcoin_es.ts
+++ b/src/qt/locale/bitcoin_es.ts
@@ -1175,10 +1175,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Saldo total en las direcciones watch-only</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>desincronizado</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_es_CL.ts b/src/qt/locale/bitcoin_es_CL.ts
index c3690480d8..f50aa49110 100644
--- a/src/qt/locale/bitcoin_es_CL.ts
+++ b/src/qt/locale/bitcoin_es_CL.ts
@@ -582,11 +582,7 @@
<source>Total:</source>
<translation>Total:</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>desincronizado</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_es_DO.ts b/src/qt/locale/bitcoin_es_DO.ts
index c5b1e41886..d2cdf87a0e 100644
--- a/src/qt/locale/bitcoin_es_DO.ts
+++ b/src/qt/locale/bitcoin_es_DO.ts
@@ -953,11 +953,7 @@
<source>Your current total balance</source>
<translation>Su balance actual total</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>desincronizado</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_et.ts b/src/qt/locale/bitcoin_et.ts
index 4a502f1a54..29a45960c9 100644
--- a/src/qt/locale/bitcoin_et.ts
+++ b/src/qt/locale/bitcoin_et.ts
@@ -755,11 +755,7 @@
<source>Recent transactions</source>
<translation>Hiljutised tehingud</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>sünkimata</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_fa.ts b/src/qt/locale/bitcoin_fa.ts
index 0bed017614..33f43f0c2d 100644
--- a/src/qt/locale/bitcoin_fa.ts
+++ b/src/qt/locale/bitcoin_fa.ts
@@ -2,6 +2,10 @@
<context>
<name>AddressBookPage</name>
<message>
+ <source>Right-click to edit address or label</source>
+ <translation>برای تغییر آدرس و یا برچسب کلیک راست کنید.</translation>
+ </message>
+ <message>
<source>Create a new address</source>
<translation>ایجاد نشانی جدید</translation>
</message>
@@ -42,6 +46,22 @@
<translation>&amp;حذف</translation>
</message>
<message>
+ <source>Choose the address to send coins to</source>
+ <translation>آدرس مورد نظر برای ارسال کوین ها را انتخاب کنید</translation>
+ </message>
+ <message>
+ <source>Choose the address to receive coins with</source>
+ <translation>آدرس موردنظر برای دریافت کوین ها را انتخاب کنید.</translation>
+ </message>
+ <message>
+ <source>Sending addresses</source>
+ <translation>آدرس های ارسال کننده</translation>
+ </message>
+ <message>
+ <source>Receiving addresses</source>
+ <translation>آدرس های دریافت کننده</translation>
+ </message>
+ <message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
<translation>این‌ها نشانی‌های بیت‌کوین شما برای ارسال وجود هستند. همیشه قبل از ارسال سکه‌ها، نشانی دریافت‌کننده و مقدار ارسالی را بررسی کنید.</translation>
</message>
@@ -322,6 +342,10 @@
<source>Bitcoin Core</source>
<translation> هسته Bitcoin </translation>
</message>
+ <message>
+ <source>&amp;About Bitcoin Core</source>
+ <translation>درباره هسته ی بیت کوین</translation>
+ </message>
<message numerus="yes">
<source>%n active connection(s) to Bitcoin network</source>
<translation><numerusform>%n ارتباط فعال با شبکهٔ بیت‌کوین</numerusform></translation>
@@ -401,10 +425,38 @@
<context>
<name>CoinControlDialog</name>
<message>
+ <source>Coin Selection</source>
+ <translation>انتخاب سکه</translation>
+ </message>
+ <message>
+ <source>Quantity:</source>
+ <translation>تعداد:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>بایت ها:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>مبلغ:</translation>
</message>
<message>
+ <source>Priority:</source>
+ <translation>اولویت:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>هزینه:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>هزینه ی پسین:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>پول خورد:</translation>
+ </message>
+ <message>
<source>Amount</source>
<translation>مبلغ</translation>
</message>
@@ -705,11 +757,7 @@
<source>Your current total balance</source>
<translation>تراز کل فعلی شما</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>ناهمگام</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
@@ -905,10 +953,34 @@
<translation>ارسال سکه</translation>
</message>
<message>
+ <source>Quantity:</source>
+ <translation>تعداد:</translation>
+ </message>
+ <message>
+ <source>Bytes:</source>
+ <translation>بایت ها:</translation>
+ </message>
+ <message>
<source>Amount:</source>
<translation>مبلغ:</translation>
</message>
<message>
+ <source>Priority:</source>
+ <translation>اولویت:</translation>
+ </message>
+ <message>
+ <source>Fee:</source>
+ <translation>هزینه:</translation>
+ </message>
+ <message>
+ <source>After Fee:</source>
+ <translation>هزینه ی پسین:</translation>
+ </message>
+ <message>
+ <source>Change:</source>
+ <translation>پول خورد:</translation>
+ </message>
+ <message>
<source>Send to multiple recipients at once</source>
<translation>ارسال به چند دریافت‌کنندهٔ به‌طور همزمان</translation>
</message>
diff --git a/src/qt/locale/bitcoin_fa_IR.ts b/src/qt/locale/bitcoin_fa_IR.ts
index 2dde67d3d5..da95f10474 100644
--- a/src/qt/locale/bitcoin_fa_IR.ts
+++ b/src/qt/locale/bitcoin_fa_IR.ts
@@ -390,11 +390,7 @@
<source>The displayed information may be out of date. Your wallet automatically synchronizes with the Bitcoin network after a connection is established, but this process has not completed yet.</source>
<translation>اطلاعات نمایش داده شده ممکن است روزآمد نباشد. wallet شما به صورت خودکار بعد از برقراری اتصال با شبکه bitcoin به روز می شود اما این فرایند هنوز تکمیل نشده است.</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>خارج از روزآمد سازی</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
</context>
diff --git a/src/qt/locale/bitcoin_fi.ts b/src/qt/locale/bitcoin_fi.ts
index 0ca66e8b26..db59ea1751 100644
--- a/src/qt/locale/bitcoin_fi.ts
+++ b/src/qt/locale/bitcoin_fi.ts
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Nykyinen tase seurantaosoitetteissa</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>Ei ajan tasalla</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_fr.ts b/src/qt/locale/bitcoin_fr.ts
index fe4288467b..67d920fd5e 100644
--- a/src/qt/locale/bitcoin_fr.ts
+++ b/src/qt/locale/bitcoin_fr.ts
@@ -1207,10 +1207,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Solde total actuel dans des adresses juste-regarder</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>désynchronisé</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -3273,6 +3269,10 @@ par exemple : alertnotify=echo %%s | mail -s "Alerte Bitcoin" admin@foo.com
<translation>Tester aléatoirement 1 message du réseau sur &lt;n&gt;</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Reconstruire au démarrage l'index de la chaîne de blocs à partir des fichiers blk000??.dat actuels</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Envoyer les informations de débogage/trace à la console au lieu du fichier debug.log</translation>
</message>
diff --git a/src/qt/locale/bitcoin_gl.ts b/src/qt/locale/bitcoin_gl.ts
index 93ece390d1..2473260c84 100644
--- a/src/qt/locale/bitcoin_gl.ts
+++ b/src/qt/locale/bitcoin_gl.ts
@@ -869,11 +869,7 @@
<source>Your current total balance</source>
<translation>O teu balance actual total</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>non sincronizado</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_he.ts b/src/qt/locale/bitcoin_he.ts
index 0a4b2f7847..66dd05fca7 100644
--- a/src/qt/locale/bitcoin_he.ts
+++ b/src/qt/locale/bitcoin_he.ts
@@ -1073,10 +1073,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>המאזן הכולל הנוכחי בכתובות לצפייה בלבד</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>לא בסנכרון</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_hu.ts b/src/qt/locale/bitcoin_hu.ts
index 0d9a57d3b4..c84d2c4e87 100644
--- a/src/qt/locale/bitcoin_hu.ts
+++ b/src/qt/locale/bitcoin_hu.ts
@@ -1001,11 +1001,7 @@
<source>Recent transactions</source>
<translation>A legutóbbi tranzakciók</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>Nincs szinkronban.</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_id_ID.ts b/src/qt/locale/bitcoin_id_ID.ts
index 7bc7ed4607..dec30dafb3 100644
--- a/src/qt/locale/bitcoin_id_ID.ts
+++ b/src/qt/locale/bitcoin_id_ID.ts
@@ -1005,11 +1005,7 @@
<source>Your current total balance</source>
<translation>Jumlah saldo Anda sekarang</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>tidak tersinkron</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_it.ts b/src/qt/locale/bitcoin_it.ts
index 2aa1e1da43..c81f458e39 100644
--- a/src/qt/locale/bitcoin_it.ts
+++ b/src/qt/locale/bitcoin_it.ts
@@ -168,6 +168,10 @@
<translation>Si è sicuri di voler cifrare il portamonete?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Bitcoin Core si chiuderà per portare a termine il processo di cifratura. Si ricorda che la cifratura del portamonete non garantisce protezione totale contro i furti causati da infezioni malware.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>IMPORTANTE: qualsiasi backup del file portamonete effettuato in precedenza dovrà essere sostituito con il file del portamonete cifrato appena generato. Per ragioni di sicurezza, i precedenti backup del file del portamonete non cifrato diventeranno inservibili non appena si inizierà ad utilizzare il nuovo portamonete cifrato.</translation>
</message>
@@ -184,6 +188,10 @@
<translation>Inserisci la nuova passphrase per il portamonete.&lt;br/&gt;Si consiglia di utilizzare &lt;b&gt;almeno dieci caratteri casuali&lt;/b&gt; oppure &lt;b&gt;otto o più parole&lt;/b&gt;.</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Inserisci la vecchia e la nuova passphrase per il portamonete.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Cifratura del portamonete fallita</translation>
</message>
@@ -391,6 +399,10 @@
<translation>&amp;Informazioni su Bitcoin Core</translation>
</message>
<message>
+ <source>Modify configuration options for Bitcoin Core</source>
+ <translation>Modifica opzioni di configurazione per Bitcoin Core</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>Mostra la lista degli indirizzi di invio utilizzati</translation>
</message>
@@ -419,6 +431,10 @@
<translation>Nessuna fonte di blocchi disponibile...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Elaborato %n blocco dello storico transazioni.</numerusform><numerusform>Elaborati %n blocchi dello storico transazioni.</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n ora</numerusform><numerusform>%n ore</numerusform></translation>
</message>
@@ -471,6 +487,36 @@
<translation>In aggiornamento...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>Data: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Quantità: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tipo: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etichetta: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Indirizzo: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Transazione inviata</translation>
</message>
@@ -669,6 +715,18 @@
<translation>nessuno</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>Questa etichetta diventerà rossa se la dimensione della transazione supererà i 1000 byte.</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>Questa etichetta diventerà rossa se la priorità sarà inferiore a "media".</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>Questa etichetta diventerà rossa se uno qualsiasi dei destinatari riceverà un importo inferiore a %1.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>Può variare di +/- %1 satoshi per input.</translation>
</message>
@@ -911,6 +969,14 @@
<translation>Indirizzo IP del proxy (ad es. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Riduci ad icona invece di uscire dall'applicazione quando la finestra viene chiusa. Attivando questa opzione l'applicazione terminerà solo dopo aver selezionato Esci dal menu File.</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>La lingua dell'interfaccia utente può essere impostata qui. L'applicazione delle modifiche avrà effetto dopo il riavvio di Bitcoin Core.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>URL di terze parti (ad es. un block explorer) che appaiono nella tabella delle transazioni come voci nel menu contestuale. "%s" nell'URL è sostituito dall'hash della transazione.
Per specificare più URL separarli con una barra verticale "|".</translation>
@@ -936,6 +1002,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Rete</translation>
</message>
<message>
+ <source>Automatically start Bitcoin Core after logging in to the system.</source>
+ <translation>Avvia automaticamente Bitcoin Core una volta effettuato l'accesso al sistema.</translation>
+ </message>
+ <message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>&amp;Avvia Bitcoin Core all'accesso al sistema</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = automatico, &lt;0 = lascia questo numero di core liberi)</translation>
</message>
@@ -1048,6 +1122,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>È necessario un riavvio del client per applicare le modifiche.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Il client sarà arrestato. Si desidera procedere?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>Questa modifica richiede un riavvio del client.</translation>
</message>
@@ -1130,10 +1208,6 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<source>Current total balance in watch-only addresses</source>
<translation>Saldo corrente totale negli indirizzi di sola lettura</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>non sincronizzato</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1186,10 +1260,18 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Impossibile leggere il file della richiesta di pagamento! Il file della richiesta di pagamento potrebbe non essere valido.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Richiesta di pagamento scaduta.</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>Le richieste di pagamento non verificate verso script di pagamento personalizzati non sono supportate.</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>Richiesta di pagamento non valida.</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Rimborso da %1</translation>
</message>
@@ -1229,6 +1311,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>User Agent</translation>
</message>
<message>
+ <source>Node/Service</source>
+ <translation>Nodo/Servizio</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Tempo di ping</translation>
</message>
@@ -1350,6 +1436,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Numero attuale di blocchi</translation>
</message>
<message>
+ <source>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Apre il file log di debug di Bitcoin Core dalla cartella dati attuale. Questa azione può richiedere alcuni secondi per file log di grandi dimensioni.</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Ricevuto</translation>
</message>
@@ -1418,6 +1508,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Tempo di Ping</translation>
</message>
<message>
+ <source>Time Offset</source>
+ <translation>Scarto Temporale</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Ora del blocco più recente</translation>
</message>
@@ -1462,6 +1556,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Cancella console</translation>
</message>
<message>
+ <source>Welcome to the Bitcoin Core RPC console.</source>
+ <translation>Benvenuto nella console RPC di Bitcoin Core.</translation>
+ </message>
+ <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Usa le frecce direzionali per scorrere la cronologia, e &lt;b&gt;Ctrl-L&lt;/b&gt; per cancellarla.</translation>
</message>
@@ -1758,6 +1856,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Se la commissione personalizzata è impostata su 1000 satoshi e la transazione è di soli 250 byte, allora "per kilobyte" paga solo 250 satoshi di commissione, mentre "somma almeno" paga 1000 satoshi. Per transazioni più grandi di un kilobyte, entrambe le opzioni pagano al kilobyte.</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation>Nascondi</translation>
+ </message>
+ <message>
<source>total at least</source>
<translation>somma almeno</translation>
</message>
@@ -1898,10 +2000,26 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>La transazione è stata respinta! Questo può accadere se alcuni bitcoin nel tuo portamonete sono già stati spesi, come nel caso in cui tu avessi utilizzato una copia del file wallet.dat per spendere bitcoin e questi non fossero stati considerati come spesi dal portamonete corrente.</translation>
</message>
<message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Una commissione maggiore di %1 è considerata irragionevolmente elevata.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Richiesta di pagamento scaduta.</translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>Paga solamente la commissione minima di %1</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>L'indirizzo del beneficiario non è valido. Si prega di ricontrollare.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Rilevato un indirizzo duplicato Ciascun indirizzo dovrebbe essere utilizzato una sola volta.</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Attenzione: Indirizzo Bitcoin non valido</translation>
</message>
@@ -1973,10 +2091,26 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Rimuovi questa voce</translation>
</message>
<message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>La commissione sarà sottratta dall'importo che si sta inviando. Il beneficiario riceverà un totale di bitcoin inferiore al valore digitato. Nel caso in cui siano stati selezionati più beneficiari la commissione sarà suddivisa in parti uguali.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>S&amp;ottrae la commissione dall'importo</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Messaggio:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Questa è una richiesta di pagamento non autenticata.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Questa è una richiesta di pagamento autenticata.</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation>Inserisci un'etichetta per questo indirizzo per aggiungerlo alla lista degli indirizzi utilizzati</translation>
</message>
@@ -2015,6 +2149,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Firma Messaggio</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>È possibile firmare messaggi/accordi con i propri indirizzi in modo da dimostrare di poter ricevere bitcoin attraverso di essi. Si consiglia di prestare attenzione a non firmare dichiarazioni vaghe o casuali, attacchi di phishing potrebbero cercare di indurre ad apporre la firma su di esse. Si raccomanda di firmare esclusivamente dichiarazioni completamente dettagliate e delle quali si condivide in pieno il contenuto.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>L'indirizzo Bitcoin da utilizzare per firmare il messaggio</translation>
</message>
@@ -2067,6 +2205,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>&amp;Verifica Messaggio</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>Per verificare il messaggio inserire l'indirizzo del firmatario, il messaggio e la firma nei campi sottostanti, assicurandosi di copiare esattamente anche ritorni a capo, spazi, tabulazioni, etc.. Si raccomanda di non lasciarsi fuorviare dalla firma a leggere più di quanto non sia riportato nel testo del messaggio stesso, in modo da evitare di cadere vittima di attacchi di tipo man-in-the-middle. Si ricorda che la verifica della firma dimostra soltanto che il firmatario può ricevere pagamenti con l'indirizzo corrispondente, non prova l'invio di alcuna transazione.</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>L'indirizzo Bitcoin con cui è stato contrassegnato il messaggio</translation>
</message>
@@ -2418,6 +2560,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Indica se un indirizzo di sola lettura sia o meno coinvolto in questa transazione.</translation>
</message>
<message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Intento/scopo della transazione definito dall'utente.</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>Importo rimosso o aggiunto al saldo.</translation>
</message>
@@ -2660,6 +2806,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Associa all'indirizzo indicato e resta permanentemente in ascolto su di esso. Usa la notazione [host]:porta per l'IPv6</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>Limita la quantità di transazioni gratuite ad &lt;n&gt;*1000 byte al minuto (predefinito: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Elimina tutte le transazioni dal portamonete e recupera solo quelle che fanno parte della blockchain attraverso il comando -rescan all'avvio.</translation>
</message>
@@ -2680,6 +2830,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>In questa modalità -genproclimit determina quanti blocchi saranno generati immediatamente.</translation>
</message>
<message>
+ <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source>
+ <translation>Commissioni massime totali da includere in una singola transazione dal portamonete. Un'impostazione troppo bassa potrebbe provocare l'annullamento di transazioni di grosse dimensioni (predefinito: %s)</translation>
+ </message>
+ <message>
+ <source>Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
+ <translation>Riduce i requisiti di spazio di archiviazione attraverso la rimozione dei vecchi blocchi (pruning). Questa modalità disabilita le funzionalità di portamonete ed è incompatibile con l'opzione -txindex. Attenzione: il ripristinando questa opzione l'intera blockchain dovrà essere riscaricata. (predefinito: 0 = disabilita il pruning, &gt;%u = dimensione desiderata in MiB per i file dei blocchi)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Imposta il numero di thread per la verifica degli script (da %u a %d, 0 = automatico, &lt;0 = lascia questo numero di core liberi, predefinito: %d)</translation>
</message>
@@ -2808,6 +2966,14 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Connessione ai soli nodi appartenenti alla rete &lt;net&gt; (ipv4, ipv6 o Tor)</translation>
</message>
<message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>La modalità prune non può essere configurata con un valore negativo.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>La modalità prune è incompatibile con l'opzione -txindex.</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Imposta la dimensione della cache del database in megabyte (%d a %d, predefinito: %d)</translation>
</message>
@@ -2844,6 +3010,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Opzioni portamonete:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>Attenzione: questa versione è obsoleta. Aggiornamento necessario!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>È necessario ricostruire il database usando -reindex per cambiare -txindex</translation>
</message>
@@ -2872,6 +3042,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Crea nuovi file con i permessi di default del sistema, invece che con umask 077 (ha effetto solo con funzionalità di portamonete disabilitate)</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Scopre i propri indirizzi IP (predefinito: 1 se in ascolto ed -externalip o -proxy non sono specificati)</translation>
+ </message>
+ <message>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation>Errore: attesa per connessioni in arrivo fallita (errore riportato %s)</translation>
</message>
@@ -2904,10 +3078,22 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Dimensione massima dei dati in transazioni di trasporto dati che saranno trasmesse ed incluse nei blocchi (predefinito: %u)</translation>
</message>
<message>
+ <source>Prune configured below the minimum of %d MB. Please use a higher number.</source>
+ <translation>La modalità prune è configurata al di sotto del minimo di %d MB. Si prega di utilizzare un valore più elevato.</translation>
+ </message>
+ <message>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
<translation>Ottiene gli indirizzi dei peer attraverso interrogazioni DNS, in caso di scarsa disponibilità (predefinito: 1 a meno che -connect non sia specificato)</translation>
</message>
<message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>Randomizza le credenziali per ogni connessione proxy. Permette la Tor stream isolation (predefinito: %u)</translation>
+ </message>
+ <message>
+ <source>Require high priority for relaying free or low-fee transactions (default: %u)</source>
+ <translation>Richiedi alta priorità per la trasmissione di transazioni a zero o basse commissioni (predefinito: %u)</translation>
+ </message>
+ <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Imposta la dimensione massima in byte delle transazioni ad alta-priorità/basse-commissioni (predefinito: %d)</translation>
</message>
@@ -2916,6 +3102,10 @@ Per specificare più URL separarli con una barra verticale "|".</translation>
<translation>Specifica il numero di thread per la generazione di bitcoin, se abilitata (-1 = tutti i core, predefinito: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>L'importo della transazione risulta troppo basso per l'invio una volta dedotte le commissioni.</translation>
+ </message>
+ <message>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation>Questo prodotto include software sviluppato dal progetto OpenSSL per l'uso del Toolkit OpenSSL &lt;https://www.openssl.org/&gt;, software crittografico scritto da Eric Young e software UPnP scritto da Thomas Bernard.</translation>
</message>
@@ -2955,6 +3145,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d
<translation>I peer inclusi in whitelist non possono subire ban per DoS e le loro transazioni saranno sempre trasmesse, anche nel caso in cui si trovino già nel mempool. Ciò è utile ad es. per i gateway</translation>
</message>
<message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>Per ritornare alla modalità unpruned sarà necessario ricostruire il database utilizzando l'opzione -reindex. L'intera blockchain sarà riscaricata.</translation>
+ </message>
+ <message>
<source>(default: %u)</source>
<translation>(default: %u)</translation>
</message>
@@ -2963,6 +3157,18 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d
<translation>Accetta richieste REST pubbliche (predefinito: %u)</translation>
</message>
<message>
+ <source>Activating best chain...</source>
+ <translation>Attivazione della blockchain migliore...</translation>
+ </message>
+ <message>
+ <source>Allow self signed root certificates (default: 0)</source>
+ <translation>Permette certificati radice auto-firmati (predefinito: 0)</translation>
+ </message>
+ <message>
+ <source>Can't run with a wallet in prune mode.</source>
+ <translation>Impossibile operare con un portamonete in modalità prune.</translation>
+ </message>
+ <message>
<source>Cannot resolve -whitebind address: '%s'</source>
<translation>Impossibile risolvere indirizzo -whitebind: '%s'</translation>
</message>
@@ -3095,6 +3301,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d
<translation>Avvia ridotto a icona</translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>L'importo della transazione è troppo basso per pagare la commissione</translation>
+ </message>
+ <message>
<source>This is experimental software.</source>
<translation>Questo è un software sperimentale.</translation>
</message>
@@ -3115,6 +3325,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d
<translation>Transazione troppo grande</translation>
</message>
<message>
+ <source>UI Options:</source>
+ <translation>Opzioni Interfaccia Utente:</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation>Impossibile associarsi a %s su questo computer (l'associazione ha restituito l'errore %s)</translation>
</message>
@@ -3279,6 +3493,10 @@ Si raccomanda inoltre di configurare alertnotify in modo da ricevere notifiche d
<translation>Mantiene al massimo &lt;n&gt; connessioni verso i peer (predefinito: %u)</translation>
</message>
<message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>Configura il portamonete per la trasmissione di transazioni</translation>
+ </message>
+ <message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation>Buffer di ricezione massimo per connessione, &lt;n&gt;*1000 byte (predefinito: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ja.ts b/src/qt/locale/bitcoin_ja.ts
index 329141edff..376d36bed0 100644
--- a/src/qt/locale/bitcoin_ja.ts
+++ b/src/qt/locale/bitcoin_ja.ts
@@ -168,6 +168,10 @@
<translation>本当にウォレットを暗号化しますか?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>暗号化処理を完了させるため Bitcoin Core をいますぐ終了します。ウォレットの暗号化では、コンピュータに感染したマルウェアなどによるビットコインの盗難から完全に守ることはできないことにご注意ください。</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>重要: 過去のウォレット ファイルのバックアップは、暗号化された新しいウォレット ファイルに取り替える必要があります。セキュリティ上の理由により、暗号化された新しいウォレットを使い始めると、暗号化されていないウォレット ファイルのバックアップはすぐに使えなくなります。</translation>
</message>
@@ -184,6 +188,10 @@
<translation>ウォレットの新しいパスフレーズを入力してください。&lt;br/&gt;&lt;b&gt;10文字以上のランダムな文字&lt;/b&gt;で構成されたものか、&lt;b&gt;8単語以上の単語&lt;/b&gt;で構成されたパスフレーズを使用してください。</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>ウォレットの古いパスフレーズおよび新しいパスフレーズを入力してください。</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>ウォレットの暗号化に失敗しました</translation>
</message>
@@ -391,6 +399,10 @@
<translation>ビットコインコアについて (&amp;A)</translation>
</message>
<message>
+ <source>Modify configuration options for Bitcoin Core</source>
+ <translation>Bitcoin Core の設定を編集する</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>使用済みの送金用アドレスとラベルの一覧を表示する</translation>
</message>
@@ -419,6 +431,10 @@
<translation>利用可能なブロックがありません...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>トランザクション履歴の %n ブロックを処理しました。</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n 時間</numerusform></translation>
</message>
@@ -471,6 +487,36 @@
<translation>追跡中...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>日付: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>総額: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>タイプ: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>ラベル: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>アドレス: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>送金取引</translation>
</message>
@@ -669,6 +715,18 @@
<translation>なし</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>トランザクションのサイズが1000バイトを超える場合にはこのラベルは赤色になります。</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>優先度が「中」未満の場合、このラベルは赤色になります。</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>受取人のうち誰かの受取額が %1 未満の場合にこのラベルは赤色になります。</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>ひとつの入力につき %1 satoshi 前後ずれることがあります。</translation>
</message>
@@ -919,6 +977,14 @@
<translation>プロキシのIPアドレス (例えば IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>ウィンドウを閉じる際にアプリケーションを終了するのではなく、最小化します。このオプションが有効化された場合、メニューから終了を選択した場合にのみアプリケーションは閉じられます。</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>ユーザ・インタフェイス言語はここで設定できます。この設定はBitcoin Coreの再起動後に有効となります。</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>トランザクションタブのコンテキストメニュー項目に表示する、サードパーティURL (例えばブロックエクスプローラ)。URL中の%sはトランザクションのハッシュ値に置き換えられます。垂直バー | で区切ることで、複数のURLを指定できます。</translation>
</message>
@@ -943,6 +1009,14 @@
<translation>ネットワーク (&amp;N)</translation>
</message>
<message>
+ <source>Automatically start Bitcoin Core after logging in to the system.</source>
+ <translation>システムにログインした際、自動的にBitcoin Coreを起動する。</translation>
+ </message>
+ <message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>システムへログインした際にBitcoin Coreを起動する (&amp;S)</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = 自動、0以上 = 指定した数のコアをフリーにする)</translation>
</message>
@@ -1055,6 +1129,10 @@
<translation>変更を有効化するにはクライアントを再起動する必要があります。</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>クライアントを終了します。続行してもよろしいですか?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>この変更はクライアントの再起動が必要です。</translation>
</message>
@@ -1137,10 +1215,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>監視限定アドレス内の現在の全残高</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>同期していない</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1193,10 +1267,18 @@
<translation>支払いリクエストファイルを読み込めませんでした!無効な支払いリクエストファイルにより引き起こされた可能性があります。</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>支払いリクエストの期限が切れました。</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>カスタム支払いスクリプトに対する、検証されていない支払いリクエストはサポートされていません。</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>無効な支払いリクエスト。</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>%1 からの返金</translation>
</message>
@@ -1236,6 +1318,10 @@
<translation>ユーザエージェント</translation>
</message>
<message>
+ <source>Node/Service</source>
+ <translation>ノード・サービス</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Ping時間</translation>
</message>
@@ -1357,6 +1443,10 @@
<translation>現在のブロック数</translation>
</message>
<message>
+ <source>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>現在のデータディレクトリからBitcoin Coreのデバッグ用ログファイルを開きます。ログファイルが巨大な場合、数秒かかることがあります。</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>受取</translation>
</message>
@@ -1425,6 +1515,10 @@
<translation>Ping時間</translation>
</message>
<message>
+ <source>Time Offset</source>
+ <translation>時間オフセット</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>最終ブロックの日時</translation>
</message>
@@ -1469,6 +1563,10 @@
<translation>コンソールをクリア</translation>
</message>
<message>
+ <source>Welcome to the Bitcoin Core RPC console.</source>
+ <translation>Bitcoin CoreのRPCコンソールへようこそ。</translation>
+ </message>
+ <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>上下の矢印で履歴をたどれます。 &lt;b&gt;Ctrl-L&lt;/b&gt; でスクリーンを消去できます。</translation>
</message>
@@ -1765,6 +1863,10 @@
<translation>カスタム手数料が1000satoshiに設定されている場合、トランザクションサイズが250バイトとすると、「1キロバイトあたり手数料」では250satoshiの手数料のみを支払いますが、「最小手数料」では1000satoshiを支払います。1キロバイトを超えるトランザクションの場合には、どちらの方法を選択したとしても1キロバイトあたりで支払われます。</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation>隠す</translation>
+ </message>
+ <message>
<source>total at least</source>
<translation>最小手数料</translation>
</message>
@@ -1905,10 +2007,30 @@
<translation>トランザクションは拒否されました。wallet.dat のコピーを使い、そしてコピーしたウォレットからコインを使用したことがマークされなかったときなど、ウォレットのいくつかのコインがすでに使用されている場合に、このエラーは起こるかもしれません。</translation>
</message>
<message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>%1 よりも高い手数料の場合、手数料が高すぎると判断されます。</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>支払いリクエストの期限が切れました。</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>%n ブロック以内に検証が開始されると予想されます。</numerusform></translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>最小手数料 %1 のみを支払う</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>受取アドレスが不正です。再チェックしてください。</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>重複したアドレスが見つかりました: アドレスはそれぞれ一度のみ使用することができます。</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>警告:無効なBitcoinアドレスです</translation>
</message>
@@ -1980,10 +2102,26 @@
<translation>この項目を削除する</translation>
</message>
<message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>送金する金額から手数料が差し引かれます。受取人は数量フィールドで指定した量よりも少ないビットコインを受け取ります。受取人が複数いる場合には、手数料は均等割されます。</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>送金額から手数料を差し引く (&amp;U)</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>メッセージ:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>これは未認証の支払いリクエストです。</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>これは認証済みの支払いリクエストです。</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation>このアドレスに対するラベルを入力することで、使用済みアドレスの一覧に追加することができます</translation>
</message>
@@ -2022,6 +2160,10 @@
<translation>メッセージの署名 (&amp;S)</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>あなたの所有しているアドレスによりメッセージや合意書に署名をすることで、それらアドレスに対して送られたビットコインを受け取ることができることを証明できます。フィッシング攻撃により不正にあなたの識別情報を署名させられてしまうことを防ぐために、不明確なものやランダムなものに対して署名しないよう注意してください。合意することが可能な、よく詳細の記された文言にのみ署名するようにしてください。</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>メッセージを署名するBitcoinアドレス</translation>
</message>
@@ -2074,6 +2216,10 @@
<translation>メッセージの検証 (&amp;V)</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>受取人のアドレスとメッセージ(改行やスペース、タブなども完全に一致するよう注意してください)および署名を以下に入力し、メッセージの署名を検証してください。中間者攻撃により騙されるのを防ぐため、署名対象のメッセージに書かれていること以上の意味を署名から読み取ろうとしないよう注意してください。これは署名作成者がこのアドレスで受け取ったことを証明するだけであり、トランザクションの送信権限を証明するものではないことに注意してください!</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>メッセージの署名に使われたBitcoinアドレス</translation>
</message>
@@ -2425,6 +2571,10 @@
<translation>監視限定アドレスがこのトランザクションに含まれているかどうか</translation>
</message>
<message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>ユーザ定義のトランザクションの意図や目的。</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>残高に追加または削除された総額。</translation>
</message>
@@ -2667,6 +2817,10 @@
<translation>指定のアドレスへバインドし、その上で常にリスンします。IPv6 は [ホスト名]:ポート番号 と表記します</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>継続的に無料トランザクションのレートを一分間に&lt;n&gt;*1000バイトに制限する (規定値: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>ウォレットの全トランザクションを削除し、これらを-rescanオプションを用いることで起動時にブロックチェインのデータのみからリカバリします。</translation>
</message>
@@ -2687,6 +2841,14 @@
<translation>このモードでは -genproclimit は何個のブロックをただちに生成するのか制御します。</translation>
</message>
<message>
+ <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source>
+ <translation>ひとつのウォレットトランザクションで使用する合計手数料の最大値。低すぎる値を指定すると巨大なトランザクションの作成ができなくなります (規定値: %s)</translation>
+ </message>
+ <message>
+ <source>Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
+ <translation>古いブロックを剪定する(削除する)ことで記憶容量の必要量を削減する。このモードを有効にするとウォレット機能のサポートは無効になり、-txindexとも互換性がなくなります。警告: この設定の再有効化には全ブロックチェインの再ダウンロードが必要となります。(規定値: 0 = ブロックの剪定無効、&gt;%u = ブロックファイルに使用するMiB単位の目標サイズ)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>スクリプト検証スレッドを設定 (%uから%dの間, 0 = 自動, &lt;0 = たくさんのコアを自由にしておく, 初期値: %d)</translation>
</message>
@@ -2816,6 +2978,14 @@
<translation>&lt;net&gt; (ipv4, ipv6 または onion) ネットワーク内のノードだけに接続する</translation>
</message>
<message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>剪定値は負の値に設定できません。</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>剪定モードは-txindexと互換性がありません。</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>データベースのキャッシュサイズをメガバイトで設定 (%dから%d。初期値: %d)</translation>
</message>
@@ -2852,6 +3022,10 @@
<translation>ウォレットオプション:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>警告: このバージョンはサポートされません。アップグレードが必要です!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>-txindex を変更するには -reindex を使用してデータベースを再構築する必要があります</translation>
</message>
@@ -2884,6 +3058,10 @@
<translation>umask 077 ではなく、システムのデフォルトパーミッションで新規ファイルを作成する (ウォレット機能が無効化されていた場合にのみ有効)</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>自分のIPアドレスを解決する (規定値: リッスンをしており、-externalipまたは-proxyオプションが指定されていない場合は1)</translation>
+ </message>
+ <message>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation>エラー: 内向きの接続をリッスンするのに失敗しました (エラー %s が返却されました)</translation>
</message>
@@ -2916,10 +3094,22 @@
<translation>中継および採掘を行う際の、データ運送トランザクションの中のデータの最大サイズ (初期値: %u)</translation>
</message>
<message>
+ <source>Prune configured below the minimum of %d MB. Please use a higher number.</source>
+ <translation>剪定が最小値の %d MB以下に設定されています。もっと大きな値を使用してください。</translation>
+ </message>
+ <message>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
<translation>保有するピアアドレスが少ない場合、DNS ルックアップによりピアアドレスを問い合わせる (-connect を使っていない場合の初期値: 1)</translation>
</message>
<message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>認証情報をプロキシー接続ごとにランダム化する。これによりTorストリーム分離をすることができます (規定値: %u)</translation>
+ </message>
+ <message>
+ <source>Require high priority for relaying free or low-fee transactions (default: %u)</source>
+ <translation>無料や低い手数料のトランザクションのリレーに際し、高い優先度を要求する (規定値: %u)</translation>
+ </message>
+ <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>最優先/最低手数料の最大サイズをバイトで指定 (初期値: %d)</translation>
</message>
@@ -2928,6 +3118,10 @@
<translation>コイン生成が有効になっていた場合の利用スレッド数を設定する (-1 = すべてのコア, 初期値: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>手数料差引後のトランザクションの金額が小さすぎるため、送金できません。</translation>
+ </message>
+ <message>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation>この製品はOpenSSLプロジェクトにより開発されたソフトウェアをOpenSSLツールキットとして利用しています &lt;https://www.openssl.org/&gt;。また、Eric Young氏により開発された暗号ソフトウェア、Thomas Bernard氏により書かれたUPnPソフトウェアを用いています。</translation>
</message>
@@ -2968,10 +3162,30 @@ rpcpassword=%s
<translation>ホワイトリストのピアはDoSによるアクセス禁止処理が無効化され、トランザクションは例えmempool内に既に存在していたとしても常にリレーされます。これは例えばゲートウェイに対して有用です</translation>
</message>
<message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>非剪定モードに戻るためには-reindexオプションを使用してデータベースを再構築する必要があります。これによりブロックチェイン全体の再ダウンロードが行われます。</translation>
+ </message>
+ <message>
+ <source>(default: %u)</source>
+ <translation>(規定値: %u)</translation>
+ </message>
+ <message>
<source>Accept public REST requests (default: %u)</source>
<translation>公開 REST リクエストを許可する (初期値: %u)</translation>
</message>
<message>
+ <source>Activating best chain...</source>
+ <translation>最優良のチェインを有効化しています...</translation>
+ </message>
+ <message>
+ <source>Allow self signed root certificates (default: 0)</source>
+ <translation>自己署名ルート証明書を許可する (規定値: 0)</translation>
+ </message>
+ <message>
+ <source>Can't run with a wallet in prune mode.</source>
+ <translation>剪定モードではウォレット機能付きで起動できません。</translation>
+ </message>
+ <message>
<source>Cannot resolve -whitebind address: '%s'</source>
<translation>-whitebind アドレス '%s' を解決できません</translation>
</message>
@@ -3068,6 +3282,10 @@ rpcpassword=%s
<translation>&lt;n&gt;個のネットワークメッセージごとにひとつをランダムに改変する</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>起動時に現在の blk000??.dat ファイルからブロック チェーンのインデックスを再構築</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>トレース/デバッグ情報を debug.log ファイルの代わりにコンソールへ送る</translation>
</message>
@@ -3104,6 +3322,10 @@ rpcpassword=%s
<translation>最小化された状態で起動する</translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>トランザクションの金額が小さすぎて手数料を支払えません</translation>
+ </message>
+ <message>
<source>This is experimental software.</source>
<translation>これは実験的なソフトウェアです。</translation>
</message>
@@ -3124,6 +3346,10 @@ rpcpassword=%s
<translation>取引が大き過ぎます</translation>
</message>
<message>
+ <source>UI Options:</source>
+ <translation>UIオプション:</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation>このコンピュータの %s にバインドすることができません (バインドが返したエラーは %s)</translation>
</message>
@@ -3288,6 +3514,10 @@ rpcpassword=%s
<translation>ピアの接続数を最大でも &lt;n&gt; 個に維持する (初期値: %u)</translation>
</message>
<message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>ウォレットのトランザクションをブロードキャストする</translation>
+ </message>
+ <message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation>接続毎の最大受信バッファ &lt;n&gt;*1000 バイト (初期値: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ka.ts b/src/qt/locale/bitcoin_ka.ts
index 0b96a18d18..b9e118a620 100644
--- a/src/qt/locale/bitcoin_ka.ts
+++ b/src/qt/locale/bitcoin_ka.ts
@@ -981,11 +981,7 @@
<source>Your current total balance</source>
<translation>თქვენი სრული მიმდინარე ბალანსი</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>არ არის სინქრონიზებული</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_ko_KR.ts b/src/qt/locale/bitcoin_ko_KR.ts
index d9ce8ea1be..42eb9eedbb 100644
--- a/src/qt/locale/bitcoin_ko_KR.ts
+++ b/src/qt/locale/bitcoin_ko_KR.ts
@@ -1025,11 +1025,7 @@
<source>Your current balance in watch-only addresses</source>
<translation>모니터링 지갑의 현재 잔액</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>동기화 필요</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_ky.ts b/src/qt/locale/bitcoin_ky.ts
index 7d4511b57d..8edee19c70 100644
--- a/src/qt/locale/bitcoin_ky.ts
+++ b/src/qt/locale/bitcoin_ky.ts
@@ -149,11 +149,7 @@
</context>
<context>
<name>OverviewPage</name>
- <message>
- <source>out of sync</source>
- <translation>синхрондоштурулган эмес</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
</context>
diff --git a/src/qt/locale/bitcoin_la.ts b/src/qt/locale/bitcoin_la.ts
index 8f03a20cf6..3e25cf95b6 100644
--- a/src/qt/locale/bitcoin_la.ts
+++ b/src/qt/locale/bitcoin_la.ts
@@ -601,11 +601,7 @@
<source>Mined balance that has not yet matured</source>
<translation>Fossum pendendum quod nondum maturum est</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>non synchronizato</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_lt.ts b/src/qt/locale/bitcoin_lt.ts
index b96afbbcc9..01fa94bab3 100644
--- a/src/qt/locale/bitcoin_lt.ts
+++ b/src/qt/locale/bitcoin_lt.ts
@@ -737,11 +737,7 @@
<source>Your current total balance</source>
<translation>Jūsų balansas</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nesinchronizuota</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_lv_LV.ts b/src/qt/locale/bitcoin_lv_LV.ts
index a46ab83c6b..25f92b6642 100644
--- a/src/qt/locale/bitcoin_lv_LV.ts
+++ b/src/qt/locale/bitcoin_lv_LV.ts
@@ -933,11 +933,7 @@
<source>Your current total balance</source>
<translation>Jūsu kopējā tekošā bilance</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nav sinhronizēts</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_nb.ts b/src/qt/locale/bitcoin_nb.ts
index c42cf52212..6e2b4e9fcc 100644
--- a/src/qt/locale/bitcoin_nb.ts
+++ b/src/qt/locale/bitcoin_nb.ts
@@ -431,6 +431,10 @@
<translation>Ingen kilde for blokker tilgjengelig...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Lastet %n blokk med transaksjonshistorikk.</numerusform><numerusform>Lastet %n blokker med transaksjonshistorikk.</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n time</numerusform><numerusform>%n timer</numerusform></translation>
</message>
@@ -977,6 +981,10 @@
<translation>Minimer i stedet for å avslutte applikasjonen når vinduet lukkes. Når dette er valgt, vil applikasjonen avsluttes kun etter at Avslutte er valgt i menyen.</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>Språk for brukergrensesnittet kan velges her. Denne innstillingen trer i kraft etter omstart av Bitcoin Core.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>Tredjepart URLer (f. eks. en blokkutforsker) som dukker opp i transaksjonsfanen som kontekst meny elementer. %s i URLen er erstattet med transaksjonen sin hash. Flere URLer er separert av en vertikal linje |.</translation>
</message>
@@ -1001,6 +1009,14 @@
<translation>&amp;Nettverk</translation>
</message>
<message>
+ <source>Automatically start Bitcoin Core after logging in to the system.</source>
+ <translation>Start Bitcoin Core automatisk ved oppstart av datamaskinen.</translation>
+ </message>
+ <message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>&amp;Start Bitcoin Core ved oppstart av datamaskinen</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = automatisk, &lt;0 = la så mange kjerner være ledig)</translation>
</message>
@@ -1113,6 +1129,10 @@
<translation>Omstart av klienten er nødvendig for å aktivere endringene.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Klienten vil bli lukket. Ønsker du å gå videre?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>Denne endringen krever omstart av klienten.</translation>
</message>
@@ -1195,10 +1215,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Nåværende totale balanse i kun observerbare adresser</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>ute av synk</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1251,10 +1267,18 @@
<translation>Betalingsetterspørringsfil kan ikke leses! Dette kan være forårsaket av en ugyldig betalingsetterspørringsfil.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsetterspørringen har utløpt.</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>Uverifiserte betalingsforespørsler til egentilpassede betalingscript er ikke støttet.</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>Ugyldig betalingsetterspørring.</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Refundering fra %1</translation>
</message>
@@ -1294,6 +1318,10 @@
<translation>Brukeragent</translation>
</message>
<message>
+ <source>Node/Service</source>
+ <translation>Node/Tjeneste</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Ping-tid</translation>
</message>
@@ -1415,6 +1443,10 @@
<translation>Nåværende antall blokker</translation>
</message>
<message>
+ <source>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Åpne Bitcoin Core sin loggfil for feilsøk fra gjeldende datamappe. Dette kan ta noen sekunder for store loggfiler.</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Mottatt</translation>
</message>
@@ -1483,6 +1515,10 @@
<translation>Ping-tid</translation>
</message>
<message>
+ <source>Time Offset</source>
+ <translation>Tidsforskyvning</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Tidspunkt for siste blokk</translation>
</message>
@@ -1527,6 +1563,10 @@
<translation>Tøm konsoll</translation>
</message>
<message>
+ <source>Welcome to the Bitcoin Core RPC console.</source>
+ <translation>Velkommen til Bitcoin Core sin RPC-konsoll.</translation>
+ </message>
+ <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Bruk opp og ned pil for å navigere historikken, og &lt;b&gt;Ctrl-L&lt;/b&gt; for å tømme skjermen.</translation>
</message>
@@ -1967,10 +2007,30 @@
<translation>Transaksjonen ble avvist! Dette kan skje hvis noen av myntene i lommeboken allerede er brukt, som hvis du kopierte wallet.dat og mynter ble brukt i kopien uten å bli markert som brukt her.</translation>
</message>
<message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>Et gebyr høyere enn %1 er ansett som et absurd høyt gebyr.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Betalingsetterspørringen har utløpt.</translation>
+ </message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>Anslått til å begynne bekreftelse innen %n blokk.</numerusform><numerusform>Anslått til å begynne bekreftelse innen %n blokker.</numerusform></translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>Betal kun minimumsgebyret på %1</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Mottakeradressen er ikke gyldig. Vennligst kontroller på nytt.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Gjenbruk av adresse funnet: adresser skal bare brukes en gang hver.</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Advarsel: Ugyldig Bitcoin-adresse</translation>
</message>
@@ -2042,10 +2102,26 @@
<translation>Fjern denne oppføringen</translation>
</message>
<message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>Gebyret vil bli trukket fra beløpet som blir sendt. Mottakeren vil motta mindre bitcoins enn det du skriver inn i beløpsfeltet. Hvis det er valgt flere mottakere, deles gebyret likt.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>T&amp;rekk fra gebyr fra beløp</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Melding:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Dette er en uautorisert betalingsetterspørring.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Dette er en autorisert betalingsetterspørring.</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation>Skriv inn en merkelapp for denne adressen for å legge den til listen av brukte adresser</translation>
</message>
@@ -2084,6 +2160,10 @@
<translation>&amp;Signer Melding</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>Du kan signere meldinger/avtaler med adresser for å bevise at du kan motta bitcoins sendt til dem. Vær forsiktig med å signere noe vagt eller tilfeldig, siden phishing-angrep kan prøve å lure deg til å signere din identitet over til dem. Bare signer fullt detaljerte utsagn som du er enig i.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>Bitcoin-adressen meldingen skal signeres med</translation>
</message>
@@ -2136,6 +2216,10 @@
<translation>&amp;Verifiser Melding</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>Skriv inn mottakerens adresse, melding (forsikre deg om at du kopier linjeskift, mellomrom, faner osv. nøyaktig) og underskrift nedenfor for å bekrefte meldingen. Vær forsiktig så du ikke leser mer ut av signaturen enn hva som er i den signerte meldingen i seg selv, for å unngå å bli lurt av et man-in-the-middle-angrep. Merk at dette bare beviser at den som signerer kan motta med adressen, dette beviser ikke hvem som har sendt transaksjoner!</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>Bitcoin-adressen meldingen ble signert med</translation>
</message>
@@ -2487,6 +2571,10 @@
<translation>Hvorvidt en kun observerbar adresse er involvert i denne transaksjonen.</translation>
</message>
<message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Brukerdefinert intensjon/hensikt med transaksjonen.</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>Beløp fjernet eller lagt til saldo.</translation>
</message>
@@ -2729,6 +2817,10 @@
<translation>Bind til angitt adresse. Bruk [vertsmaskin]:port notasjon for IPv6</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>Ratebegrens gratistransaksjoner kontinuerlig til &lt;n&gt;*1000 bytes per minutt (standardverdi: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Slett alle transaksjoner i lommeboken og gjenopprett kun de delene av blokkjeden gjennom -rescan ved oppstart</translation>
</message>
@@ -2749,6 +2841,14 @@
<translation>I denne modusen kontrollerer -genproclimit hvor mange blokker som genereres øyeblikkelig.</translation>
</message>
<message>
+ <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source>
+ <translation>Maksimalt samlede gebyrer til å bruke i en enkelt lommeboktransaksjon; settes dette for lavt kan store transaksjoner kanskje avbrytes (standardverdi: %s)</translation>
+ </message>
+ <message>
+ <source>Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
+ <translation>Reduser lagringsbehovet ved beskjæring (slette) gamle blokker. Denne modusen deaktiverer støtte for lommebok og er ikke kompatibel med -txindex. Advarsel: Tilbakestilling av denne innstillingen krever at hele blokkjeden må lastes ned på nytt. (Standardverdi: 0 = deaktiver beskjæringsblokker, &gt;%u = mål for størrelse i MiB å bruke for blokkfiler)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Angi antall tråder for skriptverifisering (%u til %d, 0 = auto, &lt;0 = la det antallet kjerner være ledig, standard: %d)</translation>
</message>
@@ -2921,6 +3021,10 @@
<translation>Valg for lommebok:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>Advarsel: Denne versjonen er utdatert; oppgradering er påkrevd!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>Du må gjenoppbygge databasen med å bruke -reindex for å endre -txindex</translation>
</message>
@@ -2953,6 +3057,10 @@
<translation>Opprett nye filer med standardtillatelser i systemet, i stedet for umask 077 (kun virksom med lommebokfunksjonalitet slått av)</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Oppdag egne IP-adresser (standardverdi: 1 ved lytting og ingen -externalip eller -proxy)</translation>
+ </message>
+ <message>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation>Feil: Lytting etter innkommende tilkoblinger feilet (lytting returnerte feil %s)</translation>
</message>
@@ -2993,6 +3101,14 @@
<translation>Søk etter nodeadresser via DNS-oppslag, hvis vi har få adresser å koble til (standard: 1 med mindre -connect)</translation>
</message>
<message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>Bruk tilfeldig identitet for hver proxytilkobling. Dette muliggjør TOR stream isolasjon (standardverdi: %u)</translation>
+ </message>
+ <message>
+ <source>Require high priority for relaying free or low-fee transactions (default: %u)</source>
+ <translation>Krev høy prioritet for videresending av gratistransaksjoner eller transaksjoner med lavt gebyr (standardverdi: %u)</translation>
+ </message>
+ <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Sett maksimum størrelse for transaksjoner med høy prioritet / lavt gebyr, i bytes (standardverdi: %d)</translation>
</message>
@@ -3001,6 +3117,10 @@
<translation>Angi antall tråder for mynt generering hvis aktivert (-1 = alle kjerner, standardverdi: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Transaksjonsbeløpet er for lite til å sendes etter at gebyret er fratrukket</translation>
+ </message>
+ <message>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation>Dette produktet inneholder programvare utviklet av OpenSSL Project for bruk i OpenSSL Toolkit &lt;https://www.openssl.org/&gt; og kryptografisk programvare skrevet av Eric Young og UPnP-programvare skrevet av Thomas Bernard.</translation>
</message>
@@ -3053,6 +3173,14 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Godta offentlige REST forespørsler (standardverdi: %u)</translation>
</message>
<message>
+ <source>Activating best chain...</source>
+ <translation>Aktiverer beste kjede...</translation>
+ </message>
+ <message>
+ <source>Allow self signed root certificates (default: 0)</source>
+ <translation>Tillat selvsignerte rotsertifikater (standardverdi: 0)</translation>
+ </message>
+ <message>
<source>Can't run with a wallet in prune mode.</source>
<translation>Kan ikke kjøre med en lommebok i beskjæringsmodus.</translation>
</message>
@@ -3153,6 +3281,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Slumpvis bland 1 av hver &lt;n&gt; nettverksmeldinger</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Gjenopprett blokkjedeindeks fra gjeldende blk000??.dat filer ved oppstart</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Send spor-/feilsøkingsinformasjon til konsollen istedenfor filen debug.log</translation>
</message>
@@ -3189,6 +3321,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Start minimert</translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>Transaksjonsbeløpet er for lite til å betale gebyr</translation>
+ </message>
+ <message>
<source>This is experimental software.</source>
<translation>Dette er eksperimentell programvare.</translation>
</message>
@@ -3377,6 +3513,10 @@ for eksempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Hold maks &lt;n&gt; koblinger åpne til andre noder (standardverdi: %u)</translation>
</message>
<message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>Få lommeboken til å kringkaste transaksjoner</translation>
+ </message>
+ <message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation>Maks mottaksbuffer per forbindelse, &lt;n&gt;*1000 bytes (standardverdi: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_nl.ts b/src/qt/locale/bitcoin_nl.ts
index 3e1d568d20..385972845a 100644
--- a/src/qt/locale/bitcoin_nl.ts
+++ b/src/qt/locale/bitcoin_nl.ts
@@ -168,6 +168,10 @@
<translation>Weet u zeker dat u uw portemonnee wilt versleutelen?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Bitcoin Core zal nu afsluiten om het versleutelingsproces te voltooien. Hou er rekening mee dat versleuteling van je portemonnee je niet volledig beschermt tegen diefstal van jouw bitcoins door malware op je computer.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>BELANGRIJK: Elke eerder gemaakte backup van uw portemonneebestand dient u te vervangen door het nieuw gegenereerde, versleutelde portemonneebestand. Om veiligheidsredenen zullen eerdere backups van het niet-versleutelde portemonneebestand onbruikbaar worden zodra u uw nieuwe, versleutelde, portemonnee begint te gebruiken.</translation>
</message>
@@ -181,7 +185,11 @@
</message>
<message>
<source>Enter the new passphrase to the wallet.&lt;br/&gt;Please use a passphrase of &lt;b&gt;ten or more random characters&lt;/b&gt;, or &lt;b&gt;eight or more words&lt;/b&gt;.</source>
- <translation>Voer een nieuw wachtwoord in voor uw portomonee.&lt;br/&gt;Gebruik een wachtwoord van &lt;b&gt;tien of meer willekeurige karakters&lt;/b&gt;, of &lt;b&gt;acht of meer woorden&lt;/b&gt;.</translation>
+ <translation>Voer een nieuw wachtwoord in voor uw portemonnee.&lt;br/&gt;Gebruik een wachtwoord van &lt;b&gt;tien of meer willekeurige karakters&lt;/b&gt;, of &lt;b&gt;acht of meer woorden&lt;/b&gt;.</translation>
+ </message>
+ <message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Voer het oude en nieuwe wachtwoord in voor uw portemonnee.</translation>
</message>
<message>
<source>Wallet encryption failed</source>
@@ -419,6 +427,10 @@
<translation>Geen bron voor blokken beschikbaar...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>%n blok aan transactie geschiedenis verwerkt.</numerusform><numerusform>%n blokken aan transactie geschiedenis verwerkt.</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n uur</numerusform><numerusform>%n uur</numerusform></translation>
</message>
@@ -471,6 +483,36 @@
<translation>Aan het bijwerken...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>Datum: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Aantal: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Type: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Label: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adres: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Verzonden transactie</translation>
</message>
@@ -669,6 +711,18 @@
<translation>geen</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>Dit label wordt rood als de transactie groter is dan 1000 bytes.</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>Dit label wordt rood als de prioriteit lager is dan "gemiddeld".</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>Dit label wordt rood wanneer een ontvanger minder dan %1 krijgt.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>Kan per input +/- %1 satoshi(s) variëren.</translation>
</message>
@@ -919,6 +973,10 @@
<translation>IP-adres van de proxy (bijv. IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>Stel hier de taal van de applicatie in. Deze instelling zal van kracht worden na het herstarten van de applicatie.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>Derde partijen URL's (bijvoorbeeld block explorer) dat in de transacties tab verschijnen als contextmenu elementen. %s in de URL is vervangen door transactie hash. Verscheidene URL's zijn gescheiden door een verticale streep |. </translation>
</message>
@@ -943,6 +1001,14 @@
<translation>&amp;Netwerk</translation>
</message>
<message>
+ <source>Automatically start Bitcoin Core after logging in to the system.</source>
+ <translation>Bitcoin Kern automatisch starten bij inloggen.</translation>
+ </message>
+ <message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>&amp;Start Bitcoin Kern tijdens login.</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = auto, &lt;0 = laat dit aantal kernen vrij)</translation>
</message>
@@ -1055,6 +1121,10 @@
<translation>Herstart van de client is vereist om veranderingen door te voeren.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Applicatie zal worden afgesloten. Wilt u doorgaan?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>Om dit aan te passen moet de client opnieuw gestart worden.</translation>
</message>
@@ -1137,10 +1207,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Huidige balans in alleen-bekijkbare adressen.</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>niet gesynchroniseerd</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_pam.ts b/src/qt/locale/bitcoin_pam.ts
index 503528f4a7..54c30dfb6f 100644
--- a/src/qt/locale/bitcoin_pam.ts
+++ b/src/qt/locale/bitcoin_pam.ts
@@ -593,11 +593,7 @@
<source>Your current total balance</source>
<translation>Ing kekang kasalungsungan kabuuang balanse</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>ali ya maka-sync</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
</context>
diff --git a/src/qt/locale/bitcoin_pl.ts b/src/qt/locale/bitcoin_pl.ts
index 7a7285aa01..db49e20cf1 100644
--- a/src/qt/locale/bitcoin_pl.ts
+++ b/src/qt/locale/bitcoin_pl.ts
@@ -3,7 +3,7 @@
<name>AddressBookPage</name>
<message>
<source>Right-click to edit address or label</source>
- <translation>Prawy klik żeby edytować adres lub etykietę</translation>
+ <translation>Kliknij prawy przycisk aby edytować adres lub etykietę</translation>
</message>
<message>
<source>Create a new address</source>
@@ -1097,10 +1097,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Łączna kwota na podglądanych adresach</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nie zsynchronizowany</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_pt_BR.ts b/src/qt/locale/bitcoin_pt_BR.ts
index d4d1d83e54..42a781de99 100644
--- a/src/qt/locale/bitcoin_pt_BR.ts
+++ b/src/qt/locale/bitcoin_pt_BR.ts
@@ -63,7 +63,7 @@
</message>
<message>
<source>Receiving addresses</source>
- <translation>Endereços para receber</translation>
+ <translation>Endereços de recebimento</translation>
</message>
<message>
<source>These are your Bitcoin addresses for sending payments. Always check the amount and the receiving address before sending coins.</source>
@@ -224,7 +224,7 @@
<name>BitcoinGUI</name>
<message>
<source>Sign &amp;message...</source>
- <translation>&amp;Assinar Mensagem...</translation>
+ <translation>&amp;Assinar mensagem...</translation>
</message>
<message>
<source>Synchronizing with network...</source>
@@ -284,11 +284,11 @@
</message>
<message>
<source>&amp;Sending addresses...</source>
- <translation>Enviando endereço&amp;s...</translation>
+ <translation>Endereço&amp;s de envio...</translation>
</message>
<message>
<source>&amp;Receiving addresses...</source>
- <translation>&amp;Receber endereços...</translation>
+ <translation>Endereços de &amp;Recebimento...</translation>
</message>
<message>
<source>Open &amp;URI...</source>
@@ -380,7 +380,7 @@
</message>
<message>
<source>&amp;Help</source>
- <translation>&amp;Ajuda</translation>
+ <translation>A&amp;juda</translation>
</message>
<message>
<source>Tabs toolbar</source>
@@ -977,6 +977,10 @@
<translation>Minimizar em vez de fechar o programa quando a janela for fechada. Quando essa opção estiver ativa, o programa só será fechado somente pela opção Sair no menu Arquivo.</translation>
</message>
<message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>A linguagem da interface do usuário pode ser alterada aqui. A mudança ocorrerá após o reinício do Bitcoin Core.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>URLs de terceiros (exemplo: explorador de blocos) que aparecem na aba de transações como itens do menu de contexto. %s na URL é substituido pela hash da transação. Múltiplas URLs são separadas pela barra vertical |.</translation>
</message>
@@ -1207,10 +1211,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Balanço total em endereços monitorados</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>fora de sincronia</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1388,7 +1388,7 @@
</message>
<message>
<source>Debug window</source>
- <translation>Janela de debug</translation>
+ <translation>Janela de depuração</translation>
</message>
<message>
<source>General</source>
@@ -2121,7 +2121,7 @@
</message>
<message>
<source>&amp;Sign Message</source>
- <translation>&amp;Assinar Mensagem</translation>
+ <translation>&amp;Assinar mensagem</translation>
</message>
<message>
<source>The Bitcoin address to sign the message with</source>
@@ -2161,7 +2161,7 @@
</message>
<message>
<source>Sign &amp;Message</source>
- <translation>Assinar &amp;Mensagem</translation>
+ <translation>Assinar &amp;mensagem</translation>
</message>
<message>
<source>Reset all sign message fields</source>
@@ -2173,7 +2173,7 @@
</message>
<message>
<source>&amp;Verify Message</source>
- <translation>&amp;Verificar Mensagem</translation>
+ <translation>&amp;Verificar mensagem</translation>
</message>
<message>
<source>The Bitcoin address the message was signed with</source>
@@ -2185,7 +2185,7 @@
</message>
<message>
<source>Verify &amp;Message</source>
- <translation>Verificar &amp;Mensagem</translation>
+ <translation>Verificar &amp;mensagem</translation>
</message>
<message>
<source>Reset all verify message fields</source>
@@ -2193,7 +2193,7 @@
</message>
<message>
<source>Click "Sign Message" to generate signature</source>
- <translation>Clique em "Assinar Mensagem" para gerar a assinatura</translation>
+ <translation>Clique em "Assinar mensagem" para gerar a assinatura</translation>
</message>
<message>
<source>The entered address is invalid.</source>
@@ -2846,7 +2846,7 @@
</message>
<message>
<source>Debugging/Testing options:</source>
- <translation>Opções de Debug/Teste:</translation>
+ <translation>Opções de depuração/teste:</translation>
</message>
<message>
<source>Do not load the wallet and disable wallet RPC calls</source>
@@ -2886,7 +2886,7 @@
</message>
<message>
<source>If &lt;category&gt; is not supplied, output all debugging information.</source>
- <translation>Se &lt;category&gt; não for informada, logar toda informação de debug.</translation>
+ <translation>Se &lt;category&gt; não for informada, registrar toda informação de depuração.</translation>
</message>
<message>
<source>Importing...</source>
@@ -2945,6 +2945,10 @@
<translation>Opções da carteira:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>Atenção: Essa versão está obsoleta, atualização necessária!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>Você precisa reconstruir o banco de dados utilizando -reindex</translation>
</message>
@@ -3110,7 +3114,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br
</message>
<message>
<source>Show all debugging options (usage: --help -help-debug)</source>
- <translation>Exibir todas opções de debug (uso: --help -help-debug)</translation>
+ <translation>Exibir todas opções de depuração (uso: --help -help-debug)</translation>
</message>
<message>
<source>Show splash screen on startup (default: 1)</source>
@@ -3238,7 +3242,7 @@ por exemplo: alertnotify=echo %%s | mail -s "Alerta do Bitcoin" admin@foo.com.br
</message>
<message>
<source>Include IP addresses in debug output (default: %u)</source>
- <translation>Incluir endereço IP na saída de debug (padrão: %u)</translation>
+ <translation>Incluir endereço IP na saída de depuração (padrão: %u)</translation>
</message>
<message>
<source>Invalid -proxy address: '%s'</source>
diff --git a/src/qt/locale/bitcoin_pt_PT.ts b/src/qt/locale/bitcoin_pt_PT.ts
index 30ac9fdf31..5012ff8d83 100644
--- a/src/qt/locale/bitcoin_pt_PT.ts
+++ b/src/qt/locale/bitcoin_pt_PT.ts
@@ -1138,10 +1138,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Saldo disponivél em enderços modo-verificação</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>fora de sincronia</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_ro_RO.ts b/src/qt/locale/bitcoin_ro_RO.ts
index 8b029eeca1..11a29e86c9 100644
--- a/src/qt/locale/bitcoin_ro_RO.ts
+++ b/src/qt/locale/bitcoin_ro_RO.ts
@@ -168,6 +168,10 @@
<translation>Sigur doriţi să criptaţi portofelul dvs.?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Bitcoin se va închide acum pentru a termina procesul de criptare. Ţineţi minte că criptarea portofelului nu vă poate proteja în totalitate de furtul monedelor de către programe dăunătoare care vă infectează calculatorul.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>IMPORTANT: Orice copie de siguranţă făcută anterior portofelului dumneavoastră ar trebui înlocuită cu cea generată cel mai recent, fişier criptat al portofelului. Pentru siguranţă, copiile de siguranţă vechi ale portofelului ne-criptat vor deveni inutile imediat ce veţi începe folosirea noului fişier criptat al portofelului.</translation>
</message>
@@ -184,6 +188,10 @@
<translation>Introduceţi noua parolă a portofelului electronic.&lt;br/&gt;Vă rugăm să folosiţi o parolă de&lt;b&gt;minimum 10 caractere aleatoare&lt;/b&gt;, sau &lt;b&gt;minimum 8 cuvinte&lt;/b&gt;.</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Introduceţi vechea şi noua parolă pentru portofel.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Criptarea portofelului nu a reuşit</translation>
</message>
@@ -391,6 +399,10 @@
<translation>&amp;Despre Nucleul Bitcoin</translation>
</message>
<message>
+ <source>Modify configuration options for Bitcoin Core</source>
+ <translation>Modifică opţiunile de configurare pentru Bitcoin</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>Arată lista de adrese trimise şi etichetele folosite.</translation>
</message>
@@ -419,6 +431,10 @@
<translation>Nici o sursă de bloc disponibilă...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>S-a procesat %n bloc din istoricul tranzacţiilor.</numerusform><numerusform>S-au procesat %n blocuri din istoricul tranzacţiilor.</numerusform><numerusform>S-au procesat %n de blocuri din istoricul tranzacţiilor.</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n oră</numerusform><numerusform>%n ore</numerusform><numerusform>%n ore</numerusform></translation>
</message>
@@ -471,6 +487,36 @@
<translation>Se actualizează...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>Data: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Sumă: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tip: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etichetă: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adresă: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Tranzacţie expediată</translation>
</message>
@@ -665,6 +711,18 @@
<translation>nimic</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>Această etichetă devine roşie în cazul în care dimensiunea tranzacţiei este mai mare de 1000 de octeţi.</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>Această etichetă devine roşie dacă prioritatea e mai mică decît "medie".</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>Această etichetă devine roşie, dacă orice beneficiar primeşte o sumă mai mică decât %1.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>Poate varia +/- %1 satoshi pentru fiecare intrare.</translation>
</message>
@@ -907,6 +965,14 @@
<translation>Adresa IP a serverului proxy (de exemplu: IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Minimizează fereastra în locul părăsirii programului în momentul închiderii ferestrei. Cînd acestă opţiune e activă, aplicaţia se va opri doar în momentul selectării comenzii 'Închide aplicaţia' din menu.</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>Limba interfeţei utilizatorului poate fi setată aici. Această setare va avea efect după repornirea Nucleului Bitcoin.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>URL-uri terţe părţi (de exemplu, un explorator de bloc), care apar în tab-ul tranzacţiilor ca elemente de meniu contextual. %s în URL este înlocuit cu hash de tranzacţie. URL-urile multiple sînt separate prin bară verticală |.</translation>
</message>
@@ -931,6 +997,10 @@
<translation>Reţea</translation>
</message>
<message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>Porneşte Nucleul Bitcoin la pornirea sistemului</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = automat, &lt;0 = lasă atîtea nuclee libere)</translation>
</message>
@@ -1043,6 +1113,10 @@
<translation>Este necesară repornirea clientului pentru a activa schimbările.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>Clientul va fi închis. Doriţi să continuaţi?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>Această schimbare necesită o repornire a clientului.</translation>
</message>
@@ -1125,10 +1199,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Soldul dvs. total în adresele doar-supraveghere</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nesincronizat</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1169,6 +1239,10 @@
<translation>URL-ul cererii de plată preluat nu este valid: %1</translation>
</message>
<message>
+ <source>URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters.</source>
+ <translation>URI nu poate fi analizat! Acest lucru poate fi cauzat de o adresă Bitcoin nevalidă sau parametri URI deformaţi.</translation>
+ </message>
+ <message>
<source>Payment request file handling</source>
<translation>Manipulare fişier cerere de plată</translation>
</message>
@@ -1177,10 +1251,18 @@
<translation>Fişierul cerere de plată nu poate fi citit! Cauza poate fi un fişier cerere de plată nevalid.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Cererea de plată a expirat.</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>Cererile de plată neverificate prin script-uri personalizate de plată nu sînt suportate.</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>Cerere de plată nevalidă.</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>Rambursare de la %1</translation>
</message>
@@ -1441,6 +1523,10 @@
<translation>Curăţă consola</translation>
</message>
<message>
+ <source>Welcome to the Bitcoin Core RPC console.</source>
+ <translation>Bun venit la consola Nucleului Bitcoin RPC.</translation>
+ </message>
+ <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Folosiţi săgetile sus şi jos pentru a naviga în istoric şi &lt;b&gt;Ctrl-L&lt;/b&gt; pentru a curăţa.</translation>
</message>
@@ -1729,6 +1815,10 @@
<translation>per kilooctet</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation>Ascunde</translation>
+ </message>
+ <message>
<source>total at least</source>
<translation>total cel puţin</translation>
</message>
@@ -1857,10 +1947,18 @@
<translation>Tranzacţia a fost respinsă! Acest lucru se poate întîmpla dacă o parte din monedele tale din portofel au fost deja cheltuite, la fel ca şi cum aţi fi folosit o copie a wallet.dat şi monedele au fost cheltuite în copie, dar nu au fost marcate ca şi cheltuite şi aici.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Cererea de plată a expirat.</translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>Plăteşte doar taxa minimă de %1</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Adresa destinatarului nu este validă, vă rugăm să o verificaţi.</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Atenţie: Adresa bitcoin nevalidă!</translation>
</message>
diff --git a/src/qt/locale/bitcoin_ru.ts b/src/qt/locale/bitcoin_ru.ts
index 30d44b090f..c208b3e25e 100644
--- a/src/qt/locale/bitcoin_ru.ts
+++ b/src/qt/locale/bitcoin_ru.ts
@@ -1105,10 +1105,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Текущий общий баланс на адресах наблюдения</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>не синхронизировано</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_sk.ts b/src/qt/locale/bitcoin_sk.ts
index 294eca4127..8e7d38be00 100644
--- a/src/qt/locale/bitcoin_sk.ts
+++ b/src/qt/locale/bitcoin_sk.ts
@@ -1081,11 +1081,7 @@
<source>Recent transactions</source>
<translation>Nedávne transakcie</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>nesynchronizované</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_sl_SI.ts b/src/qt/locale/bitcoin_sl_SI.ts
index 7a283bcca1..abbdba3760 100644
--- a/src/qt/locale/bitcoin_sl_SI.ts
+++ b/src/qt/locale/bitcoin_sl_SI.ts
@@ -929,11 +929,7 @@
<source>Your current total balance</source>
<translation>Vaše trenutno skupno stanje</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>iz sinhronizacije</translation>
- </message>
-</context>
+ </context>
<context>
<name>PaymentServer</name>
<message>
diff --git a/src/qt/locale/bitcoin_sv.ts b/src/qt/locale/bitcoin_sv.ts
index 8a46ae8470..289074f134 100644
--- a/src/qt/locale/bitcoin_sv.ts
+++ b/src/qt/locale/bitcoin_sv.ts
@@ -1212,10 +1212,6 @@ Var vänlig och försök igen.</translation>
<source>Current total balance in watch-only addresses</source>
<translation>Nuvarande total balans i granska-bara adresser</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>osynkroniserad</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -3270,6 +3266,10 @@ till exempel: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Slupmässigt brus 1 gång varje &lt;n&gt; nätverksmeddelande</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Återskapa blockkedjans index från nuvarande blk000??.dat filer under uppstarten</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Skicka trace-/debuginformation till terminalen istället för till debug.log</translation>
</message>
diff --git a/src/qt/locale/bitcoin_tr.ts b/src/qt/locale/bitcoin_tr.ts
index 66902a515b..bf6f3f2791 100644
--- a/src/qt/locale/bitcoin_tr.ts
+++ b/src/qt/locale/bitcoin_tr.ts
@@ -168,6 +168,10 @@
<translation>Cüzdanınızı şifrelemek istediğinizden emin misiniz?</translation>
</message>
<message>
+ <source>Bitcoin Core will close now to finish the encryption process. Remember that encrypting your wallet cannot fully protect your bitcoins from being stolen by malware infecting your computer.</source>
+ <translation>Şifreleme işlemini tamamlamak için Bitcoin Çekirdeği şimdi kapanacaktır. Cüzdanınızı şifrelemenin, Bitcoinlerinizin bilgisayara bulaşan kötücül bir yazılım tarafından çalınmaya karşı tamamen koruyamayacağını unutmayınız.</translation>
+ </message>
+ <message>
<source>IMPORTANT: Any previous backups you have made of your wallet file should be replaced with the newly generated, encrypted wallet file. For security reasons, previous backups of the unencrypted wallet file will become useless as soon as you start using the new, encrypted wallet.</source>
<translation>ÖNEMLİ: Önceden yapmış olduğunuz cüzdan dosyası yedeklemelerinin yeni oluşturulan şifrelenmiş cüzdan dosyası ile değiştirilmeleri gerekir. Güvenlik nedenleriyle yeni, şifrelenmiş cüzdanı kullanmaya başladığınızda eski şifrelenmemiş cüzdan dosyaları işe yaramaz hale gelecektir.</translation>
</message>
@@ -184,6 +188,10 @@
<translation>Cüzdan için yeni parolayı giriniz.&lt;br/&gt;Lütfen &lt;b&gt;on ya da daha fazla rastgele karakter&lt;/b&gt; veya &lt;b&gt;sekiz ya da daha fazla kelime&lt;/b&gt; içeren bir parola kullanınız.</translation>
</message>
<message>
+ <source>Enter the old passphrase and new passphrase to the wallet.</source>
+ <translation>Cüzdan için eski parolayı ve yeni parolayı giriniz.</translation>
+ </message>
+ <message>
<source>Wallet encryption failed</source>
<translation>Cüzdan şifrelemesi başarısız oldu</translation>
</message>
@@ -391,6 +399,10 @@
<translation>Bitcoin Çekirdeği &amp;hakkında</translation>
</message>
<message>
+ <source>Modify configuration options for Bitcoin Core</source>
+ <translation>Bitcoin Çekirdeği yapılandırma seçeneklerini değiştir</translation>
+ </message>
+ <message>
<source>Show the list of used sending addresses and labels</source>
<translation>Kullanılmış gönderme adresleri ve etiketlerin listesini göster</translation>
</message>
@@ -419,6 +431,10 @@
<translation>Hiçbir blok kaynağı mevcut değil...</translation>
</message>
<message numerus="yes">
+ <source>Processed %n block(s) of transaction history.</source>
+ <translation><numerusform>Muamele tarihçesinden %n blok işlendi.</numerusform><numerusform>Muamele tarihçesinden %n blok işlendi</numerusform></translation>
+ </message>
+ <message numerus="yes">
<source>%n hour(s)</source>
<translation><numerusform>%n saat</numerusform><numerusform>%n saat</numerusform></translation>
</message>
@@ -471,6 +487,36 @@
<translation>Aralık kapatılıyor...</translation>
</message>
<message>
+ <source>Date: %1
+</source>
+ <translation>Tarih: %1
+</translation>
+ </message>
+ <message>
+ <source>Amount: %1
+</source>
+ <translation>Meblağ: %1
+</translation>
+ </message>
+ <message>
+ <source>Type: %1
+</source>
+ <translation>Tür: %1
+</translation>
+ </message>
+ <message>
+ <source>Label: %1
+</source>
+ <translation>Etiket: %1
+</translation>
+ </message>
+ <message>
+ <source>Address: %1
+</source>
+ <translation>Adres: %1
+</translation>
+ </message>
+ <message>
<source>Sent transaction</source>
<translation>Muamele yollandı</translation>
</message>
@@ -669,6 +715,18 @@
<translation>boş</translation>
</message>
<message>
+ <source>This label turns red if the transaction size is greater than 1000 bytes.</source>
+ <translation>Eğer muamele boyutu 1000 bayttan yüksek ise bu etiket kırmızı hale gelir.</translation>
+ </message>
+ <message>
+ <source>This label turns red if the priority is smaller than "medium".</source>
+ <translation>Eğer öncelik "ortadan" düşükse bu etiket kırmızı olur.</translation>
+ </message>
+ <message>
+ <source>This label turns red if any recipient receives an amount smaller than %1.</source>
+ <translation>Eğer herhangi bir alıcı %1'den düşük bir meblağ alırsa bu etiket kırmızı olur.</translation>
+ </message>
+ <message>
<source>Can vary +/- %1 satoshi(s) per input.</source>
<translation>Giriş başına +/- %1 satoshi olarak değişebilir.</translation>
</message>
@@ -919,6 +977,14 @@
<translation>Vekil sunucusunun IP adresi (mesela IPv4: 127.0.0.1 / IPv6: ::1)</translation>
</message>
<message>
+ <source>Minimize instead of exit the application when the window is closed. When this option is enabled, the application will be closed only after selecting Exit in the menu.</source>
+ <translation>Pencere kapatıldığında uygulamadan çıkmak yerine uygulamayı küçültür. Bu seçenek etkinleştirildiğinde, uygulama sadece menüden çıkış seçildiğinde kapanacaktır.</translation>
+ </message>
+ <message>
+ <source>The user interface language can be set here. This setting will take effect after restarting Bitcoin Core.</source>
+ <translation>Kullanıcı arayüzünün dili burada belirtilebilir. Bu ayar Bitcoin Çekirdeği tekrar başlatıldığında etkinleşecektir.</translation>
+ </message>
+ <message>
<source>Third party URLs (e.g. a block explorer) that appear in the transactions tab as context menu items. %s in the URL is replaced by transaction hash. Multiple URLs are separated by vertical bar |.</source>
<translation>Muameleler sekmesinde bağlam menüsü unsurları olarak görünen üçüncü taraf bağlantıları (mesela bir blok tarayıcısı). URL'deki %s, muamele hash değeri ile değiştirilecektir. Birden çok bağlantılar düşey çubuklar | ile ayrılacaktır.</translation>
</message>
@@ -943,6 +1009,14 @@
<translation>&amp;Şebeke</translation>
</message>
<message>
+ <source>Automatically start Bitcoin Core after logging in to the system.</source>
+ <translation>Sistemde oturum açıldığında Bitcoin Çekirdeğini otomatik olarak başlat.</translation>
+ </message>
+ <message>
+ <source>&amp;Start Bitcoin Core on system login</source>
+ <translation>Bitcoin Çekirdeğini sistem oturumuyla &amp;başlat</translation>
+ </message>
+ <message>
<source>(0 = auto, &lt;0 = leave that many cores free)</source>
<translation>(0 = otomatik, &lt;0 = bu kadar çekirdeği kullanma)</translation>
</message>
@@ -1055,6 +1129,10 @@
<translation>Değişikliklerin uygulanması için istemcinin yeniden başlatılması lazımdır.</translation>
</message>
<message>
+ <source>Client will be shut down. Do you want to proceed?</source>
+ <translation>İstemci kapanacaktır. Devam etmek istiyor musunuz?</translation>
+ </message>
+ <message>
<source>This change would require a client restart.</source>
<translation>Bu değişiklik istemcinin tekrar başlatılmasını gerektirir.</translation>
</message>
@@ -1137,10 +1215,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Sadece izlenen adreslerdeki güncel toplam bakiye</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>eşleşme dışı</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -1193,14 +1267,26 @@
<translation>Ödeme talebi okunamaz ya da işlenemez! Bunun sebebi geçersiz bir ödeme talebi dosyası olabilir.</translation>
</message>
<message>
+ <source>Payment request expired.</source>
+ <translation>Ödeme talebinin ömrü doldu.</translation>
+ </message>
+ <message>
<source>Unverified payment requests to custom payment scripts are unsupported.</source>
<translation>Özel ödeme betiklerine teyit edilmemiş ödeme talepleri desteklenmez.</translation>
</message>
<message>
+ <source>Invalid payment request.</source>
+ <translation>Geçersiz ödeme talebi.</translation>
+ </message>
+ <message>
<source>Refund from %1</source>
<translation>%1 öğesinden iade</translation>
</message>
<message>
+ <source>Payment request %1 is too large (%2 bytes, allowed %3 bytes).</source>
+ <translation>%1 ödeme talebi çok büyük (%2 bayt, müsaade edilen %3 bayt).</translation>
+ </message>
+ <message>
<source>Payment request DoS protection</source>
<translation>Ödeme talebi DoS koruması</translation>
</message>
@@ -1232,6 +1318,10 @@
<translation>Kullanıcı Yazılımı</translation>
</message>
<message>
+ <source>Node/Service</source>
+ <translation>Düğüm/Servis</translation>
+ </message>
+ <message>
<source>Ping Time</source>
<translation>Ping Zamanı</translation>
</message>
@@ -1353,6 +1443,10 @@
<translation>Güncel blok sayısı</translation>
</message>
<message>
+ <source>Open the Bitcoin Core debug log file from the current data directory. This can take a few seconds for large log files.</source>
+ <translation>Güncel veri klasöründen Bitcoin Çekirdeği hata ayıklama kütük dosyasını açar. Büyük kütük dosyaları için bu birkaç saniye alabilir.</translation>
+ </message>
+ <message>
<source>Received</source>
<translation>Alınan</translation>
</message>
@@ -1421,6 +1515,10 @@
<translation>Ping Zamanı</translation>
</message>
<message>
+ <source>Time Offset</source>
+ <translation>Saat Farkı</translation>
+ </message>
+ <message>
<source>Last block time</source>
<translation>Son blok zamanı</translation>
</message>
@@ -1465,6 +1563,10 @@
<translation>Konsolu temizle</translation>
</message>
<message>
+ <source>Welcome to the Bitcoin Core RPC console.</source>
+ <translation>Bitcoin Çekirdeği RPC konsoluna hoş geldiniz.</translation>
+ </message>
+ <message>
<source>Use up and down arrows to navigate history, and &lt;b&gt;Ctrl-L&lt;/b&gt; to clear screen.</source>
<translation>Tarihçede gezinmek için imleç tuşlarını kullanınız, &lt;b&gt;Ctrl-L&lt;/b&gt; ile de ekranı temizleyebilirsiniz.</translation>
</message>
@@ -1761,6 +1863,10 @@
<translation>Eğer özel ücret 1000 satoşi olarak ayarlandıysa ve muamele sadece 250 baytsa, "kilobayt başı" ücret olarak sadece 250 satoşi öder ve "toplam asgari" 1000 satoşi öder. Bir kilobayttan yüksek muameleler için ikisi de kilobayt başı ödeme yapar.</translation>
</message>
<message>
+ <source>Hide</source>
+ <translation>Sakla</translation>
+ </message>
+ <message>
<source>total at least</source>
<translation>toplam asgari</translation>
</message>
@@ -1901,10 +2007,26 @@
<translation>Muamele reddedildi! Cüzdanınızdaki madenî paraların bazıları zaten harcanmış olduğunda bu meydana gelebilir. Örneğin wallet.dat dosyasının bir kopyasını kullandıysanız ve kopyada para harcandığında ancak burada harcandığı işaretlenmediğinde.</translation>
</message>
<message>
+ <source>A fee higher than %1 is considered an absurdly high fee.</source>
+ <translation>%1 tutarından yüksek ücret saçma derecede yüksek bir ücret olarak kabul edilir.</translation>
+ </message>
+ <message>
+ <source>Payment request expired.</source>
+ <translation>Ödeme talebinin ömrü doldu.</translation>
+ </message>
+ <message>
<source>Pay only the minimum fee of %1</source>
<translation>Sadece asgari ücret olan %1 tutarını öde</translation>
</message>
<message>
+ <source>The recipient address is not valid. Please recheck.</source>
+ <translation>Alıcı adresi geçerli değildir. Lütfen denetleyiniz.</translation>
+ </message>
+ <message>
+ <source>Duplicate address found: addresses should only be used once each.</source>
+ <translation>Çift adres bulundu: adresler herbiri için sadece bir kez kullanılmalıdır.</translation>
+ </message>
+ <message>
<source>Warning: Invalid Bitcoin address</source>
<translation>Uyarı: geçersiz Bitcoin adresi</translation>
</message>
@@ -1976,10 +2098,26 @@
<translation>Bu unsuru kaldır</translation>
</message>
<message>
+ <source>The fee will be deducted from the amount being sent. The recipient will receive less bitcoins than you enter in the amount field. If multiple recipients are selected, the fee is split equally.</source>
+ <translation>Ücret yollanan meblağdan alınacaktır. Alıcı meblağ alanında girdiğinizden daha az bitcoin alacaktır. Eğer birden çok alıcı seçiliyse ücret eşit olarak bölünecektir.</translation>
+ </message>
+ <message>
+ <source>S&amp;ubtract fee from amount</source>
+ <translation>Ücreti meblağdan düş</translation>
+ </message>
+ <message>
<source>Message:</source>
<translation>Mesaj:</translation>
</message>
<message>
+ <source>This is an unauthenticated payment request.</source>
+ <translation>Bu, kimliği doğrulanmamış bir ödeme talebidir.</translation>
+ </message>
+ <message>
+ <source>This is an authenticated payment request.</source>
+ <translation>Bu, kimliği doğrulanmış bir ödeme talebidir.</translation>
+ </message>
+ <message>
<source>Enter a label for this address to add it to the list of used addresses</source>
<translation>Kullanılmış adres listesine eklemek için bu adrese bir etiket girin</translation>
</message>
@@ -2018,6 +2156,10 @@
<translation>Mesaj &amp;imzala</translation>
</message>
<message>
+ <source>You can sign messages/agreements with your addresses to prove you can receive bitcoins sent to them. Be careful not to sign anything vague or random, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to.</source>
+ <translation>Adreslerinize yollanan bitcoinleri alabileceğiniz ispatlamak için adreslerinizle mesaj/anlaşma imzalayabilirsiniz. Oltalama saldırılarının kimliğinizi imzanızla elde etmeyi deneyebilecekleri için belirsiz ya da rastgele hiçbir şey imzalamamaya dikkat ediniz. Sadece ayrıntılı açıklaması olan ve tümüne katıldığınız ifadeleri imzalayınız.</translation>
+ </message>
+ <message>
<source>The Bitcoin address to sign the message with</source>
<translation>Mesajın imzalanmasında kullanılacak Bitcoin adresi</translation>
</message>
@@ -2070,6 +2212,10 @@
<translation>Mesaj &amp;kontrol et</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>Alıcının adresini, mesajı (satır sonları, boşluklar, sekmeler vs. karakterleri tam olarak kopyaladığınızdan emin olunuz) ve imzayı aşağıda giriniz. Bir ortadaki adam saldırısı tarafından kandırılmaya mâni olmak için imzadan, imzalı mesajın içeriğini aşan bir anlam çıkarmamaya dikkat ediniz. Bunun sadece imzalayan tarafın adres ile alım yapabildiğini ispatladığını ve herhangi bir muamelenin gönderi tarafını kanıtlayamayacağını unutmayınız!</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>Mesajın imzalanmasında kullanılan Bitcoin adresi</translation>
</message>
@@ -2421,6 +2567,10 @@
<translation>Bu muamelede sadece izlenen bir adresin bulunup bulunmadığı.</translation>
</message>
<message>
+ <source>User-defined intent/purpose of the transaction.</source>
+ <translation>Muamelenin kullanıcı tanımlı niyeti/amacı.</translation>
+ </message>
+ <message>
<source>Amount removed from or added to balance.</source>
<translation>Bakiyeden alınan ya da bakiyeye eklenen meblağ.</translation>
</message>
@@ -2663,6 +2813,10 @@
<translation>Belirtilen adrese bağlan ve daima ondan dinle. IPv6 için [makine]:port yazımını kullanınız</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>Devamlı olarak ücretsiz muameleleri dakikada &lt;n&gt;*1000 bayt olarak sınırla (varsayılan: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>Tüm cüzdan muamelelerini sil ve başlangıçta -rescan ile sadece blok zincirinin parçası olanları geri getir</translation>
</message>
@@ -2683,6 +2837,14 @@
<translation>Bu kipte -genproclimit kaç sayıda bloğun anında oluşturulduğunu kontrol eder.</translation>
</message>
<message>
+ <source>Maximum total fees to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)</source>
+ <translation>Tek cüzdan muamelesinde kullanılacak azami toplam ücret; bunu çok düşük olarak ayarlamak büyük muameleleri iptal edebilir (varsayılan: %s)</translation>
+ </message>
+ <message>
+ <source>Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. Warning: Reverting this setting requires re-downloading the entire blockchain. (default: 0 = disable pruning blocks, &gt;%u = target size in MiB to use for block files)</source>
+ <translation>Depolama gerekliliğini eski blokları silerek düşür. Bu kip cüzdan desteğini devre dışı bırakır ve -txindex ile uyumsuzdur. İkaz: Bu ayarı geri almak tüm blok zincirini yeniden indirmeyi gerektirir. (varsayılan: 0 = blokları silmeyi devre dışı bırak, &gt;%u = MB olarak blok dosyaları için kullanılacak hedef boyut)</translation>
+ </message>
+ <message>
<source>Set the number of script verification threads (%u to %d, 0 = auto, &lt;0 = leave that many cores free, default: %d)</source>
<translation>Betik kontrolü iş parçacıklarının sayısını belirler (%u ilâ %d, 0 = otomatik, &lt;0 = bu sayıda çekirdeği kullanma, varsayılan: %d)</translation>
</message>
@@ -2811,6 +2973,14 @@
<translation>Sadece &lt;net&gt; şebekesindeki düğümlere bağlan (ipv4, ipv6 veya onion)</translation>
</message>
<message>
+ <source>Prune cannot be configured with a negative value.</source>
+ <translation>Prune negatif bir değerle yapılandırılamaz.</translation>
+ </message>
+ <message>
+ <source>Prune mode is incompatible with -txindex.</source>
+ <translation>Prune kipi -txindex ile uyumsuzdur.</translation>
+ </message>
+ <message>
<source>Set database cache size in megabytes (%d to %d, default: %d)</source>
<translation>Veritabanı önbellek boyutunu megabayt olarak belirt (%d ilâ %d, varsayılan: %d)</translation>
</message>
@@ -2847,6 +3017,10 @@
<translation>Cüzdan seçenekleri:</translation>
</message>
<message>
+ <source>Warning: This version is obsolete; upgrade required!</source>
+ <translation>Uyarı: Bu sürüm çok eskidir; güncellemeniz gerekir!</translation>
+ </message>
+ <message>
<source>You need to rebuild the database using -reindex to change -txindex</source>
<translation>-txindex'i değiştirmek için veritabanını -reindex kullanarak tekrar inşa etmeniz gerekmektedir</translation>
</message>
@@ -2879,6 +3053,10 @@
<translation>Yeni dosyaları umask 077 yerine varsayılan izinlerle oluştur (sadece devre dışı cüzdan işlevselliği ile etkilidir)</translation>
</message>
<message>
+ <source>Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)</source>
+ <translation>Kendi IP adreslerini keşfet (varsayılan: dinlenildiğinde ve -externalip ya da -proxy yoksa 1)</translation>
+ </message>
+ <message>
<source>Error: Listening for incoming connections failed (listen returned error %s)</source>
<translation>Hata: İçeri gelen bağlantıların dinlenmesi başarısız oldu (dinleme %s hatasını verdi)</translation>
</message>
@@ -2911,10 +3089,22 @@
<translation>Aktardığımız ve oluşturduğumuz veri taşıyıcı muamelelerindeki azami veri boyutu (varsayılan: %u)</translation>
</message>
<message>
+ <source>Prune configured below the minimum of %d MB. Please use a higher number.</source>
+ <translation>Prune, asgari değer olan %d MB'den düşük olarak ayarlanmıştır. Lütfen daha yüksek bir sayı kullanınız.</translation>
+ </message>
+ <message>
<source>Query for peer addresses via DNS lookup, if low on addresses (default: 1 unless -connect)</source>
<translation>Adres sayısı azaldıysa DNS sorgulamasıyla eş adresleri ara (varsayılan: 1 -connect kullanılmadıysa)</translation>
</message>
<message>
+ <source>Randomize credentials for every proxy connection. This enables Tor stream isolation (default: %u)</source>
+ <translation>Her vekil bağlantısı için kimlik verilerini rastgele yap. Bu, Tor akış izolasyonunu etkinleştirir (varsayılan: %u)</translation>
+ </message>
+ <message>
+ <source>Require high priority for relaying free or low-fee transactions (default: %u)</source>
+ <translation>Ücretsiz ya da düşük ücretli muamelelerin geçişi için yüksek öncelik iste (varsayılan: %u)</translation>
+ </message>
+ <message>
<source>Set maximum size of high-priority/low-fee transactions in bytes (default: %d)</source>
<translation>Yüksek öncelikli/düşük ücretli muamelelerin azami boyutunu bayt olarak ayarla (varsayılan: %d)</translation>
</message>
@@ -2923,6 +3113,10 @@
<translation>Etkinse bitcoin oluşuturulmasına atanan iş parçacığı sayısını ayarla (-1 = tüm çekirdekler, varsayılan: %d)</translation>
</message>
<message>
+ <source>The transaction amount is too small to send after the fee has been deducted</source>
+ <translation>Bu muamele, ücret düşüldükten sonra göndermek için çok düşük</translation>
+ </message>
+ <message>
<source>This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit &lt;https://www.openssl.org/&gt; and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.</source>
<translation>Bu ürün OpenSSL projesi tarafından OpenSSL araç takımı (http://www.openssl.org/) için geliştirilen yazılımlar, Eric Young (eay@cryptsoft.com) tarafından hazırlanmış şifreleme yazılımları ve Thomas Bernard tarafından programlanmış UPnP yazılımı içerir.</translation>
</message>
@@ -2963,10 +3157,30 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Beyaz listeye alınan eşler DoS yasaklamasına uğramazlar ve muameleleri zaten mempool'da olsalar da daima aktarılır, bu mesela bir geçit için kullanışlıdır</translation>
</message>
<message>
+ <source>You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain</source>
+ <translation>Prune olmayan kipe dönmek için veritabanını -reindex ile tekrar derlemeniz gerekir. Bu, tüm blok zincirini tekrar indirecektir</translation>
+ </message>
+ <message>
+ <source>(default: %u)</source>
+ <translation>(varsayılan: %u)</translation>
+ </message>
+ <message>
<source>Accept public REST requests (default: %u)</source>
<translation>Herkese açık REST taleplerini kabul et (varsayılan: %u)</translation>
</message>
<message>
+ <source>Activating best chain...</source>
+ <translation>En iyi zincir etkinleştiriliyor...</translation>
+ </message>
+ <message>
+ <source>Allow self signed root certificates (default: 0)</source>
+ <translation>Kendinden imzalı kök sertifikalara müsaade et (varsayılan: 0)</translation>
+ </message>
+ <message>
+ <source>Can't run with a wallet in prune mode.</source>
+ <translation>Prune kipindeki bir cüzdan ile çalışamaz.</translation>
+ </message>
+ <message>
<source>Cannot resolve -whitebind address: '%s'</source>
<translation>-whitebind adresi çözümlenemedi: '%s'</translation>
</message>
@@ -2991,6 +3205,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>wallet.dat dosyasının yüklenmesinde hata: Cüzdan Bitcoin Çekirdeğinin daha yeni bir sürümünü gerektirmektedir</translation>
</message>
<message>
+ <source>Error reading from database, shutting down.</source>
+ <translation>Veritabanından okumada hata, kapatılıyor.</translation>
+ </message>
+ <message>
<source>Error: Unsupported argument -tor found, use -onion.</source>
<translation>Hata: Deskteklenmeyen -tor argümanı bulundu, -onion kullanınız.</translation>
</message>
@@ -3047,6 +3265,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>RPC sunucu seçenekleri:</translation>
</message>
<message>
+ <source>RPC support for HTTP persistent connections (default: %d)</source>
+ <translation>Kalıcı HTTP bağlantıları için RPC desteği (varsayılan: %d)</translation>
+ </message>
+ <message>
<source>Randomly drop 1 of every &lt;n&gt; network messages</source>
<translation>Her &lt;n&gt; şebeke mesajından rastgele 1 mesajı görmezden gel</translation>
</message>
@@ -3055,6 +3277,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Her &lt;n&gt; şebeke mesajından rastgele birini bulanıklaştır</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>Başlangıçta blok zinciri indeksini güncel blk000??.dat dosyalarından tekrar inşa et</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>Trace/hata ayıklama verilerini debug.log dosyası yerine konsola gönder</translation>
</message>
@@ -3091,6 +3317,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Küçültülmüş olarak başlat</translation>
</message>
<message>
+ <source>The transaction amount is too small to pay the fee</source>
+ <translation>Muamele meblağı ücreti ödemek için çok düşük</translation>
+ </message>
+ <message>
<source>This is experimental software.</source>
<translation>Bu, deneysel bir yazılımdır.</translation>
</message>
@@ -3111,6 +3341,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Muamele çok büyük</translation>
</message>
<message>
+ <source>UI Options:</source>
+ <translation>Arayüz Seçenkleri:</translation>
+ </message>
+ <message>
<source>Unable to bind to %s on this computer (bind returned error %s)</source>
<translation>Bu bilgisayarda %s unsuruna bağlanılamadı (bağlanma %s hatasını verdi)</translation>
</message>
@@ -3275,6 +3509,10 @@ mesela: alertnotify=echo %%s | mail -s "Bitcoin Alert" admin@foo.com
<translation>Eşler ile en çok &lt;n&gt; adet bağlantı kur (varsayılan: %u)</translation>
</message>
<message>
+ <source>Make the wallet broadcast transactions</source>
+ <translation>Cüzdanın muameleleri yayınlamasını sağla</translation>
+ </message>
+ <message>
<source>Maximum per-connection receive buffer, &lt;n&gt;*1000 bytes (default: %u)</source>
<translation>Her bağlantı için azami alım tamponu, &lt;n&gt;*1000 bayt (varsayılan: %u)</translation>
</message>
diff --git a/src/qt/locale/bitcoin_uk.ts b/src/qt/locale/bitcoin_uk.ts
index b2e67e296e..92e0cc75c4 100644
--- a/src/qt/locale/bitcoin_uk.ts
+++ b/src/qt/locale/bitcoin_uk.ts
@@ -440,7 +440,7 @@
</message>
<message>
<source>%1 behind</source>
- <translation>%1 позаду</translation>
+ <translation>%1 тому</translation>
</message>
<message>
<source>Last received block was generated %1 ago.</source>
@@ -1123,7 +1123,7 @@
</message>
<message>
<source>Recent transactions</source>
- <translation>Недавні транзакції</translation>
+ <translation>Останні транзакції</translation>
</message>
<message>
<source>Unconfirmed transactions to watch-only addresses</source>
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>Поточний сукупний баланс в адресах для спостереження</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>не синхронізовано</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/locale/bitcoin_zh_CN.ts b/src/qt/locale/bitcoin_zh_CN.ts
index 4c9f287e95..3bcce1faab 100644
--- a/src/qt/locale/bitcoin_zh_CN.ts
+++ b/src/qt/locale/bitcoin_zh_CN.ts
@@ -1215,10 +1215,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>观察地址(watch-only address)中的当前总余额 </translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>数据同步中</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
@@ -2018,6 +2014,10 @@
<source>Payment request expired.</source>
<translation>支付请求已过期。</translation>
</message>
+ <message numerus="yes">
+ <source>Estimated to begin confirmation within %n block(s).</source>
+ <translation><numerusform>预计 %n 个数据块后被确认。</numerusform></translation>
+ </message>
<message>
<source>Pay only the minimum fee of %1</source>
<translation>只支付最小费用 %1</translation>
@@ -2208,6 +2208,10 @@
<translation>验证消息(&amp;V)</translation>
</message>
<message>
+ <source>Enter the receiver's address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack. Note that this only proves the signing party receives with the address, it cannot prove sendership of any transaction!</source>
+ <translation>请在下面输入接收者地址、消息(确保换行符、空格符、制表符等完全相同)和签名以验证消息。请仔细核对签名信息,以提防中间人攻击。请注意,这只是证明接收方签名的地址,它不能证明任何交易!</translation>
+ </message>
+ <message>
<source>The Bitcoin address the message was signed with</source>
<translation>消息使用的签名地址</translation>
</message>
@@ -2811,6 +2815,10 @@
<translation>绑定指定的IP地址开始监听。IPv6地址请使用[host]:port 格式</translation>
</message>
<message>
+ <source>Continuously rate-limit free transactions to &lt;n&gt;*1000 bytes per minute (default: %u)</source>
+ <translation>自由交易不断的速率限制为&lt;n&gt;*1000 字节每分钟(默认值: %u)</translation>
+ </message>
+ <message>
<source>Delete all wallet transactions and only recover those parts of the blockchain through -rescan on startup</source>
<translation>删除钱包的所有交易记录,且只有用 -rescan参数启动客户端才能重新取回交易记录 </translation>
</message>
@@ -3267,6 +3275,10 @@ rpcpassword=%s
<translation>随机每1个模拟测试&lt;n&gt;网络信息</translation>
</message>
<message>
+ <source>Rebuild block chain index from current blk000??.dat files on startup</source>
+ <translation>启动时重新为当前的 blk000??.dat 文件建立索引</translation>
+ </message>
+ <message>
<source>Send trace/debug info to console instead of debug.log file</source>
<translation>跟踪/调试信息输出到控制台,不输出到 debug.log 文件</translation>
</message>
diff --git a/src/qt/locale/bitcoin_zh_TW.ts b/src/qt/locale/bitcoin_zh_TW.ts
index 254b33d5a4..3792a76095 100644
--- a/src/qt/locale/bitcoin_zh_TW.ts
+++ b/src/qt/locale/bitcoin_zh_TW.ts
@@ -1137,10 +1137,6 @@
<source>Current total balance in watch-only addresses</source>
<translation>所有只能看位址的目前全部餘額</translation>
</message>
- <message>
- <source>out of sync</source>
- <translation>還沒同步</translation>
- </message>
</context>
<context>
<name>PaymentServer</name>
diff --git a/src/qt/macdockiconhandler.h b/src/qt/macdockiconhandler.h
index 15a6583ca4..8bd867c103 100644
--- a/src/qt/macdockiconhandler.h
+++ b/src/qt/macdockiconhandler.h
@@ -30,7 +30,7 @@ public:
static void cleanup();
void handleDockIconClickEvent();
-signals:
+Q_SIGNALS:
void dockIconClicked();
private:
diff --git a/src/qt/macdockiconhandler.mm b/src/qt/macdockiconhandler.mm
index 58a0365d3d..a41d39d51e 100644
--- a/src/qt/macdockiconhandler.mm
+++ b/src/qt/macdockiconhandler.mm
@@ -130,5 +130,5 @@ void MacDockIconHandler::handleDockIconClickEvent()
this->mainWindow->show();
}
- emit this->dockIconClicked();
+ Q_EMIT this->dockIconClicked();
}
diff --git a/src/qt/networkstyle.cpp b/src/qt/networkstyle.cpp
index e28f903b2e..4541c75886 100644
--- a/src/qt/networkstyle.cpp
+++ b/src/qt/networkstyle.cpp
@@ -5,7 +5,6 @@
#include "networkstyle.h"
#include "guiconstants.h"
-#include "scicon.h"
#include <QApplication>
diff --git a/src/qt/notificator.h b/src/qt/notificator.h
index 182e948c7d..f2a15e9c34 100644
--- a/src/qt/notificator.h
+++ b/src/qt/notificator.h
@@ -40,7 +40,7 @@ public:
Critical /**< An error occurred */
};
-public slots:
+public Q_SLOTS:
/** Show notification message.
@param[in] cls general message class
@param[in] title title shown with message
diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h
index d5c434ba9c..28b8f56ca6 100644
--- a/src/qt/openuridialog.h
+++ b/src/qt/openuridialog.h
@@ -21,10 +21,10 @@ public:
QString getURI();
-protected slots:
+protected Q_SLOTS:
void accept();
-private slots:
+private Q_SLOTS:
void on_selectFileButton_clicked();
private:
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index efb2bf4158..f57c1203f6 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -13,7 +13,7 @@
#include "guiutil.h"
#include "optionsmodel.h"
-#include "main.h" // for MAX_SCRIPTCHECK_THREADS
+#include "main.h" // for DEFAULT_SCRIPTCHECK_THREADS and MAX_SCRIPTCHECK_THREADS
#include "netbase.h"
#include "txdb.h" // for -dbcache defaults
@@ -35,14 +35,14 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui(new Ui::OptionsDialog),
model(0),
mapper(0),
- fProxyIpValid(true)
+ fProxyIpsValid(true)
{
ui->setupUi(this);
/* Main elements init */
ui->databaseCache->setMinimum(nMinDbCache);
ui->databaseCache->setMaximum(nMaxDbCache);
- ui->threadsScriptVerif->setMinimum(-(int)boost::thread::hardware_concurrency());
+ ui->threadsScriptVerif->setMinimum(-GetNumCores());
ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS);
/* Network elements init */
@@ -54,10 +54,18 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
ui->proxyPort->setEnabled(false);
ui->proxyPort->setValidator(new QIntValidator(1, 65535, this));
+ ui->proxyIpTor->setEnabled(false);
+ ui->proxyPortTor->setEnabled(false);
+ ui->proxyPortTor->setValidator(new QIntValidator(1, 65535, this));
+
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyIp, SLOT(setEnabled(bool)));
connect(ui->connectSocks, SIGNAL(toggled(bool)), ui->proxyPort, SLOT(setEnabled(bool)));
+ 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);
/* Window elements init */
#ifdef Q_OS_MAC
@@ -73,7 +81,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
/* Display elements init */
QDir translations(":translations");
ui->lang->addItem(QString("(") + tr("default") + QString(")"), QVariant(""));
- foreach(const QString &langStr, translations.entryList())
+ Q_FOREACH(const QString &langStr, translations.entryList())
{
QLocale locale(langStr);
@@ -110,7 +118,7 @@ OptionsDialog::OptionsDialog(QWidget *parent, bool enableWallet) :
mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit);
mapper->setOrientation(Qt::Vertical);
- /* setup/change UI elements when proxy IP is invalid/valid */
+ /* setup/change UI elements when proxy IPs are invalid/valid */
connect(this, SIGNAL(proxyIpChecks(QValidatedLineEdit *, int)), this, SLOT(doProxyIpChecks(QValidatedLineEdit *, int)));
}
@@ -137,6 +145,8 @@ void OptionsDialog::setModel(OptionsModel *model)
mapper->setModel(model);
setMapper();
mapper->toFirst();
+
+ updateDefaultProxyNets();
}
/* warn when one of the following settings changes by user action (placed here so init via mapper doesn't trigger them) */
@@ -149,6 +159,7 @@ void OptionsDialog::setModel(OptionsModel *model)
/* Network */
connect(ui->allowIncoming, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
connect(ui->connectSocks, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
+ connect(ui->connectSocksTor, SIGNAL(clicked(bool)), this, SLOT(showRestartWarning()));
/* Display */
connect(ui->lang, SIGNAL(valueChanged()), this, SLOT(showRestartWarning()));
connect(ui->thirdPartyTxUrls, SIGNAL(textChanged(const QString &)), this, SLOT(showRestartWarning()));
@@ -173,6 +184,10 @@ void OptionsDialog::setMapper()
mapper->addMapping(ui->proxyIp, OptionsModel::ProxyIP);
mapper->addMapping(ui->proxyPort, OptionsModel::ProxyPort);
+ mapper->addMapping(ui->connectSocksTor, OptionsModel::ProxyUseTor);
+ mapper->addMapping(ui->proxyIpTor, OptionsModel::ProxyIPTor);
+ mapper->addMapping(ui->proxyPortTor, OptionsModel::ProxyPortTor);
+
/* Window */
#ifndef Q_OS_MAC
mapper->addMapping(ui->minimizeToTray, OptionsModel::MinimizeToTray);
@@ -188,7 +203,7 @@ void OptionsDialog::setMapper()
void OptionsDialog::enableOkButton()
{
/* prevent enabling of the OK button when data modified, if there is an invalid proxy address present */
- if(fProxyIpValid)
+ if(fProxyIpsValid)
setOkButtonState(true);
}
@@ -224,6 +239,7 @@ void OptionsDialog::on_okButton_clicked()
{
mapper->submit();
accept();
+ updateDefaultProxyNets();
}
void OptionsDialog::on_cancelButton_clicked()
@@ -257,11 +273,10 @@ void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPo
{
Q_UNUSED(nProxyPort);
- const std::string strAddrProxy = pUiProxyIp->text().toStdString();
CService addrProxy;
/* Check for a valid IPv4 / IPv6 address */
- if (!(fProxyIpValid = LookupNumeric(strAddrProxy.c_str(), addrProxy)))
+ if (!(fProxyIpsValid = LookupNumeric(pUiProxyIp->text().toStdString().c_str(), addrProxy)))
{
disableOkButton();
pUiProxyIp->setValid(false);
@@ -275,13 +290,39 @@ void OptionsDialog::doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPo
}
}
+void OptionsDialog::updateDefaultProxyNets()
+{
+ proxyType proxy;
+ std::string strProxy;
+ QString strDefaultProxyGUI;
+
+ GetProxy(NET_IPV4, proxy);
+ strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
+ strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
+ (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv4->setChecked(true) : ui->proxyReachIPv4->setChecked(false);
+
+ GetProxy(NET_IPV6, proxy);
+ strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
+ strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
+ (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachIPv6->setChecked(true) : ui->proxyReachIPv6->setChecked(false);
+
+ GetProxy(NET_TOR, proxy);
+ strProxy = proxy.proxy.ToStringIP() + ":" + proxy.proxy.ToStringPort();
+ strDefaultProxyGUI = ui->proxyIp->text() + ":" + ui->proxyPort->text();
+ (strProxy == strDefaultProxyGUI.toStdString()) ? ui->proxyReachTor->setChecked(true) : ui->proxyReachTor->setChecked(false);
+}
+
bool OptionsDialog::eventFilter(QObject *object, QEvent *event)
{
if(event->type() == QEvent::FocusOut)
{
if(object == ui->proxyIp)
{
- emit proxyIpChecks(ui->proxyIp, ui->proxyPort->text().toInt());
+ 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);
diff --git a/src/qt/optionsdialog.h b/src/qt/optionsdialog.h
index f4e5157595..348489c599 100644
--- a/src/qt/optionsdialog.h
+++ b/src/qt/optionsdialog.h
@@ -33,7 +33,7 @@ public:
protected:
bool eventFilter(QObject *object, QEvent *event);
-private slots:
+private Q_SLOTS:
/* enable OK button */
void enableOkButton();
/* disable OK button */
@@ -47,15 +47,17 @@ private slots:
void showRestartWarning(bool fPersistent = false);
void clearStatusLabel();
void doProxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
+ /* query the networks, for which the default proxy is used */
+ void updateDefaultProxyNets();
-signals:
+Q_SIGNALS:
void proxyIpChecks(QValidatedLineEdit *pUiProxyIp, int nProxyPort);
private:
Ui::OptionsDialog *ui;
OptionsModel *model;
QDataWidgetMapper *mapper;
- bool fProxyIpValid;
+ bool fProxyIpsValid;
};
#endif // BITCOIN_QT_OPTIONSDIALOG_H
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 41d6acf358..65e490570e 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -13,7 +13,7 @@
#include "amount.h"
#include "init.h"
-#include "main.h"
+#include "main.h" // For DEFAULT_SCRIPTCHECK_THREADS
#include "net.h"
#include "txdb.h" // for -dbcache defaults
@@ -117,6 +117,16 @@ void OptionsModel::Init()
else if(!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty())
addOverriddenOption("-proxy");
+ if (!settings.contains("fUseSeparateProxyTor"))
+ settings.setValue("fUseSeparateProxyTor", false);
+ if (!settings.contains("addrSeparateProxyTor"))
+ settings.setValue("addrSeparateProxyTor", "127.0.0.1:9050");
+ // Only try to set -onion, if user has enabled fUseSeparateProxyTor
+ if (settings.value("fUseSeparateProxyTor").toBool() && !SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))
+ addOverriddenOption("-onion");
+ else if(!settings.value("fUseSeparateProxyTor").toBool() && !GetArg("-onion", "").empty())
+ addOverriddenOption("-onion");
+
// Display
if (!settings.contains("language"))
settings.setValue("language", "");
@@ -178,6 +188,20 @@ QVariant OptionsModel::data(const QModelIndex & index, int role) const
return strlIpPort.at(1);
}
+ // separate Tor proxy
+ case ProxyUseTor:
+ return settings.value("fUseSeparateProxyTor", false);
+ case ProxyIPTor: {
+ // contains IP at index 0 and port at index 1
+ QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
+ return strlIpPort.at(0);
+ }
+ case ProxyPortTor: {
+ // contains IP at index 0 and port at index 1
+ QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
+ return strlIpPort.at(1);
+ }
+
#ifdef ENABLE_WALLET
case SpendZeroConfChange:
return settings.value("bSpendZeroConfChange");
@@ -259,6 +283,39 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
break;
+
+ // separate Tor proxy
+ case ProxyUseTor:
+ if (settings.value("fUseSeparateProxyTor") != value) {
+ settings.setValue("fUseSeparateProxyTor", value.toBool());
+ setRestartRequired(true);
+ }
+ break;
+ case ProxyIPTor: {
+ // contains current IP at index 0 and current port at index 1
+ QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
+ // if that key doesn't exist or has a changed IP
+ if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(0) != value.toString()) {
+ // construct new value from new IP and current port
+ QString strNewValue = value.toString() + ":" + strlIpPort.at(1);
+ settings.setValue("addrSeparateProxyTor", strNewValue);
+ setRestartRequired(true);
+ }
+ }
+ break;
+ case ProxyPortTor: {
+ // contains current IP at index 0 and current port at index 1
+ QStringList strlIpPort = settings.value("addrSeparateProxyTor").toString().split(":", QString::SkipEmptyParts);
+ // if that key doesn't exist or has a changed port
+ if (!settings.contains("addrSeparateProxyTor") || strlIpPort.at(1) != value.toString()) {
+ // construct new value from current IP and new port
+ QString strNewValue = strlIpPort.at(0) + ":" + value.toString();
+ settings.setValue("addrSeparateProxyTor", strNewValue);
+ setRestartRequired(true);
+ }
+ }
+ break;
+
#ifdef ENABLE_WALLET
case SpendZeroConfChange:
if (settings.value("bSpendZeroConfChange") != value) {
@@ -286,7 +343,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
case CoinControlFeatures:
fCoinControlFeatures = value.toBool();
settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
- emit coinControlFeaturesChanged(fCoinControlFeatures);
+ Q_EMIT coinControlFeaturesChanged(fCoinControlFeatures);
break;
case DatabaseCache:
if (settings.value("nDatabaseCache") != value) {
@@ -311,7 +368,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in
}
}
- emit dataChanged(index, index);
+ Q_EMIT dataChanged(index, index);
return successful;
}
@@ -324,7 +381,7 @@ void OptionsModel::setDisplayUnit(const QVariant &value)
QSettings settings;
nDisplayUnit = value.toInt();
settings.setValue("nDisplayUnit", nDisplayUnit);
- emit displayUnitChanged(nDisplayUnit);
+ Q_EMIT displayUnitChanged(nDisplayUnit);
}
}
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index bf892768ed..8448cad8de 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -34,6 +34,9 @@ public:
ProxyUse, // bool
ProxyIP, // QString
ProxyPort, // int
+ ProxyUseTor, // bool
+ ProxyIPTor, // QString
+ ProxyPortTor, // int
DisplayUnit, // BitcoinUnits::Unit
ThirdPartyTxUrls, // QString
Language, // QString
@@ -81,7 +84,7 @@ private:
/// Add option to list of GUI options overridden through command line/config file
void addOverriddenOption(const std::string &option);
-signals:
+Q_SIGNALS:
void displayUnitChanged(int unit);
void coinControlFeaturesChanged(bool);
};
diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp
index 4fa15db9c6..a56c80ac63 100644
--- a/src/qt/overviewpage.cpp
+++ b/src/qt/overviewpage.cpp
@@ -10,7 +10,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactionfilterproxy.h"
#include "transactiontablemodel.h"
#include "walletmodel.h"
@@ -18,14 +18,16 @@
#include <QAbstractItemDelegate>
#include <QPainter>
-#define DECORATION_SIZE 64
-#define NUM_ITEMS 3
+#define DECORATION_SIZE 54
+#define NUM_ITEMS 5
class TxViewDelegate : public QAbstractItemDelegate
{
Q_OBJECT
public:
- TxViewDelegate(): QAbstractItemDelegate(), unit(BitcoinUnits::BTC)
+ TxViewDelegate(const PlatformStyle *platformStyle):
+ QAbstractItemDelegate(), unit(BitcoinUnits::BTC),
+ platformStyle(platformStyle)
{
}
@@ -43,7 +45,7 @@ public:
int halfheight = (mainRect.height() - 2*ypad)/2;
QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace, halfheight);
QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight);
- icon = SingleColorIcon(icon, SingleColor());
+ icon = platformStyle->SingleColorIcon(icon);
icon.paint(painter, decorationRect);
QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime();
@@ -101,11 +103,12 @@ public:
}
int unit;
+ const PlatformStyle *platformStyle;
};
#include "overviewpage.moc"
-OverviewPage::OverviewPage(QWidget *parent) :
+OverviewPage::OverviewPage(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::OverviewPage),
clientModel(0),
@@ -116,11 +119,17 @@ OverviewPage::OverviewPage(QWidget *parent) :
currentWatchOnlyBalance(-1),
currentWatchUnconfBalance(-1),
currentWatchImmatureBalance(-1),
- txdelegate(new TxViewDelegate()),
+ txdelegate(new TxViewDelegate(platformStyle)),
filter(0)
{
ui->setupUi(this);
+ // use a SingleColorIcon for the "out of sync warning" icon
+ QIcon icon = platformStyle->SingleColorIcon(":/icons/warning");
+ icon.addPixmap(icon.pixmap(QSize(64,64), QIcon::Normal), QIcon::Disabled); // also set the disabled icon because we are using a disabled QPushButton to work around missing HiDPI support of QLabel (https://bugreports.qt.io/browse/QTBUG-42503)
+ ui->labelTransactionsStatus->setIcon(icon);
+ ui->labelWalletStatus->setIcon(icon);
+
// Recent transactions
ui->listTransactions->setItemDelegate(txdelegate);
ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE));
@@ -129,10 +138,6 @@ OverviewPage::OverviewPage(QWidget *parent) :
connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex)));
- // init "out of sync" warning labels
- ui->labelWalletStatus->setText("(" + tr("out of sync") + ")");
- ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")");
-
// start with displaying the "out of sync" warnings
showOutOfSyncWarning(true);
}
@@ -140,7 +145,7 @@ OverviewPage::OverviewPage(QWidget *parent) :
void OverviewPage::handleTransactionClicked(const QModelIndex &index)
{
if(filter)
- emit transactionClicked(filter->mapToSource(index));
+ Q_EMIT transactionClicked(filter->mapToSource(index));
}
OverviewPage::~OverviewPage()
diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h
index 64cb1dc4e0..4139eb35d3 100644
--- a/src/qt/overviewpage.h
+++ b/src/qt/overviewpage.h
@@ -12,6 +12,7 @@
class ClientModel;
class TransactionFilterProxy;
class TxViewDelegate;
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -28,18 +29,18 @@ class OverviewPage : public QWidget
Q_OBJECT
public:
- explicit OverviewPage(QWidget *parent = 0);
+ explicit OverviewPage(const PlatformStyle *platformStyle, QWidget *parent = 0);
~OverviewPage();
void setClientModel(ClientModel *clientModel);
void setWalletModel(WalletModel *walletModel);
void showOutOfSyncWarning(bool fShow);
-public slots:
+public Q_SLOTS:
void setBalance(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
-signals:
+Q_SIGNALS:
void transactionClicked(const QModelIndex &index);
private:
@@ -56,7 +57,7 @@ private:
TxViewDelegate *txdelegate;
TransactionFilterProxy *filter;
-private slots:
+private Q_SLOTS:
void updateDisplayUnit();
void handleTransactionClicked(const QModelIndex &index);
void updateAlerts(const QString &warnings);
diff --git a/src/qt/paymentrequestplus.cpp b/src/qt/paymentrequestplus.cpp
index 7e9729eeb9..78a783dea4 100644
--- a/src/qt/paymentrequestplus.cpp
+++ b/src/qt/paymentrequestplus.cpp
@@ -19,8 +19,6 @@
#include <QDebug>
#include <QSslCertificate>
-using namespace std;
-
class SSLVerifyError : public std::runtime_error
{
public:
@@ -49,7 +47,7 @@ bool PaymentRequestPlus::parse(const QByteArray& data)
return true;
}
-bool PaymentRequestPlus::SerializeToString(string* output) const
+bool PaymentRequestPlus::SerializeToString(std::string* output) const
{
return paymentRequest.SerializeToString(output);
}
diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp
index 09e9949b10..31a6d65a8d 100644
--- a/src/qt/paymentserver.cpp
+++ b/src/qt/paymentserver.cpp
@@ -10,7 +10,7 @@
#include "base58.h"
#include "chainparams.h"
-#include "main.h"
+#include "main.h" // For minRelayTxFee
#include "ui_interface.h"
#include "util.h"
#include "wallet/wallet.h"
@@ -46,8 +46,6 @@
#include <QUrlQuery>
#endif
-using namespace std;
-
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
const QString BITCOIN_IPC_PREFIX("bitcoin:");
// BIP70 payment protocol messages
@@ -148,7 +146,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
int nRootCerts = 0;
const QDateTime currentTime = QDateTime::currentDateTime();
- foreach (const QSslCertificate& cert, certList) {
+ Q_FOREACH (const QSslCertificate& cert, certList) {
// Don't log NULL certificates
if (cert.isNull())
continue;
@@ -201,7 +199,7 @@ void PaymentServer::LoadRootCAs(X509_STORE* _store)
// when uiReady() is called.
//
// Warning: ipcSendCommandLine() is called early in init,
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
{
@@ -269,7 +267,7 @@ void PaymentServer::ipcParseCommandLine(int argc, char* argv[])
bool PaymentServer::ipcSendCommandLine()
{
bool fResult = false;
- foreach (const QString& r, savedPaymentRequests)
+ Q_FOREACH (const QString& r, savedPaymentRequests)
{
QLocalSocket* socket = new QLocalSocket();
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
@@ -326,7 +324,7 @@ PaymentServer::PaymentServer(QObject* parent, bool startLocalServer) :
uriServer = new QLocalServer(this);
if (!uriServer->listen(name)) {
- // constructor is called early in init, so don't use "emit message()" here
+ // constructor is called early in init, so don't use "Q_EMIT message()" here
QMessageBox::critical(0, tr("Payment request error"),
tr("Cannot start bitcoin: click-to-pay handler"));
}
@@ -394,7 +392,7 @@ void PaymentServer::uiReady()
initNetManager();
saveURIs = false;
- foreach (const QString& s, savedPaymentRequests)
+ Q_FOREACH (const QString& s, savedPaymentRequests)
{
handleURIOrFile(s);
}
@@ -431,7 +429,7 @@ void PaymentServer::handleURIOrFile(const QString& s)
else
{
qWarning() << "PaymentServer::handleURIOrFile: Invalid URL: " << fetchUrl;
- emit message(tr("URI handling"),
+ Q_EMIT message(tr("URI handling"),
tr("Payment request fetch URL is invalid: %1").arg(fetchUrl.toString()),
CClientUIInterface::ICON_WARNING);
}
@@ -445,14 +443,14 @@ void PaymentServer::handleURIOrFile(const QString& s)
{
CBitcoinAddress address(recipient.address.toStdString());
if (!address.IsValid()) {
- emit message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
+ Q_EMIT message(tr("URI handling"), tr("Invalid payment address %1").arg(recipient.address),
CClientUIInterface::MSG_ERROR);
}
else
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
}
else
- emit message(tr("URI handling"),
+ Q_EMIT message(tr("URI handling"),
tr("URI cannot be parsed! This can be caused by an invalid Bitcoin address or malformed URI parameters."),
CClientUIInterface::ICON_WARNING);
@@ -466,12 +464,12 @@ void PaymentServer::handleURIOrFile(const QString& s)
SendCoinsRecipient recipient;
if (!readPaymentRequestFromFile(s, request))
{
- emit message(tr("Payment request file handling"),
+ Q_EMIT message(tr("Payment request file handling"),
tr("Payment request file cannot be read! This can be caused by an invalid payment request file."),
CClientUIInterface::ICON_WARNING);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -500,7 +498,7 @@ void PaymentServer::handleURIConnection()
//
// Warning: readPaymentRequestFromFile() is used in ipcSendCommandLine()
-// so don't use "emit message()", but "QMessageBox::"!
+// so don't use "Q_EMIT message()", but "QMessageBox::"!
//
bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request)
{
@@ -511,12 +509,7 @@ bool PaymentServer::readPaymentRequestFromFile(const QString& filename, PaymentR
}
// BIP70 DoS protection
- if (f.size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
- qWarning() << QString("PaymentServer::%1: Payment request %2 is too large (%3 bytes, allowed %4 bytes).")
- .arg(__func__)
- .arg(filename)
- .arg(f.size())
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
+ if (!verifySize(f.size())) {
return false;
}
@@ -533,7 +526,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
if (request.IsInitialized()) {
// Payment request network matches client network?
if (!verifyNetwork(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request network doesn't match client network."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -542,13 +535,13 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Make sure any payment requests involved are still valid.
// This is re-checked just before sending coins in WalletModel::sendCoins().
if (verifyExpired(request.getDetails())) {
- emit message(tr("Payment request rejected"), tr("Payment request expired."),
+ Q_EMIT message(tr("Payment request rejected"), tr("Payment request expired."),
CClientUIInterface::MSG_ERROR);
return false;
}
} else {
- emit message(tr("Payment request error"), tr("Payment request is not initialized."),
+ Q_EMIT message(tr("Payment request error"), tr("Payment request is not initialized."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -562,7 +555,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
QList<std::pair<CScript, CAmount> > sendingTos = request.getPayTo();
QStringList addresses;
- foreach(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ Q_FOREACH(const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
// Extract and check destination addresses
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest)) {
@@ -573,7 +566,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Unauthenticated payment requests to custom bitcoin addresses are not supported
// (there is no good way to tell the user where they are paying in a way they'd
// have a chance of understanding).
- emit message(tr("Payment request rejected"),
+ Q_EMIT message(tr("Payment request rejected"),
tr("Unverified payment requests to custom payment scripts are unsupported."),
CClientUIInterface::MSG_ERROR);
return false;
@@ -583,14 +576,14 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// but CAmount is defined as int64_t. Because of that we need to verify that amounts are in a valid range
// and no overflow has happened.
if (!verifyAmount(sendingTo.second)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
// Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first);
if (txOut.IsDust(::minRelayTxFee)) {
- emit message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
+ Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR);
@@ -600,7 +593,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
recipient.amount += sendingTo.second;
// Also verify that the final amount is still in a valid range after adding additional amounts.
if (!verifyAmount(recipient.amount)) {
- emit message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request rejected"), tr("Invalid payment request."), CClientUIInterface::MSG_ERROR);
return false;
}
}
@@ -647,7 +640,7 @@ void PaymentServer::fetchPaymentACK(CWallet* wallet, SendCoinsRecipient recipien
// Create a new refund address, or re-use:
QString account = tr("Refund from %1").arg(recipient.authenticatedMerchant);
std::string strAccount = account.toStdString();
- set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
+ std::set<CTxDestination> refundAddresses = wallet->GetAccountAddresses(strAccount);
if (!refundAddresses.empty()) {
CScript s = GetScriptForDestination(*refundAddresses.begin());
payments::Output* refund_to = payment.add_refund_to();
@@ -687,14 +680,13 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
reply->deleteLater();
// BIP70 DoS protection
- if (reply->size() > BIP70_MAX_PAYMENTREQUEST_SIZE) {
- QString msg = tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
- .arg(reply->request().url().toString())
- .arg(reply->size())
- .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
-
- qWarning() << QString("PaymentServer::%1:").arg(__func__) << msg;
- emit message(tr("Payment request DoS protection"), msg, CClientUIInterface::MSG_ERROR);
+ if (!verifySize(reply->size())) {
+ Q_EMIT message(tr("Payment request rejected"),
+ tr("Payment request %1 is too large (%2 bytes, allowed %3 bytes).")
+ .arg(reply->request().url().toString())
+ .arg(reply->size())
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE),
+ CClientUIInterface::MSG_ERROR);
return;
}
@@ -704,7 +696,7 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->errorString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
return;
}
@@ -718,12 +710,12 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
if (!request.parse(data))
{
qWarning() << "PaymentServer::netRequestFinished: Error parsing payment request";
- emit message(tr("Payment request error"),
+ Q_EMIT message(tr("Payment request error"),
tr("Payment request cannot be parsed!"),
CClientUIInterface::MSG_ERROR);
}
else if (processPaymentRequest(request, recipient))
- emit receivedPaymentRequest(recipient);
+ Q_EMIT receivedPaymentRequest(recipient);
return;
}
@@ -736,11 +728,11 @@ void PaymentServer::netRequestFinished(QNetworkReply* reply)
.arg(reply->request().url().toString());
qWarning() << "PaymentServer::netRequestFinished: " << msg;
- emit message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Payment request error"), msg, CClientUIInterface::MSG_ERROR);
}
else
{
- emit receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
+ Q_EMIT receivedPaymentACK(GUIUtil::HtmlEscape(paymentACK.memo()));
}
}
}
@@ -750,11 +742,11 @@ void PaymentServer::reportSslErrors(QNetworkReply* reply, const QList<QSslError>
Q_UNUSED(reply);
QString errString;
- foreach (const QSslError& err, errs) {
+ Q_FOREACH (const QSslError& err, errs) {
qWarning() << "PaymentServer::reportSslErrors: " << err;
errString += err.errorString() + "\n";
}
- emit message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
+ Q_EMIT message(tr("Network request error"), errString, CClientUIInterface::MSG_ERROR);
}
void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
@@ -764,8 +756,8 @@ void PaymentServer::setOptionsModel(OptionsModel *optionsModel)
void PaymentServer::handlePaymentACK(const QString& paymentACKMsg)
{
- // currently we don't futher process or store the paymentACK message
- emit message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
+ // currently we don't further process or store the paymentACK message
+ Q_EMIT message(tr("Payment acknowledged"), paymentACKMsg, CClientUIInterface::ICON_INFORMATION | CClientUIInterface::MODAL);
}
bool PaymentServer::verifyNetwork(const payments::PaymentDetails& requestDetails)
@@ -792,6 +784,18 @@ bool PaymentServer::verifyExpired(const payments::PaymentDetails& requestDetails
return fVerified;
}
+bool PaymentServer::verifySize(qint64 requestSize)
+{
+ bool fVerified = (requestSize <= BIP70_MAX_PAYMENTREQUEST_SIZE);
+ if (!fVerified) {
+ qWarning() << QString("PaymentServer::%1: Payment request too large (%2 bytes, allowed %3 bytes).")
+ .arg(__func__)
+ .arg(requestSize)
+ .arg(BIP70_MAX_PAYMENTREQUEST_SIZE);
+ }
+ return fVerified;
+}
+
bool PaymentServer::verifyAmount(const CAmount& requestAmount)
{
bool fVerified = MoneyRange(requestAmount);
diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h
index 32ed27983e..fa120a435c 100644
--- a/src/qt/paymentserver.h
+++ b/src/qt/paymentserver.h
@@ -88,17 +88,16 @@ public:
// OptionsModel is used for getting proxy settings and display unit
void setOptionsModel(OptionsModel *optionsModel);
- // This is now public, because we use it in paymentservertests.cpp
- static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
-
// Verify that the payment request network matches the client network
static bool verifyNetwork(const payments::PaymentDetails& requestDetails);
// Verify if the payment request is expired
static bool verifyExpired(const payments::PaymentDetails& requestDetails);
+ // Verify the payment request size is valid as per BIP70
+ static bool verifySize(qint64 requestSize);
// Verify the payment request amount is valid
static bool verifyAmount(const CAmount& requestAmount);
-signals:
+Q_SIGNALS:
// Fired when a valid payment request is received
void receivedPaymentRequest(SendCoinsRecipient);
@@ -108,7 +107,7 @@ signals:
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
-public slots:
+public Q_SLOTS:
// Signal this when the main window's UI is ready
// to display payment requests to the user
void uiReady();
@@ -119,7 +118,7 @@ public slots:
// Handle an incoming URI, URI with local file scheme or file
void handleURIOrFile(const QString& s);
-private slots:
+private Q_SLOTS:
void handleURIConnection();
void netRequestFinished(QNetworkReply*);
void reportSslErrors(QNetworkReply*, const QList<QSslError> &);
@@ -131,6 +130,7 @@ protected:
bool eventFilter(QObject *object, QEvent *event);
private:
+ static bool readPaymentRequestFromFile(const QString& filename, PaymentRequestPlus& request);
bool processPaymentRequest(const PaymentRequestPlus& request, SendCoinsRecipient& recipient);
void fetchRequest(const QUrl& url);
diff --git a/src/qt/peertablemodel.cpp b/src/qt/peertablemodel.cpp
index 220f273d02..770a860544 100644
--- a/src/qt/peertablemodel.cpp
+++ b/src/qt/peertablemodel.cpp
@@ -8,7 +8,6 @@
#include "guiconstants.h"
#include "guiutil.h"
-#include "net.h"
#include "sync.h"
#include <QDebug>
@@ -63,11 +62,12 @@ public:
#if QT_VERSION >= 0x040700
cachedNodeStats.reserve(vNodes.size());
#endif
- BOOST_FOREACH(CNode* pnode, vNodes)
+ Q_FOREACH (CNode* pnode, vNodes)
{
CNodeCombinedStats stats;
stats.nodeStateStats.nMisbehavior = 0;
stats.nodeStateStats.nSyncHeight = -1;
+ stats.nodeStateStats.nCommonHeight = -1;
stats.fNodeStateStatsAvailable = false;
pnode->copyStats(stats.nodeStats);
cachedNodeStats.append(stats);
@@ -91,22 +91,21 @@ public:
// build index map
mapNodeRows.clear();
int row = 0;
- BOOST_FOREACH(CNodeCombinedStats &stats, cachedNodeStats)
+ Q_FOREACH (const CNodeCombinedStats& stats, cachedNodeStats)
mapNodeRows.insert(std::pair<NodeId, int>(stats.nodeStats.nodeid, row++));
}
- int size()
+ int size() const
{
return cachedNodeStats.size();
}
CNodeCombinedStats *index(int idx)
{
- if(idx >= 0 && idx < cachedNodeStats.size()) {
+ if (idx >= 0 && idx < cachedNodeStats.size())
return &cachedNodeStats[idx];
- } else {
- return 0;
- }
+
+ return 0;
}
};
@@ -170,7 +169,7 @@ QVariant PeerTableModel::data(const QModelIndex &index, int role) const
}
} else if (role == Qt::TextAlignmentRole) {
if (index.column() == Ping)
- return (int)(Qt::AlignRight | Qt::AlignVCenter);
+ return (QVariant)(Qt::AlignRight | Qt::AlignVCenter);
}
return QVariant();
@@ -203,13 +202,8 @@ QModelIndex PeerTableModel::index(int row, int column, const QModelIndex &parent
CNodeCombinedStats *data = priv->index(row);
if (data)
- {
return createIndex(row, column, data);
- }
- else
- {
- return QModelIndex();
- }
+ return QModelIndex();
}
const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
@@ -219,9 +213,9 @@ const CNodeCombinedStats *PeerTableModel::getNodeStats(int idx)
void PeerTableModel::refresh()
{
- emit layoutAboutToBeChanged();
+ Q_EMIT layoutAboutToBeChanged();
priv->refreshPeers();
- emit layoutChanged();
+ Q_EMIT layoutChanged();
}
int PeerTableModel::getRowByNodeId(NodeId nodeid)
diff --git a/src/qt/peertablemodel.h b/src/qt/peertablemodel.h
index bff7bb824e..5f149ea873 100644
--- a/src/qt/peertablemodel.h
+++ b/src/qt/peertablemodel.h
@@ -5,7 +5,7 @@
#ifndef BITCOIN_QT_PEERTABLEMODEL_H
#define BITCOIN_QT_PEERTABLEMODEL_H
-#include "main.h"
+#include "main.h" // For CNodeStateStats
#include "net.h"
#include <QAbstractTableModel>
@@ -68,7 +68,7 @@ public:
void sort(int column, Qt::SortOrder order);
/*@}*/
-public slots:
+public Q_SLOTS:
void refresh();
private:
diff --git a/src/qt/platformstyle.cpp b/src/qt/platformstyle.cpp
new file mode 100644
index 0000000000..11cbc7a47c
--- /dev/null
+++ b/src/qt/platformstyle.cpp
@@ -0,0 +1,147 @@
+// 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.
+
+#include "platformstyle.h"
+
+#include "guiconstants.h"
+
+#include <QApplication>
+#include <QColor>
+#include <QIcon>
+#include <QImage>
+#include <QPalette>
+#include <QPixmap>
+
+static const struct {
+ const char *platformId;
+ /** Show images on push buttons */
+ const bool imagesOnButtons;
+ /** Colorize single-color icons */
+ const bool colorizeIcons;
+ /** Extra padding/spacing in transactionview */
+ const bool useExtraSpacing;
+} platform_styles[] = {
+ {"macosx", false, false, true},
+ {"windows", true, false, false},
+ /* Other: linux, unix, ... */
+ {"other", true, true, false}
+};
+static const unsigned platform_styles_count = sizeof(platform_styles)/sizeof(*platform_styles);
+
+namespace {
+/* Local functions for colorizing single-color images */
+
+void MakeSingleColorImage(QImage& img, const QColor& colorbase)
+{
+ img = img.convertToFormat(QImage::Format_ARGB32);
+ for (int x = img.width(); x--; )
+ {
+ for (int y = img.height(); y--; )
+ {
+ const QRgb rgb = img.pixel(x, y);
+ img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb)));
+ }
+ }
+}
+
+QIcon ColorizeIcon(const QIcon& ico, const QColor& colorbase)
+{
+ QIcon new_ico;
+ QSize sz;
+ Q_FOREACH(sz, ico.availableSizes())
+ {
+ QImage img(ico.pixmap(sz).toImage());
+ MakeSingleColorImage(img, colorbase);
+ new_ico.addPixmap(QPixmap::fromImage(img));
+ }
+ return new_ico;
+}
+
+QImage ColorizeImage(const QString& filename, const QColor& colorbase)
+{
+ QImage img(filename);
+ MakeSingleColorImage(img, colorbase);
+ return img;
+}
+
+QIcon ColorizeIcon(const QString& filename, const QColor& colorbase)
+{
+ return QIcon(QPixmap::fromImage(ColorizeImage(filename, colorbase)));
+}
+
+}
+
+
+PlatformStyle::PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing):
+ name(name),
+ imagesOnButtons(imagesOnButtons),
+ colorizeIcons(colorizeIcons),
+ useExtraSpacing(useExtraSpacing),
+ singleColor(0,0,0),
+ textColor(0,0,0)
+{
+ // Determine icon highlighting color
+ if (colorizeIcons) {
+ const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
+ const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
+ const QColor colorText(QApplication::palette().color(QPalette::WindowText));
+ const int colorTextLightness = colorText.lightness();
+ QColor colorbase;
+ if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness))
+ colorbase = colorHighlightBg;
+ else
+ colorbase = colorHighlightFg;
+ singleColor = colorbase;
+ }
+ // Determine text color
+ textColor = QColor(QApplication::palette().color(QPalette::WindowText));
+}
+
+QImage PlatformStyle::SingleColorImage(const QString& filename) const
+{
+ if (!colorizeIcons)
+ return QImage(filename);
+ return ColorizeImage(filename, SingleColor());
+}
+
+QIcon PlatformStyle::SingleColorIcon(const QString& filename) const
+{
+ if (!colorizeIcons)
+ return QIcon(filename);
+ return ColorizeIcon(filename, SingleColor());
+}
+
+QIcon PlatformStyle::SingleColorIcon(const QIcon& icon) const
+{
+ if (!colorizeIcons)
+ return icon;
+ return ColorizeIcon(icon, SingleColor());
+}
+
+QIcon PlatformStyle::TextColorIcon(const QString& filename) const
+{
+ return ColorizeIcon(filename, TextColor());
+}
+
+QIcon PlatformStyle::TextColorIcon(const QIcon& icon) const
+{
+ return ColorizeIcon(icon, TextColor());
+}
+
+const PlatformStyle *PlatformStyle::instantiate(const QString &platformId)
+{
+ for (unsigned x=0; x<platform_styles_count; ++x)
+ {
+ if (platformId == platform_styles[x].platformId)
+ {
+ return new PlatformStyle(
+ platform_styles[x].platformId,
+ platform_styles[x].imagesOnButtons,
+ platform_styles[x].colorizeIcons,
+ platform_styles[x].useExtraSpacing);
+ }
+ }
+ return 0;
+}
+
diff --git a/src/qt/platformstyle.h b/src/qt/platformstyle.h
new file mode 100644
index 0000000000..4e763e760e
--- /dev/null
+++ b/src/qt/platformstyle.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef BITCOIN_QT_PLATFORMSTYLE_H
+#define BITCOIN_QT_PLATFORMSTYLE_H
+
+#include <QIcon>
+#include <QPixmap>
+#include <QString>
+
+/* Coin network-specific GUI style information */
+class PlatformStyle
+{
+public:
+ /** Get style associated with provided platform name, or 0 if not known */
+ static const PlatformStyle *instantiate(const QString &platformId);
+
+ const QString &getName() const { return name; }
+
+ bool getImagesOnButtons() const { return imagesOnButtons; }
+ bool getUseExtraSpacing() const { return useExtraSpacing; }
+
+ QColor TextColor() const { return textColor; }
+ QColor SingleColor() const { return singleColor; }
+
+ /** Colorize an image (given filename) with the icon color */
+ QImage SingleColorImage(const QString& filename) const;
+
+ /** Colorize an icon (given filename) with the icon color */
+ QIcon SingleColorIcon(const QString& filename) const;
+
+ /** Colorize an icon (given object) with the icon color */
+ QIcon SingleColorIcon(const QIcon& icon) const;
+
+ /** Colorize an icon (given filename) with the text color */
+ QIcon TextColorIcon(const QString& filename) const;
+
+ /** Colorize an icon (given object) with the text color */
+ QIcon TextColorIcon(const QIcon& icon) const;
+
+private:
+ PlatformStyle(const QString &name, bool imagesOnButtons, bool colorizeIcons, bool useExtraSpacing);
+
+ QString name;
+ bool imagesOnButtons;
+ bool colorizeIcons;
+ bool useExtraSpacing;
+ QColor singleColor;
+ QColor textColor;
+ /* ... more to come later */
+};
+
+#endif // BITCOIN_QT_PLATFORMSTYLE_H
+
diff --git a/src/qt/qvalidatedlineedit.h b/src/qt/qvalidatedlineedit.h
index f63568d27f..8665acda5e 100644
--- a/src/qt/qvalidatedlineedit.h
+++ b/src/qt/qvalidatedlineedit.h
@@ -27,11 +27,11 @@ private:
bool valid;
const QValidator *checkValidator;
-public slots:
+public Q_SLOTS:
void setValid(bool valid);
void setEnabled(bool enabled);
-private slots:
+private Q_SLOTS:
void markValid();
void checkValidity();
};
diff --git a/src/qt/qvaluecombobox.cpp b/src/qt/qvaluecombobox.cpp
index f73268c958..800436661f 100644
--- a/src/qt/qvaluecombobox.cpp
+++ b/src/qt/qvaluecombobox.cpp
@@ -27,5 +27,5 @@ void QValueComboBox::setRole(int role)
void QValueComboBox::handleSelectionChanged(int idx)
{
- emit valueChanged();
+ Q_EMIT valueChanged();
}
diff --git a/src/qt/qvaluecombobox.h b/src/qt/qvaluecombobox.h
index dc85d64cb5..5b20e6a5a4 100644
--- a/src/qt/qvaluecombobox.h
+++ b/src/qt/qvaluecombobox.h
@@ -24,13 +24,13 @@ public:
/** Specify model role to use as ordinal value (defaults to Qt::UserRole) */
void setRole(int role);
-signals:
+Q_SIGNALS:
void valueChanged();
private:
int role;
-private slots:
+private Q_SLOTS:
void handleSelectionChanged(int idx);
};
diff --git a/src/qt/receivecoinsdialog.cpp b/src/qt/receivecoinsdialog.cpp
index 28cbd3abed..7fb68cc32a 100644
--- a/src/qt/receivecoinsdialog.cpp
+++ b/src/qt/receivecoinsdialog.cpp
@@ -10,9 +10,9 @@
#include "bitcoinunits.h"
#include "guiutil.h"
#include "optionsmodel.h"
+#include "platformstyle.h"
#include "receiverequestdialog.h"
#include "recentrequeststablemodel.h"
-#include "scicon.h"
#include "walletmodel.h"
#include <QAction>
@@ -22,24 +22,25 @@
#include <QScrollBar>
#include <QTextDocument>
-ReceiveCoinsDialog::ReceiveCoinsDialog(QWidget *parent) :
+ReceiveCoinsDialog::ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::ReceiveCoinsDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->clearButton->setIcon(QIcon());
- ui->receiveButton->setIcon(QIcon());
- ui->showRequestButton->setIcon(QIcon());
- ui->removeRequestButton->setIcon(QIcon());
-#else
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->receiveButton->setIcon(SingleColorIcon(":/icons/receiving_addresses"));
- ui->showRequestButton->setIcon(SingleColorIcon(":/icons/edit"));
- ui->removeRequestButton->setIcon(SingleColorIcon(":/icons/remove"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->clearButton->setIcon(QIcon());
+ ui->receiveButton->setIcon(QIcon());
+ ui->showRequestButton->setIcon(QIcon());
+ ui->removeRequestButton->setIcon(QIcon());
+ } else {
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->receiveButton->setIcon(platformStyle->SingleColorIcon(":/icons/receiving_addresses"));
+ ui->showRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->removeRequestButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ }
// context menu actions
QAction *copyLabelAction = new QAction(tr("Copy label"), this);
@@ -132,7 +133,7 @@ void ReceiveCoinsDialog::on_receiveButton_clicked()
if(ui->reuseAddress->isChecked())
{
/* Choose existing receiving address */
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
dlg.setModel(model->getAddressTableModel());
if(dlg.exec())
{
@@ -185,8 +186,7 @@ void ReceiveCoinsDialog::on_showRequestButton_clicked()
return;
QModelIndexList selection = ui->recentRequestsView->selectionModel()->selectedRows();
- foreach (QModelIndex index, selection)
- {
+ Q_FOREACH (const QModelIndex& index, selection) {
on_recentRequestsView_doubleClicked(index);
}
}
diff --git a/src/qt/receivecoinsdialog.h b/src/qt/receivecoinsdialog.h
index 70a1842fa2..eaaf129a91 100644
--- a/src/qt/receivecoinsdialog.h
+++ b/src/qt/receivecoinsdialog.h
@@ -16,6 +16,7 @@
#include <QVariant>
class OptionsModel;
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -39,12 +40,12 @@ public:
MINIMUM_COLUMN_WIDTH = 130
};
- explicit ReceiveCoinsDialog(QWidget *parent = 0);
+ explicit ReceiveCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~ReceiveCoinsDialog();
void setModel(WalletModel *model);
-public slots:
+public Q_SLOTS:
void clear();
void reject();
void accept();
@@ -57,10 +58,12 @@ private:
GUIUtil::TableViewLastColumnResizingFixer *columnResizingFixer;
WalletModel *model;
QMenu *contextMenu;
+ const PlatformStyle *platformStyle;
+
void copyColumnToClipboard(int column);
virtual void resizeEvent(QResizeEvent *event);
-private slots:
+private Q_SLOTS:
void on_receiveButton_clicked();
void on_showRequestButton_clicked();
void on_removeRequestButton_clicked();
diff --git a/src/qt/receiverequestdialog.h b/src/qt/receiverequestdialog.h
index 3e5f897be6..69f84ebbd7 100644
--- a/src/qt/receiverequestdialog.h
+++ b/src/qt/receiverequestdialog.h
@@ -32,7 +32,7 @@ public:
explicit QRImageWidget(QWidget *parent = 0);
QImage exportImage();
-public slots:
+public Q_SLOTS:
void saveImage();
void copyImage();
@@ -55,7 +55,7 @@ public:
void setModel(OptionsModel *model);
void setInfo(const SendCoinsRecipient &info);
-private slots:
+private Q_SLOTS:
void on_btnCopyURI_clicked();
void on_btnCopyAddress_clicked();
diff --git a/src/qt/recentrequeststablemodel.cpp b/src/qt/recentrequeststablemodel.cpp
index 543b977d8f..5692a7aaef 100644
--- a/src/qt/recentrequeststablemodel.cpp
+++ b/src/qt/recentrequeststablemodel.cpp
@@ -119,7 +119,7 @@ QVariant RecentRequestsTableModel::headerData(int section, Qt::Orientation orien
void RecentRequestsTableModel::updateAmountColumnTitle()
{
columns[Amount] = getAmountTitle();
- emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+ Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
}
/** Gets title for amount column including current display unit if optionsModel reference available. */
@@ -214,7 +214,7 @@ void RecentRequestsTableModel::addNewRequest(RecentRequestEntry &recipient)
void RecentRequestsTableModel::sort(int column, Qt::SortOrder order)
{
qSort(list.begin(), list.end(), RecentRequestEntryLessThan(column, order));
- emit dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
+ Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(list.size() - 1, NUMBER_OF_COLUMNS - 1, QModelIndex()));
}
void RecentRequestsTableModel::updateDisplayUnit()
diff --git a/src/qt/recentrequeststablemodel.h b/src/qt/recentrequeststablemodel.h
index 85bad126db..64faa72d45 100644
--- a/src/qt/recentrequeststablemodel.h
+++ b/src/qt/recentrequeststablemodel.h
@@ -89,7 +89,7 @@ public:
void addNewRequest(const std::string &recipient);
void addNewRequest(RecentRequestEntry &recipient);
-public slots:
+public Q_SLOTS:
void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
void updateDisplayUnit();
diff --git a/src/qt/res/bitcoin-qt-res.rc b/src/qt/res/bitcoin-qt-res.rc
index c0f3e2fb39..9f66d0af79 100644
--- a/src/qt/res/bitcoin-qt-res.rc
+++ b/src/qt/res/bitcoin-qt-res.rc
@@ -19,7 +19,7 @@ BEGIN
BLOCK "040904E4" // U.S. English - multilingual (hex)
BEGIN
VALUE "CompanyName", "Bitcoin"
- VALUE "FileDescription", "Bitcoin Core (OSS GUI client for Bitcoin)"
+ VALUE "FileDescription", "Bitcoin Core (GUI node for Bitcoin)"
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", "bitcoin-qt"
VALUE "LegalCopyright", COPYRIGHT_STR
diff --git a/src/qt/res/icons/about_qt.png b/src/qt/res/icons/about_qt.png
index dd27a99d0a..c40abfd3a6 100644
--- a/src/qt/res/icons/about_qt.png
+++ b/src/qt/res/icons/about_qt.png
Binary files differ
diff --git a/src/qt/res/icons/clock1.png b/src/qt/res/icons/clock1.png
index ceae5ed0d9..162204d1bb 100644
--- a/src/qt/res/icons/clock1.png
+++ b/src/qt/res/icons/clock1.png
Binary files differ
diff --git a/src/qt/res/icons/clock2.png b/src/qt/res/icons/clock2.png
index 159f69a8fc..8f4263a31c 100644
--- a/src/qt/res/icons/clock2.png
+++ b/src/qt/res/icons/clock2.png
Binary files differ
diff --git a/src/qt/res/icons/clock3.png b/src/qt/res/icons/clock3.png
index d668e35ffc..7f11a7566c 100644
--- a/src/qt/res/icons/clock3.png
+++ b/src/qt/res/icons/clock3.png
Binary files differ
diff --git a/src/qt/res/icons/clock4.png b/src/qt/res/icons/clock4.png
index 5ebf8ed7ac..fdd1a0fce3 100644
--- a/src/qt/res/icons/clock4.png
+++ b/src/qt/res/icons/clock4.png
Binary files differ
diff --git a/src/qt/res/icons/clock5.png b/src/qt/res/icons/clock5.png
index 96f15ef7d9..7d6556c6cf 100644
--- a/src/qt/res/icons/clock5.png
+++ b/src/qt/res/icons/clock5.png
Binary files differ
diff --git a/src/qt/res/icons/connect0.png b/src/qt/res/icons/connect0.png
index 58e2c3e965..ef708d81fb 100644
--- a/src/qt/res/icons/connect0.png
+++ b/src/qt/res/icons/connect0.png
Binary files differ
diff --git a/src/qt/res/icons/connect1.png b/src/qt/res/icons/connect1.png
index 949e7a922d..ed358e6f8e 100644
--- a/src/qt/res/icons/connect1.png
+++ b/src/qt/res/icons/connect1.png
Binary files differ
diff --git a/src/qt/res/icons/connect2.png b/src/qt/res/icons/connect2.png
index 143b2054fb..3bbb0d395c 100644
--- a/src/qt/res/icons/connect2.png
+++ b/src/qt/res/icons/connect2.png
Binary files differ
diff --git a/src/qt/res/icons/connect3.png b/src/qt/res/icons/connect3.png
index 143b2054fb..0db99ad8d3 100644
--- a/src/qt/res/icons/connect3.png
+++ b/src/qt/res/icons/connect3.png
Binary files differ
diff --git a/src/qt/res/icons/connect4.png b/src/qt/res/icons/connect4.png
index f96e3455ce..9dd19fc2bd 100644
--- a/src/qt/res/icons/connect4.png
+++ b/src/qt/res/icons/connect4.png
Binary files differ
diff --git a/src/qt/res/icons/transaction0.png b/src/qt/res/icons/transaction0.png
index 1091b86e68..72c44565ec 100644
--- a/src/qt/res/icons/transaction0.png
+++ b/src/qt/res/icons/transaction0.png
Binary files differ
diff --git a/src/qt/res/icons/warning.png b/src/qt/res/icons/warning.png
new file mode 100644
index 0000000000..6bc5ac7895
--- /dev/null
+++ b/src/qt/res/icons/warning.png
Binary files differ
diff --git a/src/qt/res/movies/makespinner.sh b/src/qt/res/movies/makespinner.sh
index 625fb17173..a4c2fddbbf 100755
--- a/src/qt/res/movies/makespinner.sh
+++ b/src/qt/res/movies/makespinner.sh
@@ -1,6 +1,7 @@
-for i in {1..35}
+FRAMEDIR=$(dirname $0)
+for i in {0..35}
do
- value=$(printf "%03d" $i)
+ frame=$(printf "%03d" $i)
angle=$(($i * 10))
- convert spinner-000.png -background "rgba(0,0,0,0.0)" -distort SRT $angle spinner-$value.png
+ convert $FRAMEDIR/../src/spinner.png -background "rgba(0,0,0,0.0)" -distort SRT $angle $FRAMEDIR/spinner-$frame.png
done
diff --git a/src/qt/res/movies/spinner-000.png b/src/qt/res/movies/spinner-000.png
index 1e92d859da..0dc48d0d8c 100644
--- a/src/qt/res/movies/spinner-000.png
+++ b/src/qt/res/movies/spinner-000.png
Binary files differ
diff --git a/src/qt/res/src/clock_1.svg b/src/qt/res/src/clock_1.svg
index 4e49772d26..2a3d84c2d0 100644
--- a/src/qt/res/src/clock_1.svg
+++ b/src/qt/res/src/clock_1.svg
@@ -9,5 +9,7 @@
c-57.8,0-112.1,22.5-153,63.4c-40.9,40.9-63.4,95.2-63.4,153c0,57.8,22.5,112.1,63.4,153c40.9,40.9,95.2,63.4,153,63.4
c57.8,0,112.1-22.5,153-63.4c40.9-40.9,63.4-95.2,63.4-153c0-57.8-22.5-112.1-63.4-153C409.8,227.1,355.4,204.6,297.6,204.6z"/>
</g>
-<polygon points="478.3,253.4 297.6,184.6 297.6,420.9 534,420.9 "/>
+<path
+ d="M 478.3,253.4 297.6,184.6 c 0,0 0,78.8 0,118.2 0,117.5 -0.4,118.1 118.2,118.1 39.4,0 118.2,0 118.2,0 z"
+ id="polygon7" />
</svg>
diff --git a/src/qt/res/src/clock_2.svg b/src/qt/res/src/clock_2.svg
index 995446e46e..2de8d467b7 100644
--- a/src/qt/res/src/clock_2.svg
+++ b/src/qt/res/src/clock_2.svg
@@ -9,6 +9,5 @@
c-57.8,0-112.1,22.5-153,63.4c-40.9,40.9-63.4,95.2-63.4,153c0,57.8,22.5,112.1,63.4,153c40.9,40.9,95.2,63.4,153,63.4
c57.8,0,112.1-22.5,153-63.4c40.9-40.9,63.4-95.2,63.4-153c0-57.8-22.5-112.1-63.4-153C409.8,227.1,355.4,204.6,297.6,204.6z"/>
</g>
-<polygon points="465.2,601.6 534,420.9 297.6,420.9 297.6,657.3 "/>
-<polygon points="478.3,253.4 297.6,184.6 297.6,420.9 534,420.9 "/>
+<polygon points="465.2,601.6 534,420.9 478.3,253.4 297.6,184.6 297.6,420.9 297.6,657.3 "/>
</svg>
diff --git a/src/qt/res/src/clock_3.svg b/src/qt/res/src/clock_3.svg
index ea47a84730..b691043e3e 100644
--- a/src/qt/res/src/clock_3.svg
+++ b/src/qt/res/src/clock_3.svg
@@ -9,7 +9,7 @@
c-57.8,0-112.1,22.5-153,63.4c-40.9,40.9-63.4,95.2-63.4,153c0,57.8,22.5,112.1,63.4,153c40.9,40.9,95.2,63.4,153,63.4
c57.8,0,112.1-22.5,153-63.4c40.9-40.9,63.4-95.2,63.4-153c0-57.8-22.5-112.1-63.4-153C409.8,227.1,355.4,204.6,297.6,204.6z"/>
</g>
-<polygon points="117,588.5 297.6,657.3 297.6,420.9 61.3,420.9 "/>
-<polygon points="465.2,601.6 534,420.9 297.6,420.9 297.6,657.3 "/>
-<polygon points="478.3,253.4 297.6,184.6 297.6,420.9 534,420.9 "/>
+<path
+ d="M 465.2,601.6 534,420.9 478.3,253.4 297.6,184.6 c 0,0 0,78.8 0,118.2 0,117.7 0.4,118.1 -118.1,118.1 -39.4,0 -118.2,0 -118.2,0 l 55.7,167.6 180.6,68.8 z"
+ id="polygon7" />
</svg>
diff --git a/src/qt/res/src/clock_4.svg b/src/qt/res/src/clock_4.svg
index 43160288d8..ea311f31e8 100644
--- a/src/qt/res/src/clock_4.svg
+++ b/src/qt/res/src/clock_4.svg
@@ -1,18 +1,23 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 841.9 841.9" enable-background="new 0 0 841.9 841.9" xml:space="preserve">
-<g>
- <path d="M297.6,677.3c-68.5,0-132.9-26.7-181.3-75.1S41.3,489.4,41.3,420.9s26.7-132.9,75.1-181.3c48.4-48.4,112.8-75.1,181.3-75.1
- s132.9,26.7,181.3,75.1c48.4,48.4,75.1,112.8,75.1,181.3s-26.7,132.9-75.1,181.3S366.1,677.3,297.6,677.3z M297.6,204.6
- c-57.8,0-112.1,22.5-153,63.4c-40.9,40.9-63.4,95.2-63.4,153c0,57.8,22.5,112.1,63.4,153c40.9,40.9,95.2,63.4,153,63.4
- c57.8,0,112.1-22.5,153-63.4c40.9-40.9,63.4-95.2,63.4-153c0-57.8-22.5-112.1-63.4-153C409.8,227.1,355.4,204.6,297.6,204.6z"/>
-</g>
-<polygon points="130.1,240.3 61.3,420.9 297.6,420.9 297.6,184.6 "/>
-<polygon points="117,588.5 297.6,657.3 297.6,420.9 61.3,420.9 "/>
-<polygon points="465.2,601.6 534,420.9 297.6,420.9 297.6,657.3 "/>
-<polygon points="478.3,253.4 297.6,184.6 297.6,420.9 534,420.9 "/>
-<path fill="#FFFFFF" d="M293.5,452.6h99.6c14.9,0,24.8-9.9,24.8-24.8S408,403,393.1,403h-74.8V278.2c0-14.9-9.9-24.8-24.8-24.8
- c-14.9,0-24.8,9.9-24.8,24.8v149.6C268.7,440.2,278.7,452.6,293.5,452.6z"/>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xml:space="preserve"
+ enable-background="new 0 0 841.9 841.9"
+ viewBox="0 0 841.9 841.9"
+ y="0px"
+ x="0px"
+ id="Ebene_1"
+ version="1.1"><metadata
+ id="metadata15"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs13" /><g
+ id="g3"><path
+ id="path5"
+ d="M297.6,677.3c-68.5,0-132.9-26.7-181.3-75.1S41.3,489.4,41.3,420.9s26.7-132.9,75.1-181.3c48.4-48.4,112.8-75.1,181.3-75.1 s132.9,26.7,181.3,75.1c48.4,48.4,75.1,112.8,75.1,181.3s-26.7,132.9-75.1,181.3S366.1,677.3,297.6,677.3z M297.6,204.6 c-57.8,0-112.1,22.5-153,63.4c-40.9,40.9-63.4,95.2-63.4,153c0,57.8,22.5,112.1,63.4,153c40.9,40.9,95.2,63.4,153,63.4 c57.8,0,112.1-22.5,153-63.4c40.9-40.9,63.4-95.2,63.4-153c0-57.8-22.5-112.1-63.4-153C409.8,227.1,355.4,204.6,297.6,204.6z" /></g><path
+ id="polygon7"
+ d="M 297.6 184.6 L 130.1 240.3 L 61.3 420.9 L 117 588.5 L 297.6 657.3 L 465.2 601.6 L 534 420.9 L 478.3 253.4 L 297.6 184.6 z M 293.5 253.4 C 308.4 253.4 318.3 263.3 318.3 278.2 L 318.3 403 L 393.1 403 C 408 403 417.9 412.9 417.9 427.8 C 417.9 442.7 408 452.6 393.1 452.6 L 293.5 452.6 C 278.7 452.6 268.7 440.2 268.7 427.8 L 268.7 278.2 C 268.7 263.3 278.6 253.4 293.5 253.4 z " /></svg> \ No newline at end of file
diff --git a/src/qt/res/src/connect-0.svg b/src/qt/res/src/connect-0.svg
index bedbec7777..7d2afac622 100644
--- a/src/qt/res/src/connect-0.svg
+++ b/src/qt/res/src/connect-0.svg
@@ -1,11 +1,66 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M13.4,19.4c0.8-0.8,0.8-2,0-2.8c-0.8-0.8-2-0.8-2.8,0
- c-0.8,0.8-0.8,2.1,0,2.8C11.4,20.2,12.6,20.2,13.4,19.4z M7.8,15.8c-0.5,0-1-0.2-1.4-0.6c-0.8-0.8-0.8-2,0-2.8
- c3.1-3.1,8.2-3.1,11.3,0c0.8,0.8,0.8,2,0,2.8c-0.8,0.8-2,0.8-2.8,0c-1.6-1.6-4.1-1.6-5.7,0C8.8,15.6,8.3,15.8,7.8,15.8z"/>
-<path fill="none" stroke="#000000" stroke-miterlimit="10" d="M20.5,11.5c-0.5,0-1-0.2-1.4-0.6C15.2,7,8.8,7,4.9,10.9
- c-0.8,0.8-2,0.8-2.8,0c-0.8-0.8-0.8-2,0-2.8c5.5-5.5,14.3-5.5,19.8,0c0.8,0.8,0.8,2,0,2.8C21.5,11.3,21,11.5,20.5,11.5z"/>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg2"
+ viewBox="0 0 24 24"
+ height="24"
+ width="24"
+ version="1.2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ id="g4142"
+ transform="matrix(0,-1,-1,0,23.96,24)">
+ <g
+ id="g4210"
+ transform="matrix(-1,0,0,1,59.86,-106.6)">
+ <g
+ id="g4289"
+ transform="matrix(-1,0,0,1,-16.98,0.8136)">
+ <g
+ id="g4291">
+ <path
+ id="path4293"
+ d="m -65.35,116.3 0,3 0.5,0 c 0.54,0 1,0.5 1,1 l 0,2.6 c -1.15,0.5 -2,1.6 -2,3 0,2 1.59,3.5 3.5,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-2.3 -1.81,-4 -4,-4 z m 1,1.2 c 1.39,0.3 2.5,1.3 2.5,2.8 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.5,-1.1 -2.5,-2.5 0,-1.1 0.69,-2 1.66,-2.3 l 0.34,-0.1 0,-3.2 c 0,-0.9 -0.67,-1.5 -1.5,-1.8 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <g
+ style="fill:#969696;fill-opacity:1"
+ id="g4295">
+ <path
+ id="path4297"
+ d="m -67.35,106.1 c -1.94,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,2.2 1.79,4 4,4 l 0.5,0 0,-0.5 0,-2.5 -0.5,0 c -0.55,0 -1,-0.5 -1,-1 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.57,-3.5 -3.5,-3.5 z m 0,1 c 1.37,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,0.9 0.67,1.5 1.5,1.8 l 0,1 c -1.38,-0.3 -2.5,-1.4 -2.5,-2.8 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.12,-2.5 2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ <path
+ id="path4299"
+ d="m -57.35,106.1 c -1.93,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,0.5 -0.45,1 -1,1 l -4.85,0 3.17,3 1.68,0 c 2.21,0 4,-1.8 4,-4 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.56,-3.5 -3.5,-3.5 z m 0,1 c 1.38,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,1.6 -1.35,3 -3,3 l -1.81,0 -2.04,-1 3.85,0 c 1.11,0 2,-0.9 2,-2 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.13,-2.5 2.5,-2.5 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ <path
+ id="path4301"
+ d="m -69.84,116.3 c -2.19,0 -4,1.7 -4,4 l 0,2.6 c -1.14,0.6 -1.99,1.6 -1.99,3 0,2 1.6,3.5 3.51,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-0.5 0.45,-1 1,-1 l 5.01,0 -3.36,-3 z m 0,1 1.84,0 2.19,1 -4.01,0 c -1.11,0 -2,0.9 -2,2 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.51,-1.1 -2.51,-2.5 0,-1.1 0.7,-2 1.66,-2.3 l 0.33,-0.1 0,-0.4 0,-2.8 c 0,-1.7 1.33,-3 3,-3 z"
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
+ </g>
+ </g>
+ </g>
+ <path
+ id="path4165"
+ d="m 12,8.77 c -0.84,0 -1.66,0.341 -2.254,0.937 -0.599,0.593 -0.942,1.403 -0.945,2.253 0,0.85 0.337,1.67 0.933,2.26 a 0.6001,0.6001 0 0 0 0,0 c 0.594,0.6 1.424,0.94 2.264,0.94 0.84,0 1.67,-0.34 2.26,-0.94 0.6,-0.59 0.94,-1.41 0.94,-2.26 0,-0.84 -0.34,-1.66 -0.95,-2.253 C 13.66,9.111 12.84,8.77 12,8.77 Z"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/src/qt/res/src/connect-1.svg b/src/qt/res/src/connect-1.svg
index d3d4e46a41..d17928c97d 100644
--- a/src/qt/res/src/connect-1.svg
+++ b/src/qt/res/src/connect-1.svg
@@ -1,21 +1,69 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<g>
- <path d="M12,11c1.9,0,3.6,0.7,4.9,2c0.4,0.4,0.4,1,0,1.4c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3C14.6,13.5,13.3,13,12,13
- c-1.3,0-2.6,0.5-3.5,1.5c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4C8.4,11.7,10.1,11,12,11 M12,17
- c0.3,0,0.5,0.1,0.7,0.3c0.2,0.2,0.3,0.4,0.3,0.7s-0.1,0.5-0.3,0.7C12.5,18.9,12.3,19,12,19c-0.3,0-0.5-0.1-0.7-0.3
- C11.1,18.5,11,18.3,11,18c0-0.3,0.1-0.5,0.3-0.7C11.5,17.1,11.7,17,12,17 M12,10c-2,0-4.1,0.8-5.7,2.3c-0.8,0.8-0.8,2,0,2.8
- c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6C10,14.4,11,14,12,14c1,0,2,0.4,2.8,1.2c0.4,0.4,0.9,0.6,1.4,0.6s1-0.2,1.4-0.6
- c0.8-0.8,0.8-2,0-2.8C16.1,10.8,14,10,12,10L12,10z M12,16c-0.5,0-1,0.2-1.4,0.6c-0.8,0.8-0.8,2.1,0,2.8C11,19.8,11.5,20,12,20
- c0.5,0,1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8C13,16.2,12.5,16,12,16L12,16z"/>
-</g>
-<g>
- <path d="M12,5c3.5,0,6.7,1.3,9.2,3.8c0.4,0.4,0.4,1,0,1.4c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3C17.7,8.1,14.9,7,12,7
- c-2.9,0-5.7,1.1-7.8,3.2c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4C5.3,6.4,8.5,5,12,5 M12,4
- C8.4,4,4.8,5.4,2.1,8.1c-0.8,0.8-0.8,2,0,2.8c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6C6.9,9,9.4,8,12,8c2.6,0,5.1,1,7.1,2.9
- c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8C19.2,5.4,15.6,4,12,4L12,4z"/>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.2"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ id="g4210"
+ transform="translate(0,0.25)">
+ <g
+ id="g4142"
+ transform="matrix(0,-1,-1,0,23.96,23.75)">
+ <g
+ id="g4213"
+ transform="matrix(-1,0,0,1,59.86,-106.6)">
+ <g
+ id="g4289"
+ transform="matrix(-1,0,0,1,-16.98,0.8136)">
+ <g
+ id="g4291">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -65.35,116.3 0,3 0.5,0 c 0.54,0 1,0.5 1,1 l 0,2.6 c -1.15,0.5 -2,1.6 -2,3 0,2 1.59,3.5 3.5,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-2.3 -1.81,-4 -4,-4 z m 1,1.2 c 1.39,0.3 2.5,1.3 2.5,2.8 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.5,-1.1 -2.5,-2.5 0,-1.1 0.69,-2 1.66,-2.3 l 0.34,-0.1 0,-3.2 c 0,-0.9 -0.67,-1.5 -1.5,-1.8 z"
+ id="path4293" />
+ <g
+ id="g4295">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -67.35,106.1 c -1.94,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,2.2 1.79,4 4,4 l 0.5,0 0,-0.5 0,-2.5 -0.5,0 c -0.55,0 -1,-0.5 -1,-1 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.57,-3.5 -3.5,-3.5 z m 0,1 c 1.37,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,0.9 0.67,1.5 1.5,1.8 l 0,1 c -1.38,-0.3 -2.5,-1.4 -2.5,-2.8 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.12,-2.5 2.5,-2.5 z"
+ id="path4297" />
+ <path
+ id="path4145"
+ d="m -57.35,106 c -1.99,0 -3.6,1.7 -3.6,3.6 0,1.4 0.83,2.6 2,3.2 l 0,2.5 c 0,0.5 -0.41,0.9 -0.9,0.9 l -4.35,0 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 l 4.35,0 c 2.26,0 4.1,-1.9 4.1,-4.1 l 0,-2.5 c 1.17,-0.6 2,-1.8 2,-3.2 0,-1.9 -1.6,-3.6 -3.6,-3.6 z"
+ style="" />
+ </g>
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -69.84,116.3 c -2.19,0 -4,1.7 -4,4 l 0,2.6 c -1.14,0.6 -1.99,1.6 -1.99,3 0,2 1.6,3.5 3.51,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-0.5 0.45,-1 1,-1 l 5.01,0 -3.34,-3 z m 0,1 2.02,0 2.01,1 -4.01,0 c -1.11,0 -2,0.9 -2,2 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.51,-1.1 -2.51,-2.5 0,-1.1 0.7,-2 1.66,-2.3 l 0.33,-0.1 0,-0.4 0,-2.8 c 0,-1.7 1.33,-3 3,-3 z"
+ id="path4301" />
+ </g>
+ </g>
+ </g>
+ <path
+ id="path4173"
+ d="m 12,8.764 c -0.84,0 -1.67,0.336 -2.264,0.931 a 0.6001,0.6001 0 0 0 -0,0 C 9.138,10.29 8.802,11.11 8.801,11.96 c 0,0.85 0.337,1.67 0.933,2.26 a 0.6001,0.6001 0 0 0 0,0 c 0.594,0.6 1.424,0.94 2.264,0.94 0.84,0 1.67,-0.34 2.26,-0.94 0.6,-0.59 0.94,-1.41 0.94,-2.26 0,-0.84 -0.34,-1.67 -0.94,-2.265 C 13.67,9.1 12.84,8.764 12,8.764 Z"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+ </g>
+</svg>
diff --git a/src/qt/res/src/connect-2.svg b/src/qt/res/src/connect-2.svg
index d5becc52b7..841ca6071d 100644
--- a/src/qt/res/src/connect-2.svg
+++ b/src/qt/res/src/connect-2.svg
@@ -1,22 +1,59 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<path d="M13.4,19.4c0.8-0.8,0.8-2,0-2.8c-0.8-0.8-2-0.8-2.8,0c-0.8,0.8-0.8,2.1,0,2.8C11.4,20.2,12.6,20.2,13.4,19.4z"/>
-<g>
- <path d="M12,11c1.9,0,3.6,0.7,4.9,2c0.4,0.4,0.4,1,0,1.4c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3C14.6,13.5,13.3,13,12,13
- c-1.3,0-2.6,0.5-3.5,1.5c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4C8.4,11.7,10.1,11,12,11 M12,17
- c0.3,0,0.5,0.1,0.7,0.3c0.2,0.2,0.3,0.4,0.3,0.7s-0.1,0.5-0.3,0.7C12.5,18.9,12.3,19,12,19c-0.3,0-0.5-0.1-0.7-0.3
- C11.1,18.5,11,18.3,11,18c0-0.3,0.1-0.5,0.3-0.7C11.5,17.1,11.7,17,12,17 M12,10c-2,0-4.1,0.8-5.7,2.3c-0.8,0.8-0.8,2,0,2.8
- c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6C10,14.4,11,14,12,14c1,0,2,0.4,2.8,1.2c0.4,0.4,0.9,0.6,1.4,0.6s1-0.2,1.4-0.6
- c0.8-0.8,0.8-2,0-2.8C16.1,10.8,14,10,12,10L12,10z M12,16c-0.5,0-1,0.2-1.4,0.6c-0.8,0.8-0.8,2.1,0,2.8C11,19.8,11.5,20,12,20
- c0.5,0,1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8C13,16.2,12.5,16,12,16L12,16z"/>
-</g>
-<g>
- <path d="M12,5c3.5,0,6.7,1.3,9.2,3.8c0.4,0.4,0.4,1,0,1.4c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3C17.7,8.1,14.9,7,12,7
- c-2.9,0-5.7,1.1-7.8,3.2c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4C5.3,6.4,8.5,5,12,5 M12,4
- C8.4,4,4.8,5.4,2.1,8.1c-0.8,0.8-0.8,2,0,2.8c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6C6.9,9,9.4,8,12,8c2.6,0,5.1,1,7.1,2.9
- c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8C19.2,5.4,15.6,4,12,4L12,4z"/>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.2"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ id="g4210"
+ transform="matrix(0,1,-1,0,130.6,-35.86)">
+ <g
+ id="g4289"
+ transform="matrix(-1,0,0,1,-16.98,0.8136)">
+ <g
+ id="g4291">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -65.35,116.3 0,3 0.5,0 c 0.54,0 1,0.5 1,1 l 0,2.6 c -1.15,0.5 -2,1.6 -2,3 0,2 1.59,3.5 3.5,3.5 1.91,0 3.5,-1.5 3.5,-3.5 0,-1.4 -0.85,-2.5 -2,-3 l 0,-2.6 c 0,-2.3 -1.81,-4 -4,-4 z m 1,1.2 c 1.39,0.3 2.5,1.3 2.5,2.8 l 0,3.2 0.34,0.1 c 0.96,0.3 1.66,1.2 1.66,2.3 0,1.4 -1.11,2.5 -2.5,2.5 -1.39,0 -2.5,-1.1 -2.5,-2.5 0,-1.1 0.69,-2 1.66,-2.3 l 0.34,-0.1 0,-3.2 c 0,-0.9 -0.67,-1.5 -1.5,-1.8 z"
+ id="path4293" />
+ <g
+ id="g4295">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -67.35,106.1 c -1.94,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,2.2 1.79,4 4,4 l 0.5,0 0,-0.5 0,-2.5 -0.5,0 c -0.55,0 -1,-0.5 -1,-1 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.57,-3.5 -3.5,-3.5 z m 0,1 c 1.37,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,0.9 0.67,1.5 1.5,1.8 l 0,1 c -1.38,-0.3 -2.5,-1.4 -2.5,-2.8 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.12,-2.5 2.5,-2.5 z"
+ id="path4297" />
+ <path
+ id="path4142"
+ d="m -57.35,106 c -1.99,0 -3.6,1.7 -3.6,3.6 0,1.4 0.83,2.6 2,3.2 l 0,2.5 c 0,0.5 -0.41,0.9 -0.9,0.9 l -4.35,0 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 l 4.35,0 c 2.26,0 4.1,-1.9 4.1,-4.1 l 0,-2.5 c 1.17,-0.6 2,-1.8 2,-3.2 0,-1.9 -1.6,-3.6 -3.6,-3.6 z" />
+ </g>
+ <path
+ id="path4148"
+ d="m -69.84,116.2 c -2.24,0 -4.1,1.8 -4.1,4.1 l 0,2.5 c -1.17,0.5 -1.99,1.7 -1.99,3.1 0,2 1.64,3.6 3.61,3.6 1.96,0 3.6,-1.6 3.6,-3.6 0,-1.4 -0.83,-2.6 -2,-3.2 l 0,-2.4 c 0,-0.5 0.41,-0.9 0.9,-0.9 l 4.51,0 a 0.6001,0.6001 0 0 0 0.6,-0.6 l 0,-2 a 0.6001,0.6001 0 0 0 -0.6,-0.6 l -4.53,0 z" />
+ </g>
+ </g>
+ <path
+ id="path4170"
+ d="m 47.86,115.4 c -0.84,0 -1.65,0.4 -2.24,1 -0.64,0.5 -0.96,1.3 -0.96,2.2 0,0.9 0.32,1.7 0.96,2.2 0.59,0.6 1.4,1 2.24,1 0.84,0 1.65,-0.4 2.24,-1 0.64,-0.5 0.96,-1.3 0.96,-2.2 0,-0.9 -0.32,-1.7 -0.96,-2.2 -0.59,-0.6 -1.4,-1 -2.24,-1 z"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+ </g>
+</svg>
diff --git a/src/qt/res/src/connect-3.svg b/src/qt/res/src/connect-3.svg
index 9bfa04721f..b06e67daf8 100644
--- a/src/qt/res/src/connect-3.svg
+++ b/src/qt/res/src/connect-3.svg
@@ -1,16 +1,72 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve">
-<path d="M13.4,19.4c0.8-0.8,0.8-2,0-2.8c-0.8-0.8-2-0.8-2.8,0c-0.8,0.8-0.8,2.1,0,2.8C11.4,20.2,12.6,20.2,13.4,19.4z"/>
-<path d="M13.4,19.4c0.8-0.8,0.8-2,0-2.8c-0.8-0.8-2-0.8-2.8,0c-0.8,0.8-0.8,2.1,0,2.8C11.4,20.2,12.6,20.2,13.4,19.4z M7.8,15.8
- c-0.5,0-1-0.2-1.4-0.6c-0.8-0.8-0.8-2,0-2.8c3.1-3.1,8.2-3.1,11.3,0c0.8,0.8,0.8,2,0,2.8c-0.8,0.8-2,0.8-2.8,0
- c-1.6-1.6-4.1-1.6-5.7,0C8.8,15.6,8.3,15.8,7.8,15.8z"/>
-<g>
- <path d="M12,5c3.5,0,6.7,1.3,9.2,3.8c0.4,0.4,0.4,1,0,1.4c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3C17.7,8.1,14.9,7,12,7
- c-2.9,0-5.7,1.1-7.8,3.2c-0.2,0.2-0.4,0.3-0.7,0.3c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4C5.3,6.4,8.5,5,12,5 M12,4
- C8.4,4,4.8,5.4,2.1,8.1c-0.8,0.8-0.8,2,0,2.8c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6C6.9,9,9.4,8,12,8c2.6,0,5.1,1,7.1,2.9
- c0.4,0.4,0.9,0.6,1.4,0.6c0.5,0,1-0.2,1.4-0.6c0.8-0.8,0.8-2,0-2.8C19.2,5.4,15.6,4,12,4L12,4z"/>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg2"
+ viewBox="0 0 24 24"
+ height="24"
+ width="24"
+ version="1.2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ transform="translate(0.2636,0.29)"
+ id="g4160">
+ <g
+ id="g4210"
+ transform="matrix(0,1,-1,0,130.3,-36.15)">
+ <g
+ id="g4289"
+ transform="matrix(-1,0,0,1,-16.98,0.8136)">
+ <g
+ id="g4291">
+ <path
+ id="path4147"
+ d="m -64.85,116.2 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 c 0.48,0 0.9,0.4 0.9,0.9 l 0,2.4 c -1.18,0.6 -2,1.8 -2,3.2 0,2 1.64,3.6 3.6,3.6 1.97,0 3.6,-1.6 3.6,-3.6 0,-1.4 -0.83,-2.6 -2,-3.2 l 0,-2.4 c 0,-2.3 -1.86,-4.1 -4.1,-4.1 z"
+ style="" />
+ <g
+ id="g4295">
+ <path
+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
+ d="m -67.35,106.1 c -1.94,0 -3.5,1.6 -3.5,3.5 0,1.4 0.85,2.5 2,3 l 0,2.7 c 0,2.2 1.79,4 4,4 l 0.5,0 0,-0.5 0,-2.5 -0.5,0 c -0.55,0 -1,-0.5 -1,-1 l 0,-2.7 c 1.15,-0.5 2,-1.6 2,-3 0,-1.9 -1.57,-3.5 -3.5,-3.5 z m 0,1 c 1.37,0 2.5,1.2 2.5,2.5 0,1.1 -0.7,2 -1.66,2.3 l -0.34,0.1 0,3.3 c 0,0.9 0.67,1.5 1.5,1.8 l 0,1 c -1.38,-0.3 -2.5,-1.4 -2.5,-2.8 l 0,-3.3 -0.34,-0.1 c -0.96,-0.3 -1.66,-1.2 -1.66,-2.3 0,-1.3 1.12,-2.5 2.5,-2.5 z"
+ id="path4297" />
+ <path
+ id="path4145"
+ d="m -57.35,106 c -1.99,0 -3.6,1.7 -3.6,3.6 0,1.4 0.83,2.6 2,3.2 l 0,2.5 c 0,0.5 -0.41,0.9 -0.9,0.9 l -4.35,0 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 l 4.35,0 c 2.26,0 4.1,-1.9 4.1,-4.1 l 0,-2.5 c 1.17,-0.6 2,-1.8 2,-3.2 0,-1.9 -1.6,-3.6 -3.6,-3.6 z"
+ style="" />
+ </g>
+ <path
+ id="path4149"
+ d="m -69.84,116.2 c -2.24,0 -4.1,1.8 -4.1,4.1 l 0,2.5 c -1.17,0.5 -1.99,1.7 -1.99,3.1 0,2 1.64,3.6 3.61,3.6 1.96,0 3.6,-1.6 3.6,-3.6 0,-1.4 -0.83,-2.6 -2,-3.2 l 0,-2.4 c 0,-0.5 0.41,-0.9 0.9,-0.9 l 4.51,0 a 0.6001,0.6001 0 0 0 0.6,-0.6 l 0,-2 a 0.6001,0.6001 0 0 0 -0.6,-0.6 l -4.53,0 z"
+ style="" />
+ </g>
+ </g>
+ </g>
+ <g
+ transform="matrix(0,1,1,0,-106.3,-36.15)"
+ id="g4142">
+ <g
+ transform="matrix(-1,0,0,1,-16.98,0.8136)"
+ id="g4144" />
+ </g>
+ </g>
+ <path
+ id="path4170"
+ d="m 15.2,12 c 0,-0.84 -0.4,-1.65 -1,-2.242 -0.5,-0.64 -1.3,-0.96 -2.2,-0.96 -0.9,0 -1.7,0.32 -2.2,0.96 -0.6,0.592 -1,1.402 -1,2.242 0,0.84 0.4,1.65 1,2.24 0.5,0.64 1.3,0.96 2.2,0.96 0.9,0 1.7,-0.32 2.2,-0.96 0.6,-0.59 1,-1.4 1,-2.24 z"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+</svg>
diff --git a/src/qt/res/src/connect-4.svg b/src/qt/res/src/connect-4.svg
new file mode 100644
index 0000000000..0abc7955fd
--- /dev/null
+++ b/src/qt/res/src/connect-4.svg
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.2"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ id="svg2">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <g
+ id="g4142"
+ transform="matrix(0,-1,-1,0,23.96,24)">
+ <g
+ transform="matrix(-1,0,0,1,59.86,-106.6)"
+ id="g4210">
+ <g
+ transform="matrix(-1,0,0,1,-16.98,0.8136)"
+ id="g4289">
+ <g
+ id="g4291">
+ <path
+ id="path4153"
+ d="m -64.85,116.2 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 c 0.48,0 0.9,0.4 0.9,0.9 l 0,2.4 c -1.18,0.6 -2,1.8 -2,3.2 0,2 1.64,3.6 3.6,3.6 1.97,0 3.6,-1.6 3.6,-3.6 0,-1.4 -0.83,-2.6 -2,-3.2 l 0,-2.4 c 0,-2.3 -1.86,-4.1 -4.1,-4.1 z"
+ style="" />
+ <g
+ id="g4295">
+ <path
+ id="path4149"
+ d="m -67.35,106 c -2,0 -3.6,1.7 -3.6,3.6 0,1.4 0.83,2.6 2,3.2 l 0,2.5 c 0,2.2 1.84,4.1 4.1,4.1 a 0.6001,0.6001 0 0 0 0.6,-0.6 l 0,-2 a 0.6001,0.6001 0 0 0 -0.6,-0.6 c -0.49,0 -0.9,-0.4 -0.9,-0.9 l 0,-2.5 c 1.17,-0.6 2,-1.8 2,-3.2 0,-1.9 -1.61,-3.6 -3.6,-3.6 z"
+ style="" />
+ <path
+ id="path4147"
+ d="m -57.35,106 c -1.99,0 -3.6,1.7 -3.6,3.6 0,1.4 0.83,2.6 2,3.2 l 0,2.5 c 0,0.5 -0.41,0.9 -0.9,0.9 l -4.35,0 a 0.6001,0.6001 0 0 0 -0.6,0.6 l 0,2 a 0.6001,0.6001 0 0 0 0.6,0.6 l 4.35,0 c 2.26,0 4.1,-1.9 4.1,-4.1 l 0,-2.5 c 1.17,-0.6 2,-1.8 2,-3.2 0,-1.9 -1.6,-3.6 -3.6,-3.6 z"
+ style="" />
+ </g>
+ <path
+ id="path4155"
+ d="m -69.84,116.2 c -2.24,0 -4.1,1.8 -4.1,4.1 l 0,2.5 c -1.17,0.5 -1.99,1.7 -1.99,3.1 0,2 1.64,3.6 3.61,3.6 1.96,0 3.6,-1.6 3.6,-3.6 0,-1.4 -0.83,-2.6 -2,-3.2 l 0,-2.4 c 0,-0.5 0.41,-0.9 0.9,-0.9 l 4.51,0 a 0.6001,0.6001 0 0 0 0.6,-0.6 l 0,-2 a 0.6001,0.6001 0 0 0 -0.6,-0.6 l -4.53,0 z"
+ style="" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <path
+ id="path4170"
+ d="m 15.2,12 c 0,-0.84 -0.4,-1.65 -1,-2.24 C 13.7,9.12 12.9,8.8 12,8.8 c -0.9,0 -1.7,0.32 -2.2,0.96 -0.6,0.59 -1,1.4 -1,2.24 0,0.84 0.4,1.65 1,2.24 0.5,0.64 1.3,0.96 2.2,0.96 0.9,0 1.7,-0.32 2.2,-0.96 0.6,-0.59 1,-1.4 1,-2.24 z"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+</svg>
diff --git a/src/qt/res/src/qt.svg b/src/qt/res/src/qt.svg
index 9ef54f493c..373c91f0c6 100644
--- a/src/qt/res/src/qt.svg
+++ b/src/qt/res/src/qt.svg
@@ -1,25 +1,26 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 841.9 595.3" enable-background="new 0 0 841.9 595.3" xml:space="preserve">
-<g>
- <path d="M182.8,310c0-74.4,0-148.8,0-220.7c0-19.8,5-39.7,19.8-54.6c12.4-12.4,27.3-17.4,44.6-19.8c37.2-5,74.4,2.5,109.1,7.4
- C428.4,34.7,497.8,44.6,569.8,57c27.3,5,57,9.9,84.3,12.4c7.4,0,5,5,5,9.9c0,91.8,0,181.1,0,272.8c0,32.2,0,64.5,0,99.2
- c0,14.9-5,29.8-12.4,44.6c-9.9,14.9-22.3,22.3-39.7,27.3c-69.4,12.4-138.9,22.3-208.3,34.7c-57,9.9-114.1,19.8-171.1,29.8
- c-2.5,0-5,0-7.4-2.5c-12.4-14.9-22.3-24.8-32.2-34.7c-2.5-2.5-2.5-7.4-2.5-9.9c0-71.9,0-143.9,0-215.8
- C182.8,320,182.8,315,182.8,310z M430.9,436.5c9.9-7.4,19.8-12.4,29.8-19.8c14.9-14.9,24.8-32.2,29.8-54.6
- c12.4-54.6,14.9-111.6,0-166.2c-12.4-47.1-42.2-74.4-84.3-79.4c-37.2-2.5-67,7.4-86.8,39.7c-7.4,14.9-12.4,29.8-14.9,44.6
- c-9.9,39.7-9.9,81.9-5,121.5c2.5,22.3,7.4,44.6,17.4,67c12.4,24.8,29.8,42.2,54.6,49.6c2.5,0,5,2.5,5,5c5,12.4,7.4,22.3,12.4,34.7
- s17.4,19.8,32.2,22.3c14.9,2.5,27.3,2.5,42.2,0c2.5,0,2.5-2.5,2.5-2.5c0-9.9,0-22.3,0-32.2C438.3,461.3,433.3,456.4,430.9,436.5z
- M505.3,191c0,12.4,0,22.3,0,34.7c0,2.5,2.5,2.5,5,2.5c5,0,7.4,0,12.4,0c0,2.5,0,5,0,9.9c0,44.6,0,86.8,0,131.5
- c0,7.4,0,17.4,2.5,24.8c2.5,12.4,12.4,22.3,24.8,24.8c19.8,5,37.2-2.5,54.6-9.9l2.5-2.5c0-9.9,0-19.8,0-29.8
- c-7.4,2.5-14.9,5-22.3,5s-12.4-2.5-14.9-9.9c0-5-2.5-9.9-2.5-14.9c0-39.7,0-79.4,0-119.1c0-2.5,0-5,0-7.4c9.9,0,19.8,0,29.8,2.5
- c5,0,7.4-2.5,7.4-7.4c0-7.4,0-14.9,0-22.3c0-5-2.5-7.4-7.4-7.4c-7.4,0-14.9-2.5-22.3-2.5c-5,0-7.4-2.5-7.4-7.4
- c0-14.9,0-29.8,0-42.2c0-5-2.5-5-5-7.4c-5,0-12.4,0-17.4-2.5s-7.4,0-9.9,7.4c-2.5,17.4-7.4,32.2-12.4,49.6
- C520.2,191,512.7,191,505.3,191z"/>
- <path d="M443.3,277.8c-2.5,27.3-5,57-9.9,84.3c0,7.4-5,17.4-9.9,24.8c-12.4,17.4-32.2,14.9-44.6-2.5c-9.9-14.9-12.4-32.2-14.9-49.6
- c-5-42.2-5-81.9,0-124c5-12.4,7.4-24.8,14.9-37.2c12.4-17.4,34.7-17.4,47.1-2.5c2.5,5,7.4,9.9,7.4,14.9c2.5,9.9,5,19.8,7.4,32.2
- c2.5,9.9,2.5,22.3,2.5,34.7C440.8,260.4,440.8,270.4,443.3,277.8L443.3,277.8z"/>
-</g>
-</svg>
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ id="Ebene_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 609.4 609.4"
+ enable-background="new 0 0 841.9 595.3"
+ xml:space="preserve"
+ width="609.4"
+ height="609.4"><metadata
+ id="metadata13"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs11" /><g
+ id="g4151"
+ transform="matrix(2.553,0,0,2.553,-2149,281.5)"><path
+ id="path26"
+ transform="matrix(0.3917,0,0,0.3917,841.8,-110.3)"
+ d="M 153.7 16.9 C 115 16.44 69.7 31.67 67.96 86.81 L 67.96 550.7 L 105 592.4 L 495.9 526.7 C 521.4 522.1 541.9 490.2 541.9 455.9 L 541.9 77.77 L 183.4 18.97 C 179.4 18.3 161.4 17 157.5 16.99 C 156.2 16.94 155 16.91 153.7 16.9 z M 273.5 124.1 C 278.1 124.1 282.7 124.3 287.3 124.9 L 287.3 125 C 320 128.8 343.7 144.2 359.3 170.9 C 374.6 197.1 382 234.6 382 284 C 382 329.2 376.4 364.7 365.4 390.7 C 354.2 417.2 337.1 434.6 313.4 442.8 C 315.9 455 319.5 463.2 324.1 467.5 C 326.9 469.8 330.7 471.4 335.3 471.9 L 335.6 471.9 L 336.3 471.9 L 341.5 471.9 C 343.5 471.9 344.5 472.4 348.3 471.9 L 348.3 507.9 L 332 510.2 C 327.2 510.7 322.6 510.9 318.2 510.9 C 303.9 510.9 292.4 507.6 283.5 500.5 C 272 491.3 263.6 473.4 258.2 447.1 C 233.2 441.8 213.5 425.9 200 399.1 C 186.5 372.1 179.3 332.2 179.3 280.4 C 179.3 224.5 189 183.2 207.7 157 C 223.8 134.9 245.7 124.1 273.5 124.1 z M 424.4 143.5 L 455.1 146.9 L 455.1 202.2 L 488.2 204.8 L 488.2 239.5 L 455.1 237.8 L 455.1 364.7 C 455.1 375.6 457.6 382.8 460.2 386.1 C 460.2 388.9 465.3 390.4 467.8 390.4 L 470.4 390.4 C 478 389.9 485.7 387.9 493.4 384.1 L 493.4 415.7 C 478 422.1 465.3 425.7 450 426.9 C 450 427.2 447.4 427.2 444.8 427.2 C 432.1 427.2 424.4 423.6 416.8 416.5 C 409.1 408.1 404 394.5 404 376.1 L 404 235.6 L 390.2 234.8 L 390.2 197.6 L 411.7 199.1 L 424.4 143.5 z M 284.5 166.4 C 272.5 166.4 263.3 173.3 256.9 187.3 C 250.1 202.5 246.7 233.9 246.7 281.7 C 246.7 327.6 250.1 360.3 256.9 379.5 C 263.3 397.8 273 406.8 285.8 406.8 L 287.3 406.8 C 300.1 406 309.5 397.1 316.2 380.5 C 322.6 363.9 325.6 331.5 325.6 283 C 325.6 239.4 322.6 209.5 316.2 193 C 309.8 176.4 300.1 167.5 287.3 166.4 L 284.5 166.4 z "
+ style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></svg> \ No newline at end of file
diff --git a/src/qt/res/spinner.png b/src/qt/res/src/spinner.png
index b296a58481..b296a58481 100644
--- a/src/qt/res/spinner.png
+++ b/src/qt/res/src/spinner.png
Binary files differ
diff --git a/src/qt/res/src/transaction0.svg b/src/qt/res/src/transaction0.svg
new file mode 100644
index 0000000000..e7fcd8214c
--- /dev/null
+++ b/src/qt/res/src/transaction0.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ id="svg4142"
+ viewBox="0 0 128 127.9"
+ height="36.12mm"
+ width="36.12mm">
+ <defs
+ id="defs4144" />
+ <metadata
+ id="metadata4147">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ transform="translate(-284.4,-501.6)">
+ <path
+ id="path4792"
+ d="m 348.8,513.8 c -12.7,-0.7 -24.9,9.1 -27,21.7 -3.8,8.8 7.2,13.7 13.7,9.2 3.1,-7.5 9.4,-17.9 18.9,-11.6 9.7,6.1 2.1,17.6 -3,24.1 -6.1,7.8 -11.4,14.8 -8.9,23 5.4,17.7 10.8,3.7 12.8,-0.1 4.3,-8.2 6,-8.8 11.5,-16.1 6.4,-8.6 11.6,-19.9 7.7,-30.8 -2.8,-11.5 -13.9,-19.9 -25.7,-19.4 z m -0.7,84.7 c -11.4,2.4 -9.1,19.5 2.7,17.1 11.8,-2.4 8.7,-19.5 -2.7,-17.1 z"
+ style="fill:#000000" />
+ </g>
+</svg>
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index 29c971ec79..9603a26c6e 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -5,29 +5,32 @@
#include "rpcconsole.h"
#include "ui_rpcconsole.h"
+#include "bantablemodel.h"
#include "clientmodel.h"
#include "guiutil.h"
-#include "peertablemodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
+#include "bantablemodel.h"
-#include "main.h"
#include "chainparams.h"
#include "rpcserver.h"
#include "rpcclient.h"
#include "util.h"
-#include "json/json_spirit_value.h"
-
#include <openssl/crypto.h>
+#include "univalue/univalue.h"
+
#ifdef ENABLE_WALLET
#include <db_cxx.h>
#endif
#include <QKeyEvent>
+#include <QMenu>
#include <QScrollBar>
+#include <QSignalMapper>
#include <QThread>
#include <QTime>
+#include <QTimer>
#if QT_VERSION < 0x050000
#include <QUrl>
@@ -59,13 +62,47 @@ class RPCExecutor : public QObject
{
Q_OBJECT
-public slots:
+public Q_SLOTS:
void request(const QString &command);
-signals:
+Q_SIGNALS:
void reply(int category, const QString &command);
};
+/** Class for handling RPC timers
+ * (used for e.g. re-locking the wallet after a timeout)
+ */
+class QtRPCTimerBase: public QObject, public RPCTimerBase
+{
+ Q_OBJECT
+public:
+ QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis):
+ func(func)
+ {
+ timer.setSingleShot(true);
+ connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
+ timer.start(millis);
+ }
+ ~QtRPCTimerBase() {}
+private Q_SLOTS:
+ void timeout() { func(); }
+private:
+ QTimer timer;
+ boost::function<void(void)> func;
+};
+
+class QtRPCTimerInterface: public RPCTimerInterface
+{
+public:
+ ~QtRPCTimerInterface() {}
+ const char *Name() { return "Qt"; }
+ RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
+ {
+ return new QtRPCTimerBase(func, millis);
+ }
+};
+
+
#include "rpcconsole.moc"
/**
@@ -94,7 +131,7 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm
STATE_ESCAPE_DOUBLEQUOTED
} state = STATE_EATING_SPACES;
std::string curarg;
- foreach(char ch, strCommand)
+ Q_FOREACH(char ch, strCommand)
{
switch(state)
{
@@ -157,7 +194,7 @@ void RPCExecutor::request(const QString &command)
std::vector<std::string> args;
if(!parseCommandLine(args, command.toStdString()))
{
- emit reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
return;
}
if(args.empty())
@@ -167,53 +204,56 @@ void RPCExecutor::request(const QString &command)
std::string strPrint;
// Convert argument list to JSON objects in method-dependent way,
// and pass it along with the method name to the dispatcher.
- json_spirit::Value result = tableRPC.execute(
+ UniValue result = tableRPC.execute(
args[0],
RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
// Format result reply
- if (result.type() == json_spirit::null_type)
+ if (result.isNull())
strPrint = "";
- else if (result.type() == json_spirit::str_type)
+ else if (result.isStr())
strPrint = result.get_str();
else
- strPrint = write_string(result, true);
+ strPrint = result.write(2);
- emit reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
+ Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
}
- catch (const json_spirit::Object& objError)
+ catch (UniValue& objError)
{
try // Nice formatting for standard-format error
{
int code = find_value(objError, "code").get_int();
std::string message = find_value(objError, "message").get_str();
- emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")");
}
catch (const std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message
{ // Show raw JSON object
- emit reply(RPCConsole::CMD_ERROR, QString::fromStdString(write_string(json_spirit::Value(objError), false)));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString::fromStdString(objError.write()));
}
}
catch (const std::exception& e)
{
- emit reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
+ Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what()));
}
}
-RPCConsole::RPCConsole(QWidget *parent) :
+RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent),
ui(new Ui::RPCConsole),
clientModel(0),
historyPtr(0),
- cachedNodeid(-1)
+ cachedNodeid(-1),
+ platformStyle(platformStyle),
+ peersTableContextMenu(0),
+ banTableContextMenu(0)
{
ui->setupUi(this);
GUIUtil::restoreWindowGeometry("nRPCConsoleWindow", this->size(), this);
-#ifndef Q_OS_MAC
- ui->openDebugLogfileButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
+ if (platformStyle->getImagesOnButtons()) {
+ ui->openDebugLogfileButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
// Install event filter for up and down arrow
ui->lineEdit->installEventFilter(this);
@@ -230,6 +270,9 @@ RPCConsole::RPCConsole(QWidget *parent) :
ui->label_berkeleyDBVersion->hide();
ui->berkeleyDBVersion->hide();
#endif
+ // Register RPC timer interface
+ rpcTimerInterface = new QtRPCTimerInterface();
+ RPCRegisterTimerInterface(rpcTimerInterface);
startExecutor();
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
@@ -243,7 +286,9 @@ RPCConsole::RPCConsole(QWidget *parent) :
RPCConsole::~RPCConsole()
{
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
- emit stopExecutor();
+ Q_EMIT stopExecutor();
+ RPCUnregisterTimerInterface(rpcTimerInterface);
+ delete rpcTimerInterface;
delete ui;
}
@@ -287,8 +332,7 @@ void RPCConsole::setClientModel(ClientModel *model)
{
clientModel = model;
ui->trafficGraph->setClientModel(model);
- if(model)
- {
+ if (model && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) {
// Keep up to date with client
setNumConnections(model->getNumConnections());
connect(model, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int)));
@@ -305,21 +349,85 @@ void RPCConsole::setClientModel(ClientModel *model)
ui->peerWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->peerWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->peerWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->peerWidget->setContextMenuPolicy(Qt::CustomContextMenu);
ui->peerWidget->setColumnWidth(PeerTableModel::Address, ADDRESS_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Subversion, SUBVERSION_COLUMN_WIDTH);
ui->peerWidget->setColumnWidth(PeerTableModel::Ping, PING_COLUMN_WIDTH);
-
- // connect the peerWidget selection model to our peerSelected() handler
+ ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
+
+ // create peer table context menu actions
+ QAction* disconnectAction = new QAction(tr("&Disconnect Node"), this);
+ QAction* banAction1h = new QAction(tr("Ban Node for") + " " + tr("1 &hour"), this);
+ QAction* banAction24h = new QAction(tr("Ban Node for") + " " + tr("1 &day"), this);
+ QAction* banAction7d = new QAction(tr("Ban Node for") + " " + tr("1 &week"), this);
+ QAction* banAction365d = new QAction(tr("Ban Node for") + " " + tr("1 &year"), this);
+
+ // create peer table context menu
+ peersTableContextMenu = new QMenu();
+ peersTableContextMenu->addAction(disconnectAction);
+ peersTableContextMenu->addAction(banAction1h);
+ peersTableContextMenu->addAction(banAction24h);
+ peersTableContextMenu->addAction(banAction7d);
+ peersTableContextMenu->addAction(banAction365d);
+
+ // Add a signal mapping to allow dynamic context menu arguments.
+ // We need to use int (instead of int64_t), because signal mapper only supports
+ // int or objects, which is okay because max bantime (1 year) is < int_max.
+ QSignalMapper* signalMapper = new QSignalMapper(this);
+ signalMapper->setMapping(banAction1h, 60*60);
+ signalMapper->setMapping(banAction24h, 60*60*24);
+ signalMapper->setMapping(banAction7d, 60*60*24*7);
+ signalMapper->setMapping(banAction365d, 60*60*24*365);
+ connect(banAction1h, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction24h, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction7d, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(banAction365d, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(banSelectedNode(int)));
+
+ // peer table context menu signals
+ connect(ui->peerWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showPeersTableContextMenu(const QPoint&)));
+ connect(disconnectAction, SIGNAL(triggered()), this, SLOT(disconnectSelectedNode()));
+
+ // peer table signal handling - update peer details when selecting new node
connect(ui->peerWidget->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
- this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
+ this, SLOT(peerSelected(const QItemSelection &, const QItemSelection &)));
+ // peer table signal handling - update peer details when new nodes are added to the model
connect(model->getPeerTableModel(), SIGNAL(layoutChanged()), this, SLOT(peerLayoutChanged()));
+ // set up ban table
+ ui->banlistWidget->setModel(model->getBanTableModel());
+ ui->banlistWidget->verticalHeader()->hide();
+ ui->banlistWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ ui->banlistWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
+ ui->banlistWidget->setSelectionMode(QAbstractItemView::SingleSelection);
+ ui->banlistWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+ ui->banlistWidget->setColumnWidth(BanTableModel::Address, BANSUBNET_COLUMN_WIDTH);
+ ui->banlistWidget->setColumnWidth(BanTableModel::Bantime, BANTIME_COLUMN_WIDTH);
+ ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
+
+ // create ban table context menu action
+ QAction* unbanAction = new QAction(tr("&Unban Node"), this);
+
+ // create ban table context menu
+ banTableContextMenu = new QMenu();
+ banTableContextMenu->addAction(unbanAction);
+
+ // ban table context menu signals
+ connect(ui->banlistWidget, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showBanTableContextMenu(const QPoint&)));
+ connect(unbanAction, SIGNAL(triggered()), this, SLOT(unbanSelectedNode()));
+
+ // ban table signal handling - clear peer details when clicking a peer in the ban table
+ connect(ui->banlistWidget, SIGNAL(clicked(const QModelIndex&)), this, SLOT(clearSelectedNode()));
+ // ban table signal handling - ensure ban table is shown or hidden (if empty)
+ connect(model->getBanTableModel(), SIGNAL(layoutChanged()), this, SLOT(showOrHideBanTableIfRequired()));
+ showOrHideBanTableIfRequired();
+
// Provide initial values
ui->clientVersion->setText(model->formatFullVersion());
+ ui->clientUserAgent->setText(model->formatSubVersion());
ui->clientName->setText(model->clientName());
ui->buildDate->setText(model->formatBuildDate());
ui->startupTime->setText(model->formatClientStartupTime());
-
ui->networkName->setText(QString::fromStdString(Params().NetworkIDString()));
}
}
@@ -350,7 +458,7 @@ void RPCConsole::clear()
ui->messagesWidget->document()->addResource(
QTextDocument::ImageResource,
QUrl(ICON_MAPPING[i].url),
- SingleColorImage(ICON_MAPPING[i].source, SingleColor()).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
+ platformStyle->SingleColorImage(ICON_MAPPING[i].source).scaled(ICON_SIZE, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
}
// Set default style sheet
@@ -417,7 +525,7 @@ void RPCConsole::on_lineEdit_returnPressed()
if(!cmd.isEmpty())
{
message(CMD_REQUEST, cmd);
- emit cmdRequest(cmd);
+ Q_EMIT cmdRequest(cmd);
// Remove command, if already in history
history.removeOne(cmd);
// Append command to history
@@ -471,10 +579,10 @@ void RPCConsole::startExecutor()
void RPCConsole::on_tabWidget_currentChanged(int index)
{
- if(ui->tabWidget->widget(index) == ui->tab_console)
- {
+ if (ui->tabWidget->widget(index) == ui->tab_console)
ui->lineEdit->setFocus();
- }
+ else if (ui->tabWidget->widget(index) != ui->tab_peers)
+ clearSelectedNode();
}
void RPCConsole::on_openDebugLogfileButton_clicked()
@@ -523,7 +631,7 @@ void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelecti
{
Q_UNUSED(deselected);
- if (!clientModel || selected.indexes().isEmpty())
+ if (!clientModel || !clientModel->getPeerTableModel() || selected.indexes().isEmpty())
return;
const CNodeCombinedStats *stats = clientModel->getPeerTableModel()->getNodeStats(selected.indexes().first().row());
@@ -533,7 +641,7 @@ void RPCConsole::peerSelected(const QItemSelection &selected, const QItemSelecti
void RPCConsole::peerLayoutChanged()
{
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
const CNodeCombinedStats *stats = NULL;
@@ -544,12 +652,11 @@ void RPCConsole::peerLayoutChanged()
return;
// find the currently selected row
- int selectedRow;
+ int selectedRow = -1;
QModelIndexList selectedModelIndex = ui->peerWidget->selectionModel()->selectedIndexes();
- if (selectedModelIndex.isEmpty())
- selectedRow = -1;
- else
+ if (!selectedModelIndex.isEmpty()) {
selectedRow = selectedModelIndex.first().row();
+ }
// check if our detail node has a row in the table (it may not necessarily
// be at selectedRow since its position can change after a layout change)
@@ -557,11 +664,8 @@ void RPCConsole::peerLayoutChanged()
if (detailNodeRow < 0)
{
- // detail node dissapeared from table (node disconnected)
+ // detail node disappeared from table (node disconnected)
fUnselect = true;
- cachedNodeid = -1;
- ui->detailWidget->hide();
- ui->peerHeading->setText(tr("Select a peer to view detailed information."));
}
else
{
@@ -576,10 +680,8 @@ void RPCConsole::peerLayoutChanged()
stats = clientModel->getPeerTableModel()->getNodeStats(detailNodeRow);
}
- if (fUnselect && selectedRow >= 0)
- {
- ui->peerWidget->selectionModel()->select(QItemSelection(selectedModelIndex.first(), selectedModelIndex.last()),
- QItemSelectionModel::Deselect);
+ if (fUnselect && selectedRow >= 0) {
+ clearSelectedNode();
}
if (fReselect)
@@ -597,7 +699,8 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
cachedNodeid = stats->nodeStats.nodeid;
// update the detail ui with latest node information
- QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName));
+ QString peerAddrDetails(QString::fromStdString(stats->nodeStats.addrName) + " ");
+ peerAddrDetails += tr("(node id: %1)").arg(QString::number(stats->nodeStats.nodeid));
if (!stats->nodeStats.addrLocal.empty())
peerAddrDetails += "<br />" + tr("via %1").arg(QString::fromStdString(stats->nodeStats.addrLocal));
ui->peerHeading->setText(peerAddrDetails);
@@ -608,11 +711,13 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerBytesRecv->setText(FormatBytes(stats->nodeStats.nRecvBytes));
ui->peerConnTime->setText(GUIUtil::formatDurationStr(GetTime() - stats->nodeStats.nTimeConnected));
ui->peerPingTime->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingTime));
+ ui->peerPingWait->setText(GUIUtil::formatPingTime(stats->nodeStats.dPingWait));
ui->timeoffset->setText(GUIUtil::formatTimeOffset(stats->nodeStats.nTimeOffset));
- ui->peerVersion->setText(QString("%1").arg(stats->nodeStats.nVersion));
+ ui->peerVersion->setText(QString("%1").arg(QString::number(stats->nodeStats.nVersion)));
ui->peerSubversion->setText(QString::fromStdString(stats->nodeStats.cleanSubVer));
ui->peerDirection->setText(stats->nodeStats.fInbound ? tr("Inbound") : tr("Outbound"));
- ui->peerHeight->setText(QString("%1").arg(stats->nodeStats.nStartingHeight));
+ ui->peerHeight->setText(QString("%1").arg(QString::number(stats->nodeStats.nStartingHeight)));
+ ui->peerWhitelisted->setText(stats->nodeStats.fWhitelisted ? tr("Yes") : tr("No"));
// This check fails for example if the lock was busy and
// nodeStateStats couldn't be fetched.
@@ -625,9 +730,12 @@ void RPCConsole::updateNodeDetail(const CNodeCombinedStats *stats)
ui->peerSyncHeight->setText(QString("%1").arg(stats->nodeStateStats.nSyncHeight));
else
ui->peerSyncHeight->setText(tr("Unknown"));
- } else {
- ui->peerBanScore->setText(tr("Fetching..."));
- ui->peerSyncHeight->setText(tr("Fetching..."));
+
+ // Common height is init to -1
+ if (stats->nodeStateStats.nCommonHeight > -1)
+ ui->peerCommonHeight->setText(QString("%1").arg(stats->nodeStateStats.nCommonHeight));
+ else
+ ui->peerCommonHeight->setText(tr("Unknown"));
}
ui->detailWidget->show();
@@ -642,7 +750,7 @@ void RPCConsole::showEvent(QShowEvent *event)
{
QWidget::showEvent(event);
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
// start PeerTableModel auto refresh
@@ -653,9 +761,92 @@ void RPCConsole::hideEvent(QHideEvent *event)
{
QWidget::hideEvent(event);
- if (!clientModel)
+ if (!clientModel || !clientModel->getPeerTableModel())
return;
// stop PeerTableModel auto refresh
clientModel->getPeerTableModel()->stopAutoRefresh();
}
+
+void RPCConsole::showPeersTableContextMenu(const QPoint& point)
+{
+ QModelIndex index = ui->peerWidget->indexAt(point);
+ if (index.isValid())
+ peersTableContextMenu->exec(QCursor::pos());
+}
+
+void RPCConsole::showBanTableContextMenu(const QPoint& point)
+{
+ QModelIndex index = ui->banlistWidget->indexAt(point);
+ if (index.isValid())
+ banTableContextMenu->exec(QCursor::pos());
+}
+
+void RPCConsole::disconnectSelectedNode()
+{
+ // Get currently selected peer address
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ // Find the node, disconnect it and clear the selected node
+ if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ bannedNode->fDisconnect = true;
+ clearSelectedNode();
+ }
+}
+
+void RPCConsole::banSelectedNode(int bantime)
+{
+ if (!clientModel)
+ return;
+
+ // Get currently selected peer address
+ QString strNode = GUIUtil::getEntryData(ui->peerWidget, 0, PeerTableModel::Address);
+ // Find possible nodes, ban it and clear the selected node
+ if (CNode *bannedNode = FindNode(strNode.toStdString())) {
+ std::string nStr = strNode.toStdString();
+ std::string addr;
+ int port = 0;
+ SplitHostPort(nStr, port, addr);
+
+ CNode::Ban(CNetAddr(addr), BanReasonManuallyAdded, bantime);
+ bannedNode->fDisconnect = true;
+ DumpBanlist();
+
+ clearSelectedNode();
+ clientModel->getBanTableModel()->refresh();
+ }
+}
+
+void RPCConsole::unbanSelectedNode()
+{
+ if (!clientModel)
+ return;
+
+ // Get currently selected ban address
+ QString strNode = GUIUtil::getEntryData(ui->banlistWidget, 0, BanTableModel::Address);
+ CSubNet possibleSubnet(strNode.toStdString());
+
+ if (possibleSubnet.IsValid())
+ {
+ CNode::Unban(possibleSubnet);
+ DumpBanlist();
+ clientModel->getBanTableModel()->refresh();
+ }
+}
+
+void RPCConsole::clearSelectedNode()
+{
+ ui->peerWidget->selectionModel()->clearSelection();
+ cachedNodeid = -1;
+ ui->detailWidget->hide();
+ ui->peerHeading->setText(tr("Select a peer to view detailed information."));
+}
+
+void RPCConsole::showOrHideBanTableIfRequired()
+{
+ if (!clientModel)
+ return;
+
+ bool visible = clientModel->getBanTableModel()->shouldShow();
+ ui->banlistWidget->setVisible(visible);
+ ui->banHeading->setVisible(visible);
+} \ No newline at end of file
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 8737be35d1..b86f776786 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -13,12 +13,15 @@
#include <QWidget>
class ClientModel;
+class PlatformStyle;
+class RPCTimerInterface;
namespace Ui {
class RPCConsole;
}
QT_BEGIN_NAMESPACE
+class QMenu;
class QItemSelection;
QT_END_NAMESPACE
@@ -28,7 +31,7 @@ class RPCConsole: public QWidget
Q_OBJECT
public:
- explicit RPCConsole(QWidget *parent);
+ explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
~RPCConsole();
void setClientModel(ClientModel *model);
@@ -45,7 +48,7 @@ protected:
virtual bool eventFilter(QObject* obj, QEvent *event);
void keyPressEvent(QKeyEvent *);
-private slots:
+private Q_SLOTS:
void on_lineEdit_returnPressed();
void on_tabWidget_currentChanged(int index);
/** open the debug.log from the current datadir */
@@ -57,8 +60,16 @@ private slots:
void resizeEvent(QResizeEvent *event);
void showEvent(QShowEvent *event);
void hideEvent(QHideEvent *event);
-
-public slots:
+ /** Show custom context menu on Peers tab */
+ void showPeersTableContextMenu(const QPoint& point);
+ /** Show custom context menu on Bans tab */
+ void showBanTableContextMenu(const QPoint& point);
+ /** Hides ban table if no bans are present */
+ void showOrHideBanTableIfRequired();
+ /** clear the selected node */
+ void clearSelectedNode();
+
+public Q_SLOTS:
void clear();
void message(int category, const QString &message, bool html = false);
/** Set number of connections shown in the UI */
@@ -73,8 +84,14 @@ public slots:
void peerSelected(const QItemSelection &selected, const QItemSelection &deselected);
/** Handle updated peer information */
void peerLayoutChanged();
-
-signals:
+ /** Disconnect a selected node on the Peers tab */
+ void disconnectSelectedNode();
+ /** Ban a selected node on the Peers tab */
+ void banSelectedNode(int bantime);
+ /** Unban a selected node on the Bans tab */
+ void unbanSelectedNode();
+
+Q_SIGNALS:
// For RPC command executor
void stopExecutor();
void cmdRequest(const QString &command);
@@ -90,7 +107,10 @@ private:
{
ADDRESS_COLUMN_WIDTH = 200,
SUBVERSION_COLUMN_WIDTH = 100,
- PING_COLUMN_WIDTH = 80
+ PING_COLUMN_WIDTH = 80,
+ BANSUBNET_COLUMN_WIDTH = 200,
+ BANTIME_COLUMN_WIDTH = 250
+
};
Ui::RPCConsole *ui;
@@ -98,6 +118,10 @@ private:
QStringList history;
int historyPtr;
NodeId cachedNodeid;
+ const PlatformStyle *platformStyle;
+ RPCTimerInterface *rpcTimerInterface;
+ QMenu *peersTableContextMenu;
+ QMenu *banTableContextMenu;
};
#endif // BITCOIN_QT_RPCCONSOLE_H
diff --git a/src/qt/scicon.cpp b/src/qt/scicon.cpp
deleted file mode 100644
index a0ffcd82a9..0000000000
--- a/src/qt/scicon.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2014 The Bitcoin developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#include "scicon.h"
-
-#include <QApplication>
-#include <QColor>
-#include <QIcon>
-#include <QImage>
-#include <QPalette>
-#include <QPixmap>
-
-static void MakeSingleColorImage(QImage& img, const QColor& colorbase)
-{
- img = img.convertToFormat(QImage::Format_ARGB32);
- for (int x = img.width(); x--; )
- {
- for (int y = img.height(); y--; )
- {
- const QRgb rgb = img.pixel(x, y);
- img.setPixel(x, y, qRgba(colorbase.red(), colorbase.green(), colorbase.blue(), qAlpha(rgb)));
- }
- }
-}
-
-QImage SingleColorImage(const QString& filename, const QColor& colorbase)
-{
- QImage img(filename);
- MakeSingleColorImage(img, colorbase);
- return img;
-}
-
-QIcon SingleColorIcon(const QIcon& ico, const QColor& colorbase)
-{
- QIcon new_ico;
- QSize sz;
- Q_FOREACH(sz, ico.availableSizes())
- {
- QImage img(ico.pixmap(sz).toImage());
- MakeSingleColorImage(img, colorbase);
- new_ico.addPixmap(QPixmap::fromImage(img));
- }
- return new_ico;
-}
-
-QIcon SingleColorIcon(const QString& filename, const QColor& colorbase)
-{
- return QIcon(QPixmap::fromImage(SingleColorImage(filename, colorbase)));
-}
-
-QColor SingleColor()
-{
- const QColor colorHighlightBg(QApplication::palette().color(QPalette::Highlight));
- const QColor colorHighlightFg(QApplication::palette().color(QPalette::HighlightedText));
- const QColor colorText(QApplication::palette().color(QPalette::WindowText));
- const int colorTextLightness = colorText.lightness();
- QColor colorbase;
- if (abs(colorHighlightBg.lightness() - colorTextLightness) < abs(colorHighlightFg.lightness() - colorTextLightness))
- colorbase = colorHighlightBg;
- else
- colorbase = colorHighlightFg;
- return colorbase;
-}
-
-QIcon SingleColorIcon(const QString& filename)
-{
- return SingleColorIcon(filename, SingleColor());
-}
-
-static QColor TextColor()
-{
- return QColor(QApplication::palette().color(QPalette::WindowText));
-}
-
-QIcon TextColorIcon(const QString& filename)
-{
- return SingleColorIcon(filename, TextColor());
-}
-
-QIcon TextColorIcon(const QIcon& ico)
-{
- return SingleColorIcon(ico, TextColor());
-}
diff --git a/src/qt/scicon.h b/src/qt/scicon.h
deleted file mode 100644
index 1388069ddb..0000000000
--- a/src/qt/scicon.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2014 The Bitcoin developers
-// Distributed under the MIT software license, see the accompanying
-// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-
-#ifndef BITCOIN_QT_SCICON_H
-#define BITCOIN_QT_SCICON_H
-
-#include <QtCore>
-
-QT_BEGIN_NAMESPACE
-class QColor;
-class QIcon;
-class QString;
-QT_END_NAMESPACE
-
-QImage SingleColorImage(const QString& filename, const QColor&);
-QIcon SingleColorIcon(const QIcon&, const QColor&);
-QIcon SingleColorIcon(const QString& filename, const QColor&);
-QColor SingleColor();
-QIcon SingleColorIcon(const QString& filename);
-QIcon TextColorIcon(const QIcon&);
-QIcon TextColorIcon(const QString& filename);
-
-#endif // BITCOIN_QT_SCICON_H
diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp
index 3d57711568..a083a6f80e 100644
--- a/src/qt/sendcoinsdialog.cpp
+++ b/src/qt/sendcoinsdialog.cpp
@@ -11,14 +11,15 @@
#include "coincontroldialog.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "sendcoinsentry.h"
#include "walletmodel.h"
#include "base58.h"
#include "coincontrol.h"
-#include "main.h"
+#include "main.h" // mempool and minRelayTxFee
#include "ui_interface.h"
+#include "txmempool.h"
#include "wallet/wallet.h"
#include <QMessageBox>
@@ -26,25 +27,26 @@
#include <QSettings>
#include <QTextDocument>
-SendCoinsDialog::SendCoinsDialog(QWidget *parent) :
+SendCoinsDialog::SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SendCoinsDialog),
clientModel(0),
model(0),
fNewRecipientAllowed(true),
- fFeeMinimized(true)
+ fFeeMinimized(true),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
-#ifdef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- ui->addButton->setIcon(QIcon());
- ui->clearButton->setIcon(QIcon());
- ui->sendButton->setIcon(QIcon());
-#else
- ui->addButton->setIcon(SingleColorIcon(":/icons/add"));
- ui->clearButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->sendButton->setIcon(SingleColorIcon(":/icons/send"));
-#endif
+ if (!platformStyle->getImagesOnButtons()) {
+ ui->addButton->setIcon(QIcon());
+ ui->clearButton->setIcon(QIcon());
+ ui->sendButton->setIcon(QIcon());
+ } else {
+ ui->addButton->setIcon(platformStyle->SingleColorIcon(":/icons/add"));
+ ui->clearButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->sendButton->setIcon(platformStyle->SingleColorIcon(":/icons/send"));
+ }
GUIUtil::setupAddressWidget(ui->lineEditCoinControlChange, this);
@@ -251,7 +253,7 @@ void SendCoinsDialog::on_sendButton_clicked()
// Format confirmation message
QStringList formatted;
- foreach(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, currentTransaction.getRecipients())
{
// generate bold amount string
QString amount = "<b>" + BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), rcp.amount);
@@ -305,14 +307,14 @@ void SendCoinsDialog::on_sendButton_clicked()
questionString.append("<hr />");
CAmount totalAmount = currentTransaction.getTotalTransactionAmount() + txFee;
QStringList alternativeUnits;
- foreach(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
+ Q_FOREACH(BitcoinUnits::Unit u, BitcoinUnits::availableUnits())
{
if(u != model->getOptionsModel()->getDisplayUnit())
alternativeUnits.append(BitcoinUnits::formatHtmlWithUnit(u, totalAmount));
}
- questionString.append(tr("Total Amount %1 (= %2)")
+ questionString.append(tr("Total Amount %1<span style='font-size:10pt;font-weight:normal;'><br />(=%2)</span>")
.arg(BitcoinUnits::formatHtmlWithUnit(model->getOptionsModel()->getDisplayUnit(), totalAmount))
- .arg(alternativeUnits.join(" " + tr("or") + " ")));
+ .arg(alternativeUnits.join(" " + tr("or") + "<br />")));
QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"),
questionString.arg(formatted.join("<br />")),
@@ -363,7 +365,7 @@ void SendCoinsDialog::accept()
SendCoinsEntry *SendCoinsDialog::addEntry()
{
- SendCoinsEntry *entry = new SendCoinsEntry(this);
+ SendCoinsEntry *entry = new SendCoinsEntry(platformStyle, this);
entry->setModel(model);
ui->entries->addWidget(entry);
connect(entry, SIGNAL(removeEntry(SendCoinsEntry*)), this, SLOT(removeEntry(SendCoinsEntry*)));
@@ -540,7 +542,7 @@ void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn
return;
}
- emit message(tr("Send Coins"), msgParams.first, msgParams.second);
+ Q_EMIT message(tr("Send Coins"), msgParams.first, msgParams.second);
}
void SendCoinsDialog::minimizeFeeSection(bool fMinimize)
@@ -710,7 +712,7 @@ void SendCoinsDialog::coinControlFeatureChanged(bool checked)
// Coin Control: button inputs -> show actual coin control dialog
void SendCoinsDialog::coinControlButtonClicked()
{
- CoinControlDialog dlg;
+ CoinControlDialog dlg(platformStyle);
dlg.setModel(model);
dlg.exec();
coinControlUpdateLabels();
@@ -752,10 +754,9 @@ void SendCoinsDialog::coinControlChangeEdited(const QString& text)
}
else // Valid address
{
- CPubKey pubkey;
CKeyID keyid;
addr.GetKeyID(keyid);
- if (!model->getPubKey(keyid, pubkey)) // Unknown change address
+ if (!model->havePrivKey(keyid)) // Unknown change address
{
ui->labelCoinControlChangeLabel->setText(tr("Warning: Unknown change address"));
}
diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h
index fc513bf2ba..391905ffcd 100644
--- a/src/qt/sendcoinsdialog.h
+++ b/src/qt/sendcoinsdialog.h
@@ -12,6 +12,7 @@
class ClientModel;
class OptionsModel;
+class PlatformStyle;
class SendCoinsEntry;
class SendCoinsRecipient;
@@ -31,7 +32,7 @@ class SendCoinsDialog : public QDialog
Q_OBJECT
public:
- explicit SendCoinsDialog(QWidget *parent = 0);
+ explicit SendCoinsDialog(const PlatformStyle *platformStyle, QWidget *parent = 0);
~SendCoinsDialog();
void setClientModel(ClientModel *clientModel);
@@ -45,7 +46,7 @@ public:
void pasteEntry(const SendCoinsRecipient &rv);
bool handlePaymentRequest(const SendCoinsRecipient &recipient);
-public slots:
+public Q_SLOTS:
void clear();
void reject();
void accept();
@@ -60,15 +61,16 @@ private:
WalletModel *model;
bool fNewRecipientAllowed;
bool fFeeMinimized;
+ const PlatformStyle *platformStyle;
// Process WalletModel::SendCoinsReturn and generate a pair consisting
- // of a message and message flags for use in emit message().
+ // of a message and message flags for use in Q_EMIT message().
// Additional parameter msgArg can be used via .arg(msgArg).
void processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg = QString());
void minimizeFeeSection(bool fMinimize);
void updateFeeMinimizedLabel();
-private slots:
+private Q_SLOTS:
void on_sendButton_clicked();
void on_buttonChooseFee_clicked();
void on_buttonMinimizeFee_clicked();
@@ -93,7 +95,7 @@ private slots:
void updateSmartFeeLabel();
void updateGlobalFeeVariables();
-signals:
+Q_SIGNALS:
// Fired when a message should be reported to the user
void message(const QString &title, const QString &message, unsigned int style);
};
diff --git a/src/qt/sendcoinsentry.cpp b/src/qt/sendcoinsentry.cpp
index 6eec33ffd4..44aa8ad1af 100644
--- a/src/qt/sendcoinsentry.cpp
+++ b/src/qt/sendcoinsentry.cpp
@@ -9,30 +9,30 @@
#include "addresstablemodel.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "walletmodel.h"
#include <QApplication>
#include <QClipboard>
-SendCoinsEntry::SendCoinsEntry(QWidget *parent) :
+SendCoinsEntry::SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent) :
QStackedWidget(parent),
ui(new Ui::SendCoinsEntry),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
- ui->addressBookButton->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->pasteButton->setIcon(SingleColorIcon(":/icons/editpaste"));
- ui->deleteButton->setIcon(SingleColorIcon(":/icons/remove"));
- ui->deleteButton_is->setIcon(SingleColorIcon(":/icons/remove"));
- ui->deleteButton_s->setIcon(SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->pasteButton->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
+ ui->deleteButton->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->deleteButton_is->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->deleteButton_s->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
setCurrentWidget(ui->SendCoins);
-#ifdef Q_OS_MAC
- ui->payToLayout->setSpacing(4);
-#endif
+ if (platformStyle->getUseExtraSpacing())
+ ui->payToLayout->setSpacing(4);
#if QT_VERSION >= 0x040700
ui->addAsLabel->setPlaceholderText(tr("Enter a label for this address to add it to your address book"));
#endif
@@ -65,7 +65,7 @@ void SendCoinsEntry::on_addressBookButton_clicked()
{
if(!model)
return;
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
dlg.setModel(model->getAddressTableModel());
if(dlg.exec())
{
@@ -114,7 +114,7 @@ void SendCoinsEntry::clear()
void SendCoinsEntry::deleteClicked()
{
- emit removeEntry(this);
+ Q_EMIT removeEntry(this);
}
bool SendCoinsEntry::validate()
diff --git a/src/qt/sendcoinsentry.h b/src/qt/sendcoinsentry.h
index c2d1185bdd..107ab70158 100644
--- a/src/qt/sendcoinsentry.h
+++ b/src/qt/sendcoinsentry.h
@@ -10,6 +10,7 @@
#include <QStackedWidget>
class WalletModel;
+class PlatformStyle;
namespace Ui {
class SendCoinsEntry;
@@ -25,7 +26,7 @@ class SendCoinsEntry : public QStackedWidget
Q_OBJECT
public:
- explicit SendCoinsEntry(QWidget *parent = 0);
+ explicit SendCoinsEntry(const PlatformStyle *platformStyle, QWidget *parent = 0);
~SendCoinsEntry();
void setModel(WalletModel *model);
@@ -45,15 +46,15 @@ public:
void setFocus();
-public slots:
+public Q_SLOTS:
void clear();
-signals:
+Q_SIGNALS:
void removeEntry(SendCoinsEntry *entry);
void payAmountChanged();
void subtractFeeFromAmountChanged();
-private slots:
+private Q_SLOTS:
void deleteClicked();
void on_payTo_textChanged(const QString &address);
void on_addressBookButton_clicked();
@@ -64,6 +65,7 @@ private:
SendCoinsRecipient recipient;
Ui::SendCoinsEntry *ui;
WalletModel *model;
+ const PlatformStyle *platformStyle;
bool updateLabel(const QString &address);
};
diff --git a/src/qt/signverifymessagedialog.cpp b/src/qt/signverifymessagedialog.cpp
index ce166f3672..60e8e36ebe 100644
--- a/src/qt/signverifymessagedialog.cpp
+++ b/src/qt/signverifymessagedialog.cpp
@@ -7,7 +7,7 @@
#include "addressbookpage.h"
#include "guiutil.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "walletmodel.h"
#include "base58.h"
@@ -20,21 +20,22 @@
#include <QClipboard>
-SignVerifyMessageDialog::SignVerifyMessageDialog(QWidget *parent) :
+SignVerifyMessageDialog::SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent) :
QDialog(parent),
ui(new Ui::SignVerifyMessageDialog),
- model(0)
+ model(0),
+ platformStyle(platformStyle)
{
ui->setupUi(this);
- ui->addressBookButton_SM->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->pasteButton_SM->setIcon(SingleColorIcon(":/icons/editpaste"));
- ui->copySignatureButton_SM->setIcon(SingleColorIcon(":/icons/editcopy"));
- ui->signMessageButton_SM->setIcon(SingleColorIcon(":/icons/edit"));
- ui->clearButton_SM->setIcon(SingleColorIcon(":/icons/remove"));
- ui->addressBookButton_VM->setIcon(SingleColorIcon(":/icons/address-book"));
- ui->verifyMessageButton_VM->setIcon(SingleColorIcon(":/icons/transaction_0"));
- ui->clearButton_VM->setIcon(SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->pasteButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editpaste"));
+ ui->copySignatureButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/editcopy"));
+ ui->signMessageButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/edit"));
+ ui->clearButton_SM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
+ ui->addressBookButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/address-book"));
+ ui->verifyMessageButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/transaction_0"));
+ ui->clearButton_VM->setIcon(platformStyle->SingleColorIcon(":/icons/remove"));
#if QT_VERSION >= 0x040700
ui->signatureOut_SM->setPlaceholderText(tr("Click \"Sign Message\" to generate signature"));
@@ -94,7 +95,7 @@ void SignVerifyMessageDialog::on_addressBookButton_SM_clicked()
{
if (model && model->getAddressTableModel())
{
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this);
dlg.setModel(model->getAddressTableModel());
if (dlg.exec())
{
@@ -148,12 +149,12 @@ void SignVerifyMessageDialog::on_signMessageButton_SM_clicked()
return;
}
- CDataStream ss(SER_GETHASH, 0);
+ CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << ui->messageIn_SM->document()->toPlainText().toStdString();
std::vector<unsigned char> vchSig;
- if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig))
+ if (!key.SignCompact(ss.GetHash(), vchSig))
{
ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }");
ui->statusLabel_SM->setText(QString("<nobr>") + tr("Message signing failed.") + QString("</nobr>"));
@@ -185,7 +186,7 @@ void SignVerifyMessageDialog::on_addressBookButton_VM_clicked()
{
if (model && model->getAddressTableModel())
{
- AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
+ AddressBookPage dlg(platformStyle, AddressBookPage::ForSelection, AddressBookPage::SendingTab, this);
dlg.setModel(model->getAddressTableModel());
if (dlg.exec())
{
@@ -223,12 +224,12 @@ void SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()
return;
}
- CDataStream ss(SER_GETHASH, 0);
+ CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << ui->messageIn_VM->document()->toPlainText().toStdString();
CPubKey pubkey;
- if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig))
+ if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
{
ui->signatureIn_VM->setValid(false);
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
diff --git a/src/qt/signverifymessagedialog.h b/src/qt/signverifymessagedialog.h
index 27807adc84..d651d5049b 100644
--- a/src/qt/signverifymessagedialog.h
+++ b/src/qt/signverifymessagedialog.h
@@ -7,6 +7,7 @@
#include <QDialog>
+class PlatformStyle;
class WalletModel;
namespace Ui {
@@ -18,7 +19,7 @@ class SignVerifyMessageDialog : public QDialog
Q_OBJECT
public:
- explicit SignVerifyMessageDialog(QWidget *parent);
+ explicit SignVerifyMessageDialog(const PlatformStyle *platformStyle, QWidget *parent);
~SignVerifyMessageDialog();
void setModel(WalletModel *model);
@@ -34,8 +35,9 @@ protected:
private:
Ui::SignVerifyMessageDialog *ui;
WalletModel *model;
+ const PlatformStyle *platformStyle;
-private slots:
+private Q_SLOTS:
/* sign message */
void on_addressBookButton_SM_clicked();
void on_pasteButton_SM_clicked();
diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp
index 8430e017c1..c15b64c327 100644
--- a/src/qt/splashscreen.cpp
+++ b/src/qt/splashscreen.cpp
@@ -57,7 +57,7 @@ SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle)
QPainter pixPaint(&pixmap);
pixPaint.setPen(QColor(100,100,100));
- // draw a slighly radial gradient
+ // draw a slightly radial gradient
QRadialGradient gradient(QPoint(0,0), splashSize.width()/devicePixelRatio);
gradient.setColorAt(0, Qt::white);
gradient.setColorAt(1, QColor(247,247,247));
diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h
index 84e4556dd8..29d16d4eae 100644
--- a/src/qt/splashscreen.h
+++ b/src/qt/splashscreen.h
@@ -27,7 +27,7 @@ protected:
void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event);
-public slots:
+public Q_SLOTS:
/** Slot to call finish() method as it's not defined as slot */
void slotFinish(QWidget *mainWin);
diff --git a/src/qt/test/paymentservertests.cpp b/src/qt/test/paymentservertests.cpp
index e2ec439b2e..fa5696325d 100644
--- a/src/qt/test/paymentservertests.cpp
+++ b/src/qt/test/paymentservertests.cpp
@@ -185,7 +185,8 @@ void PaymentServerTests::paymentServerTests()
tempFile.open();
tempFile.write((const char*)randData, sizeof(randData));
tempFile.close();
- QCOMPARE(PaymentServer::readPaymentRequestFromFile(tempFile.fileName(), r.paymentRequest), false);
+ // compares 50001 <= BIP70_MAX_PAYMENTREQUEST_SIZE == false
+ QCOMPARE(PaymentServer::verifySize(tempFile.size()), false);
// Payment request with amount overflow (amount is set to 21000001 BTC):
data = DecodeBase64(paymentrequest5_cert2_BASE64);
@@ -195,7 +196,7 @@ void PaymentServerTests::paymentServerTests()
QVERIFY(r.paymentRequest.IsInitialized());
// Extract address and amount from the request
QList<std::pair<CScript, CAmount> > sendingTos = r.paymentRequest.getPayTo();
- foreach (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
+ Q_FOREACH (const PAIRTYPE(CScript, CAmount)& sendingTo, sendingTos) {
CTxDestination dest;
if (ExtractDestination(sendingTo.first, dest))
QCOMPARE(PaymentServer::verifyAmount(sendingTo.second), false);
diff --git a/src/qt/test/paymentservertests.h b/src/qt/test/paymentservertests.h
index c98bbf0833..71d61fcbe7 100644
--- a/src/qt/test/paymentservertests.h
+++ b/src/qt/test/paymentservertests.h
@@ -14,7 +14,7 @@ class PaymentServerTests : public QObject
{
Q_OBJECT
-private slots:
+private Q_SLOTS:
void paymentServerTests();
};
@@ -25,7 +25,7 @@ class RecipientCatcher : public QObject
{
Q_OBJECT
-public slots:
+public Q_SLOTS:
void getRecipient(SendCoinsRecipient r);
public:
diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp
index bb768f1325..f91de2008c 100644
--- a/src/qt/test/test_main.cpp
+++ b/src/qt/test/test_main.cpp
@@ -17,6 +17,8 @@
#include <QObject>
#include <QTest>
+#include <openssl/ssl.h>
+
#if defined(QT_STATICPLUGIN) && QT_VERSION < 0x050000
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
@@ -36,6 +38,8 @@ int main(int argc, char *argv[])
QCoreApplication app(argc, argv);
app.setApplicationName("Bitcoin-Qt-test");
+ SSL_library_init();
+
URITests test1;
if (QTest::qExec(&test1) != 0)
fInvalid = true;
diff --git a/src/qt/test/uritests.h b/src/qt/test/uritests.h
index a0b7dc6c72..434169dcde 100644
--- a/src/qt/test/uritests.h
+++ b/src/qt/test/uritests.h
@@ -12,7 +12,7 @@ class URITests : public QObject
{
Q_OBJECT
-private slots:
+private Q_SLOTS:
void uriTests();
};
diff --git a/src/qt/trafficgraphwidget.cpp b/src/qt/trafficgraphwidget.cpp
index 0b2eb9eaf2..9b67445bc0 100644
--- a/src/qt/trafficgraphwidget.cpp
+++ b/src/qt/trafficgraphwidget.cpp
@@ -139,10 +139,10 @@ void TrafficGraphWidget::updateRates()
}
float tmax = 0.0f;
- foreach(float f, vSamplesIn) {
+ Q_FOREACH(float f, vSamplesIn) {
if(f > tmax) tmax = f;
}
- foreach(float f, vSamplesOut) {
+ Q_FOREACH(float f, vSamplesOut) {
if(f > tmax) tmax = f;
}
fMax = tmax;
diff --git a/src/qt/trafficgraphwidget.h b/src/qt/trafficgraphwidget.h
index 4c6b17fe7e..6336a8d144 100644
--- a/src/qt/trafficgraphwidget.h
+++ b/src/qt/trafficgraphwidget.h
@@ -27,7 +27,7 @@ public:
protected:
void paintEvent(QPaintEvent *);
-public slots:
+public Q_SLOTS:
void updateRates();
void setGraphRangeMins(int mins);
void clear();
diff --git a/src/qt/transactiondesc.cpp b/src/qt/transactiondesc.cpp
index 4fffd03adf..801c6c62d2 100644
--- a/src/qt/transactiondesc.cpp
+++ b/src/qt/transactiondesc.cpp
@@ -21,12 +21,10 @@
#include <stdint.h>
#include <string>
-using namespace std;
-
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
{
AssertLockHeld(cs_main);
- if (!IsFinalTx(wtx, chainActive.Height() + 1))
+ if (!CheckFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
return tr("Open for %n more block(s)", "", wtx.nLockTime - chainActive.Height());
@@ -167,7 +165,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
if (fAllFromMe)
{
- if(fAllFromMe == ISMINE_WATCH_ONLY)
+ if(fAllFromMe & ISMINE_WATCH_ONLY)
strHTML += "<b>" + tr("From") + ":</b> " + tr("watch-only") + "<br>";
//
@@ -192,7 +190,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += GUIUtil::HtmlEscape(CBitcoinAddress(address).ToString());
if(toSelf == ISMINE_SPENDABLE)
strHTML += " (own address)";
- else if(toSelf == ISMINE_WATCH_ONLY)
+ else if(toSelf & ISMINE_WATCH_ONLY)
strHTML += " (watch-only)";
strHTML += "<br>";
}
@@ -243,14 +241,14 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, TransactionReco
strHTML += "<b>" + tr("Transaction ID") + ":</b> " + TransactionRecord::formatSubTxId(wtx.GetHash(), rec->idx) + "<br>";
// Message from normal bitcoin:URI (bitcoin:123...?message=example)
- foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm)
+ Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
if (r.first == "Message")
strHTML += "<br><b>" + tr("Message") + ":</b><br>" + GUIUtil::HtmlEscape(r.second, true) + "<br>";
//
// PaymentRequest info:
//
- foreach (const PAIRTYPE(string, string)& r, wtx.vOrderForm)
+ Q_FOREACH (const PAIRTYPE(std::string, std::string)& r, wtx.vOrderForm)
{
if (r.first == "PaymentRequest")
{
diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp
index 7f1db58e5d..d8623daf5d 100644
--- a/src/qt/transactionrecord.cpp
+++ b/src/qt/transactionrecord.cpp
@@ -56,7 +56,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
CTxDestination address;
sub.idx = parts.size(); // sequence number
sub.credit = txout.nValue;
- sub.involvesWatchAddress = mine == ISMINE_WATCH_ONLY;
+ sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address))
{
// Received by Bitcoin Address
@@ -86,7 +86,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
{
isminetype mine = wallet->IsMine(txin);
- if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true;
+ if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
if(fAllFromMe > mine) fAllFromMe = mine;
}
@@ -94,7 +94,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
isminetype mine = wallet->IsMine(txout);
- if(mine == ISMINE_WATCH_ONLY) involvesWatchAddress = true;
+ if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
if(fAllToMe > mine) fAllToMe = mine;
}
@@ -188,7 +188,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
status.depth = wtx.GetDepthInMainChain();
status.cur_num_blocks = chainActive.Height();
- if (!IsFinalTx(wtx, chainActive.Height() + 1))
+ if (!CheckFinalTx(wtx))
{
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
{
diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp
index 34464b4075..98ad1a44b6 100644
--- a/src/qt/transactiontablemodel.cpp
+++ b/src/qt/transactiontablemodel.cpp
@@ -8,7 +8,7 @@
#include "guiconstants.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactiondesc.h"
#include "transactionrecord.h"
#include "walletmodel.h"
@@ -25,6 +25,8 @@
#include <QIcon>
#include <QList>
+#include <boost/foreach.hpp>
+
// Amount column is right-aligned it contains numbers
static int column_alignments[] = {
Qt::AlignLeft|Qt::AlignVCenter, /* status */
@@ -142,7 +144,7 @@ public:
{
parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
int insert_idx = lowerIndex;
- foreach(const TransactionRecord &rec, toInsert)
+ Q_FOREACH(const TransactionRecord &rec, toInsert)
{
cachedWallet.insert(insert_idx, rec);
insert_idx += 1;
@@ -220,12 +222,13 @@ public:
}
};
-TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *parent):
+TransactionTableModel::TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent):
QAbstractTableModel(parent),
wallet(wallet),
walletModel(parent),
priv(new TransactionTablePriv(wallet, this)),
- fProcessingQueuedTransactions(false)
+ fProcessingQueuedTransactions(false),
+ platformStyle(platformStyle)
{
columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
priv->refreshWallet();
@@ -245,7 +248,7 @@ TransactionTableModel::~TransactionTableModel()
void TransactionTableModel::updateAmountColumnTitle()
{
columns[Amount] = BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
- emit headerDataChanged(Qt::Horizontal,Amount,Amount);
+ Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
}
void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
@@ -262,8 +265,8 @@ void TransactionTableModel::updateConfirmations()
// Invalidate status (number of confirmations) and (possibly) description
// for all rows. Qt is smart enough to only actually request the data for the
// visible rows.
- emit dataChanged(index(0, Status), index(priv->size()-1, Status));
- emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
+ Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
+ Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
}
int TransactionTableModel::rowCount(const QModelIndex &parent) const
@@ -519,7 +522,7 @@ QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
case Qt::DecorationRole:
{
QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
- return TextColorIcon(icon);
+ return platformStyle->TextColorIcon(icon);
}
case Qt::DisplayRole:
switch(index.column())
@@ -650,7 +653,7 @@ void TransactionTableModel::updateDisplayUnit()
{
// emit dataChanged to update Amount column with the current unit
updateAmountColumnTitle();
- emit dataChanged(index(0, Amount), index(priv->size()-1, Amount));
+ Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
}
// queue notifications to show a non freezing progress dialog e.g. for rescan
diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h
index 30a15df9e6..2089f703a6 100644
--- a/src/qt/transactiontablemodel.h
+++ b/src/qt/transactiontablemodel.h
@@ -10,6 +10,7 @@
#include <QAbstractTableModel>
#include <QStringList>
+class PlatformStyle;
class TransactionRecord;
class TransactionTablePriv;
class WalletModel;
@@ -23,7 +24,7 @@ class TransactionTableModel : public QAbstractTableModel
Q_OBJECT
public:
- explicit TransactionTableModel(CWallet* wallet, WalletModel *parent = 0);
+ explicit TransactionTableModel(const PlatformStyle *platformStyle, CWallet* wallet, WalletModel *parent = 0);
~TransactionTableModel();
enum ColumnIndex {
@@ -82,6 +83,7 @@ private:
QStringList columns;
TransactionTablePriv *priv;
bool fProcessingQueuedTransactions;
+ const PlatformStyle *platformStyle;
void subscribeToCoreSignals();
void unsubscribeFromCoreSignals();
@@ -98,7 +100,7 @@ private:
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const;
QVariant txAddressDecoration(const TransactionRecord *wtx) const;
-public slots:
+public Q_SLOTS:
/* New transaction, or transaction changed status */
void updateTransaction(const QString &hash, int status, bool showTransaction);
void updateConfirmations();
diff --git a/src/qt/transactionview.cpp b/src/qt/transactionview.cpp
index 526940632e..54e5a82720 100644
--- a/src/qt/transactionview.cpp
+++ b/src/qt/transactionview.cpp
@@ -10,7 +10,7 @@
#include "editaddressdialog.h"
#include "guiutil.h"
#include "optionsmodel.h"
-#include "scicon.h"
+#include "platformstyle.h"
#include "transactiondescdialog.h"
#include "transactionfilterproxy.h"
#include "transactionrecord.h"
@@ -35,7 +35,7 @@
#include <QUrl>
#include <QVBoxLayout>
-TransactionView::TransactionView(QWidget *parent) :
+TransactionView::TransactionView(const PlatformStyle *platformStyle, QWidget *parent) :
QWidget(parent), model(0), transactionProxyModel(0),
transactionView(0)
{
@@ -44,27 +44,28 @@ TransactionView::TransactionView(QWidget *parent) :
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->setContentsMargins(0,0,0,0);
-#ifdef Q_OS_MAC
- hlayout->setSpacing(5);
- hlayout->addSpacing(26);
-#else
- hlayout->setSpacing(0);
- hlayout->addSpacing(23);
-#endif
+
+ if (platformStyle->getUseExtraSpacing()) {
+ hlayout->setSpacing(5);
+ hlayout->addSpacing(26);
+ } else {
+ hlayout->setSpacing(0);
+ hlayout->addSpacing(23);
+ }
watchOnlyWidget = new QComboBox(this);
watchOnlyWidget->setFixedWidth(24);
watchOnlyWidget->addItem("", TransactionFilterProxy::WatchOnlyFilter_All);
- watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
- watchOnlyWidget->addItem(SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
+ watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_plus"), "", TransactionFilterProxy::WatchOnlyFilter_Yes);
+ watchOnlyWidget->addItem(platformStyle->SingleColorIcon(":/icons/eye_minus"), "", TransactionFilterProxy::WatchOnlyFilter_No);
hlayout->addWidget(watchOnlyWidget);
dateWidget = new QComboBox(this);
-#ifdef Q_OS_MAC
- dateWidget->setFixedWidth(121);
-#else
- dateWidget->setFixedWidth(120);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ dateWidget->setFixedWidth(121);
+ } else {
+ dateWidget->setFixedWidth(120);
+ }
dateWidget->addItem(tr("All"), All);
dateWidget->addItem(tr("Today"), Today);
dateWidget->addItem(tr("This week"), ThisWeek);
@@ -75,11 +76,11 @@ TransactionView::TransactionView(QWidget *parent) :
hlayout->addWidget(dateWidget);
typeWidget = new QComboBox(this);
-#ifdef Q_OS_MAC
- typeWidget->setFixedWidth(121);
-#else
- typeWidget->setFixedWidth(120);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ typeWidget->setFixedWidth(121);
+ } else {
+ typeWidget->setFixedWidth(120);
+ }
typeWidget->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES);
typeWidget->addItem(tr("Received with"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) |
@@ -102,11 +103,11 @@ TransactionView::TransactionView(QWidget *parent) :
#if QT_VERSION >= 0x040700
amountWidget->setPlaceholderText(tr("Min amount"));
#endif
-#ifdef Q_OS_MAC
- amountWidget->setFixedWidth(97);
-#else
- amountWidget->setFixedWidth(100);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ amountWidget->setFixedWidth(97);
+ } else {
+ amountWidget->setFixedWidth(100);
+ }
amountWidget->setValidator(new QDoubleValidator(0, 1e20, 8, this));
hlayout->addWidget(amountWidget);
@@ -121,11 +122,11 @@ TransactionView::TransactionView(QWidget *parent) :
vlayout->setSpacing(0);
int width = view->verticalScrollBar()->sizeHint().width();
// Cover scroll bar width with spacing
-#ifdef Q_OS_MAC
- hlayout->addSpacing(width+2);
-#else
- hlayout->addSpacing(width);
-#endif
+ if (platformStyle->getUseExtraSpacing()) {
+ hlayout->addSpacing(width+2);
+ } else {
+ hlayout->addSpacing(width);
+ }
// Always show scroll bar
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
view->setTabKeyNavigation(false);
@@ -341,11 +342,11 @@ void TransactionView::exportClicked()
writer.addColumn(tr("ID"), 0, TransactionTableModel::TxIDRole);
if(!writer.write()) {
- emit message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
+ Q_EMIT message(tr("Exporting Failed"), tr("There was an error trying to save the transaction history to %1.").arg(filename),
CClientUIInterface::MSG_ERROR);
}
else {
- emit message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
+ Q_EMIT message(tr("Exporting Successful"), tr("The transaction history was successfully saved to %1.").arg(filename),
CClientUIInterface::MSG_INFORMATION);
}
}
diff --git a/src/qt/transactionview.h b/src/qt/transactionview.h
index 092d919042..ac157fb98d 100644
--- a/src/qt/transactionview.h
+++ b/src/qt/transactionview.h
@@ -10,6 +10,7 @@
#include <QWidget>
#include <QKeyEvent>
+class PlatformStyle;
class TransactionFilterProxy;
class WalletModel;
@@ -32,7 +33,7 @@ class TransactionView : public QWidget
Q_OBJECT
public:
- explicit TransactionView(QWidget *parent = 0);
+ explicit TransactionView(const PlatformStyle *platformStyle, QWidget *parent = 0);
void setModel(WalletModel *model);
@@ -83,7 +84,7 @@ private:
bool eventFilter(QObject *obj, QEvent *event);
-private slots:
+private Q_SLOTS:
void contextualMenu(const QPoint &);
void dateRangeChanged();
void showDetails();
@@ -95,13 +96,13 @@ private slots:
void openThirdPartyTxUrl(QString url);
void updateWatchOnlyColumn(bool fHaveWatchOnly);
-signals:
+Q_SIGNALS:
void doubleClicked(const QModelIndex&);
/** Fired when a message should be reported to the user */
void message(const QString &title, const QString &message, unsigned int style);
-public slots:
+public Q_SLOTS:
void chooseDate(int idx);
void chooseType(int idx);
void chooseWatchonly(int idx);
diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp
index 386cf31d73..5e26f3e01b 100644
--- a/src/qt/utilitydialog.cpp
+++ b/src/qt/utilitydialog.cpp
@@ -84,7 +84,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) :
QTextCharFormat bold;
bold.setFontWeight(QFont::Bold);
- foreach (const QString &line, coreOptions.split("\n")) {
+ Q_FOREACH (const QString &line, coreOptions.split("\n")) {
if (line.startsWith(" -"))
{
cursor.currentTable()->appendRows(1);
diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h
index 288b985f13..47282ae2d0 100644
--- a/src/qt/utilitydialog.h
+++ b/src/qt/utilitydialog.h
@@ -31,7 +31,7 @@ private:
Ui::HelpMessageDialog *ui;
QString text;
-private slots:
+private Q_SLOTS:
void on_okButton_accepted();
};
diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp
index 892947bf3a..ba8c28464d 100644
--- a/src/qt/walletframe.cpp
+++ b/src/qt/walletframe.cpp
@@ -12,9 +12,10 @@
#include <QHBoxLayout>
#include <QLabel>
-WalletFrame::WalletFrame(BitcoinGUI *_gui) :
+WalletFrame::WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui) :
QFrame(_gui),
- gui(_gui)
+ gui(_gui),
+ platformStyle(platformStyle)
{
// Leave HBox hook for adding a list view later
QHBoxLayout *walletFrameLayout = new QHBoxLayout(this);
@@ -42,7 +43,7 @@ bool WalletFrame::addWallet(const QString& name, WalletModel *walletModel)
if (!gui || !clientModel || !walletModel || mapWalletViews.count(name) > 0)
return false;
- WalletView *walletView = new WalletView(this);
+ WalletView *walletView = new WalletView(platformStyle, this);
walletView->setBitcoinGUI(gui);
walletView->setClientModel(clientModel);
walletView->setWalletModel(walletModel);
diff --git a/src/qt/walletframe.h b/src/qt/walletframe.h
index eea97defc9..9a56e97f9c 100644
--- a/src/qt/walletframe.h
+++ b/src/qt/walletframe.h
@@ -10,6 +10,7 @@
class BitcoinGUI;
class ClientModel;
+class PlatformStyle;
class SendCoinsRecipient;
class WalletModel;
class WalletView;
@@ -23,7 +24,7 @@ class WalletFrame : public QFrame
Q_OBJECT
public:
- explicit WalletFrame(BitcoinGUI *_gui = 0);
+ explicit WalletFrame(const PlatformStyle *platformStyle, BitcoinGUI *_gui = 0);
~WalletFrame();
void setClientModel(ClientModel *clientModel);
@@ -45,9 +46,11 @@ private:
bool bOutOfSync;
+ const PlatformStyle *platformStyle;
+
WalletView *currentWalletView();
-public slots:
+public Q_SLOTS:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp
index 9b8be76beb..5c21db8bdf 100644
--- a/src/qt/walletmodel.cpp
+++ b/src/qt/walletmodel.cpp
@@ -25,9 +25,9 @@
#include <QSet>
#include <QTimer>
-using namespace std;
+#include <boost/foreach.hpp>
-WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
+WalletModel::WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent) :
QObject(parent), wallet(wallet), optionsModel(optionsModel), addressTableModel(0),
transactionTableModel(0),
recentRequestsTableModel(0),
@@ -39,7 +39,7 @@ WalletModel::WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *p
fForceCheckBalanceChanged = false;
addressTableModel = new AddressTableModel(wallet, this);
- transactionTableModel = new TransactionTableModel(wallet, this);
+ transactionTableModel = new TransactionTableModel(platformStyle, wallet, this);
recentRequestsTableModel = new RecentRequestsTableModel(wallet, this);
// This timer will be fired repeatedly to update the balance
@@ -107,7 +107,7 @@ void WalletModel::updateStatus()
EncryptionStatus newEncryptionStatus = getEncryptionStatus();
if(cachedEncryptionStatus != newEncryptionStatus)
- emit encryptionStatusChanged(newEncryptionStatus);
+ Q_EMIT encryptionStatusChanged(newEncryptionStatus);
}
void WalletModel::pollBalanceChanged()
@@ -159,7 +159,7 @@ void WalletModel::checkBalanceChanged()
cachedWatchOnlyBalance = newWatchOnlyBalance;
cachedWatchUnconfBalance = newWatchUnconfBalance;
cachedWatchImmatureBalance = newWatchImmatureBalance;
- emit balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
+ Q_EMIT balanceChanged(newBalance, newUnconfirmedBalance, newImmatureBalance,
newWatchOnlyBalance, newWatchUnconfBalance, newWatchImmatureBalance);
}
}
@@ -180,7 +180,7 @@ void WalletModel::updateAddressBook(const QString &address, const QString &label
void WalletModel::updateWatchOnlyFlag(bool fHaveWatchonly)
{
fHaveWatchOnly = fHaveWatchonly;
- emit notifyWatchonlyChanged(fHaveWatchonly);
+ Q_EMIT notifyWatchonlyChanged(fHaveWatchonly);
}
bool WalletModel::validateAddress(const QString &address)
@@ -205,7 +205,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
int nAddresses = 0;
// Pre-check input data for validity
- foreach(const SendCoinsRecipient &rcp, recipients)
+ Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
{
if (rcp.fSubtractFeeFromAmount)
fSubtractFeeFromAmount = true;
@@ -285,7 +285,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact
{
return SendCoinsReturn(AmountWithFeeExceedsBalance);
}
- emit message(tr("Send Coins"), QString::fromStdString(strFailReason),
+ Q_EMIT message(tr("Send Coins"), QString::fromStdString(strFailReason),
CClientUIInterface::MSG_ERROR);
return TransactionCreationFailed;
}
@@ -306,7 +306,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
LOCK2(cs_main, wallet->cs_wallet);
CWalletTx *newTx = transaction.getTransaction();
- foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
if (rcp.paymentRequest.IsInitialized())
{
@@ -337,7 +337,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
// Add addresses / update labels that we've sent to to the address book,
// and emit coinsSent signal for each recipient
- foreach(const SendCoinsRecipient &rcp, transaction.getRecipients())
+ Q_FOREACH(const SendCoinsRecipient &rcp, transaction.getRecipients())
{
// Don't touch the address book when we have a payment request
if (!rcp.paymentRequest.IsInitialized())
@@ -361,7 +361,7 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran
}
}
}
- emit coinsSent(wallet, rcp, transaction_array);
+ Q_EMIT coinsSent(wallet, rcp, transaction_array);
}
checkBalanceChanged(); // update balance immediately, otherwise there could be a short noticeable delay until pollBalanceChanged hits
@@ -521,7 +521,7 @@ WalletModel::UnlockContext WalletModel::requestUnlock()
if(was_locked)
{
// Request UI to unlock wallet
- emit requireUnlock();
+ Q_EMIT requireUnlock();
}
// If wallet is still locked, unlock was failed or cancelled, mark context as invalid
bool valid = getEncryptionStatus() != Locked;
@@ -556,6 +556,11 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
return wallet->GetPubKey(address, vchPubKeyOut);
}
+bool WalletModel::havePrivKey(const CKeyID &address) const
+{
+ return wallet->HaveKey(address);
+}
+
// returns a list of COutputs from COutPoints
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
{
diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h
index e263438880..a5e877d81f 100644
--- a/src/qt/walletmodel.h
+++ b/src/qt/walletmodel.h
@@ -17,6 +17,7 @@
class AddressTableModel;
class OptionsModel;
+class PlatformStyle;
class RecentRequestsTableModel;
class TransactionTableModel;
class WalletModelTransaction;
@@ -100,7 +101,7 @@ class WalletModel : public QObject
Q_OBJECT
public:
- explicit WalletModel(CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
+ explicit WalletModel(const PlatformStyle *platformStyle, CWallet *wallet, OptionsModel *optionsModel, QObject *parent = 0);
~WalletModel();
enum StatusCode // Returned by sendCoins
@@ -186,6 +187,7 @@ public:
UnlockContext requestUnlock();
bool getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const;
+ bool havePrivKey(const CKeyID &address) const;
void getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs);
bool isSpent(const COutPoint& outpoint) const;
void listCoins(std::map<QString, std::vector<COutput> >& mapCoins) const;
@@ -227,7 +229,7 @@ private:
void unsubscribeFromCoreSignals();
void checkBalanceChanged();
-signals:
+Q_SIGNALS:
// Signal that balance in wallet changed
void balanceChanged(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance,
const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance);
@@ -252,7 +254,7 @@ signals:
// Watch-only address added
void notifyWatchonlyChanged(bool fHaveWatchonly);
-public slots:
+public Q_SLOTS:
/* Wallet status might have changed */
void updateStatus();
/* New transaction, or transaction changed status */
diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp
index 206bb7c774..6a9b2d5bd3 100644
--- a/src/qt/walletmodeltransaction.cpp
+++ b/src/qt/walletmodeltransaction.cpp
@@ -81,7 +81,7 @@ void WalletModelTransaction::reassignAmounts(int nChangePosRet)
CAmount WalletModelTransaction::getTotalTransactionAmount()
{
CAmount totalTransactionAmount = 0;
- foreach(const SendCoinsRecipient &rcp, recipients)
+ Q_FOREACH(const SendCoinsRecipient &rcp, recipients)
{
totalTransactionAmount += rcp.amount;
}
diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp
index 956c8b8913..77efdb5cdd 100644
--- a/src/qt/walletview.cpp
+++ b/src/qt/walletview.cpp
@@ -11,8 +11,8 @@
#include "guiutil.h"
#include "optionsmodel.h"
#include "overviewpage.h"
+#include "platformstyle.h"
#include "receivecoinsdialog.h"
-#include "scicon.h"
#include "sendcoinsdialog.h"
#include "signverifymessagedialog.h"
#include "transactiontablemodel.h"
@@ -29,31 +29,35 @@
#include <QPushButton>
#include <QVBoxLayout>
-WalletView::WalletView(QWidget *parent):
+WalletView::WalletView(const PlatformStyle *platformStyle, QWidget *parent):
QStackedWidget(parent),
clientModel(0),
- walletModel(0)
+ walletModel(0),
+ platformStyle(platformStyle)
{
// Create tabs
- overviewPage = new OverviewPage();
+ overviewPage = new OverviewPage(platformStyle);
transactionsPage = new QWidget(this);
QVBoxLayout *vbox = new QVBoxLayout();
QHBoxLayout *hbox_buttons = new QHBoxLayout();
- transactionView = new TransactionView(this);
+ transactionView = new TransactionView(platformStyle, this);
vbox->addWidget(transactionView);
QPushButton *exportButton = new QPushButton(tr("&Export"), this);
exportButton->setToolTip(tr("Export the data in the current tab to a file"));
-#ifndef Q_OS_MAC // Icons on push buttons are very uncommon on Mac
- exportButton->setIcon(SingleColorIcon(":/icons/export"));
-#endif
+ if (platformStyle->getImagesOnButtons()) {
+ exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
+ }
hbox_buttons->addStretch();
hbox_buttons->addWidget(exportButton);
vbox->addLayout(hbox_buttons);
transactionsPage->setLayout(vbox);
- receiveCoinsPage = new ReceiveCoinsDialog();
- sendCoinsPage = new SendCoinsDialog();
+ receiveCoinsPage = new ReceiveCoinsDialog(platformStyle);
+ sendCoinsPage = new SendCoinsDialog(platformStyle);
+
+ usedSendingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
+ usedReceivingAddressesPage = new AddressBookPage(platformStyle, AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
addWidget(overviewPage);
addWidget(transactionsPage);
@@ -114,6 +118,8 @@ void WalletView::setWalletModel(WalletModel *walletModel)
overviewPage->setWalletModel(walletModel);
receiveCoinsPage->setModel(walletModel);
sendCoinsPage->setModel(walletModel);
+ usedReceivingAddressesPage->setModel(walletModel->getAddressTableModel());
+ usedSendingAddressesPage->setModel(walletModel->getAddressTableModel());
if (walletModel)
{
@@ -153,7 +159,7 @@ void WalletView::processNewTransaction(const QModelIndex& parent, int start, int
QString address = ttm->data(index, TransactionTableModel::AddressRole).toString();
QString label = ttm->data(index, TransactionTableModel::LabelRole).toString();
- emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label);
+ Q_EMIT incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address, label);
}
void WalletView::gotoOverviewPage()
@@ -182,7 +188,7 @@ void WalletView::gotoSendCoinsPage(QString addr)
void WalletView::gotoSignMessageTab(QString addr)
{
// calls show() in showTab_SM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
+ SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
signVerifyMessageDialog->setModel(walletModel);
signVerifyMessageDialog->showTab_SM(true);
@@ -194,7 +200,7 @@ void WalletView::gotoSignMessageTab(QString addr)
void WalletView::gotoVerifyMessageTab(QString addr)
{
// calls show() in showTab_VM()
- SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(this);
+ SignVerifyMessageDialog *signVerifyMessageDialog = new SignVerifyMessageDialog(platformStyle, this);
signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
signVerifyMessageDialog->setModel(walletModel);
signVerifyMessageDialog->showTab_VM(true);
@@ -215,7 +221,7 @@ void WalletView::showOutOfSyncWarning(bool fShow)
void WalletView::updateEncryptionStatus()
{
- emit encryptionStatusChanged(walletModel->getEncryptionStatus());
+ Q_EMIT encryptionStatusChanged(walletModel->getEncryptionStatus());
}
void WalletView::encryptWallet(bool status)
@@ -239,11 +245,11 @@ void WalletView::backupWallet()
return;
if (!walletModel->backupWallet(filename)) {
- emit message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
+ Q_EMIT message(tr("Backup Failed"), tr("There was an error trying to save the wallet data to %1.").arg(filename),
CClientUIInterface::MSG_ERROR);
}
else {
- emit message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
+ Q_EMIT message(tr("Backup Successful"), tr("The wallet data was successfully saved to %1.").arg(filename),
CClientUIInterface::MSG_INFORMATION);
}
}
@@ -272,20 +278,20 @@ void WalletView::usedSendingAddresses()
{
if(!walletModel)
return;
- AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::SendingTab, this);
- dlg->setAttribute(Qt::WA_DeleteOnClose);
- dlg->setModel(walletModel->getAddressTableModel());
- dlg->show();
+
+ usedSendingAddressesPage->show();
+ usedSendingAddressesPage->raise();
+ usedSendingAddressesPage->activateWindow();
}
void WalletView::usedReceivingAddresses()
{
if(!walletModel)
return;
- AddressBookPage *dlg = new AddressBookPage(AddressBookPage::ForEditing, AddressBookPage::ReceivingTab, this);
- dlg->setAttribute(Qt::WA_DeleteOnClose);
- dlg->setModel(walletModel->getAddressTableModel());
- dlg->show();
+
+ usedReceivingAddressesPage->show();
+ usedReceivingAddressesPage->raise();
+ usedReceivingAddressesPage->activateWindow();
}
void WalletView::showProgress(const QString &title, int nProgress)
diff --git a/src/qt/walletview.h b/src/qt/walletview.h
index 1840e21e9c..2a6a6a2df2 100644
--- a/src/qt/walletview.h
+++ b/src/qt/walletview.h
@@ -12,11 +12,13 @@
class BitcoinGUI;
class ClientModel;
class OverviewPage;
+class PlatformStyle;
class ReceiveCoinsDialog;
class SendCoinsDialog;
class SendCoinsRecipient;
class TransactionView;
class WalletModel;
+class AddressBookPage;
QT_BEGIN_NAMESPACE
class QModelIndex;
@@ -34,7 +36,7 @@ class WalletView : public QStackedWidget
Q_OBJECT
public:
- explicit WalletView(QWidget *parent);
+ explicit WalletView(const PlatformStyle *platformStyle, QWidget *parent);
~WalletView();
void setBitcoinGUI(BitcoinGUI *gui);
@@ -60,12 +62,15 @@ private:
QWidget *transactionsPage;
ReceiveCoinsDialog *receiveCoinsPage;
SendCoinsDialog *sendCoinsPage;
+ AddressBookPage *usedSendingAddressesPage;
+ AddressBookPage *usedReceivingAddressesPage;
TransactionView *transactionView;
QProgressDialog *progressDialog;
+ const PlatformStyle *platformStyle;
-public slots:
+public Q_SLOTS:
/** Switch to overview (home) page */
void gotoOverviewPage();
/** Switch to history (transactions) page */
@@ -105,7 +110,7 @@ public slots:
/** Show progress dialog e.g. for rescan */
void showProgress(const QString &title, int nProgress);
-signals:
+Q_SIGNALS:
/** Signal that we want to show the main window */
void showNormalIfMinimized();
/** Fired when a message should be reported to the user */
diff --git a/src/rest.cpp b/src/rest.cpp
index 1b7954bbf6..226e237fc6 100644
--- a/src/rest.cpp
+++ b/src/rest.cpp
@@ -3,9 +3,11 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chain.h"
#include "primitives/block.h"
#include "primitives/transaction.h"
#include "main.h"
+#include "httpserver.h"
#include "rpcserver.h"
#include "streams.h"
#include "sync.h"
@@ -16,10 +18,11 @@
#include <boost/algorithm/string.hpp>
#include <boost/dynamic_bitset.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-static const int MAX_GETUTXOS_OUTPOINTS = 100; //allow a max of 100 outpoints to be queried at once
+static const size_t MAX_GETUTXOS_OUTPOINTS = 15; //allow a max of 15 outpoints to be queried at once
enum RetFormat {
RF_UNDEF,
@@ -54,34 +57,38 @@ struct CCoin {
}
};
-class RestErr
-{
-public:
- enum HTTPStatusCode status;
- string message;
-};
-
-extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
-extern Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
-extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
+extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
+extern UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false);
+extern UniValue mempoolInfoToJSON();
+extern UniValue mempoolToJSON(bool fVerbose = false);
+extern void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
+extern UniValue blockheaderToJSON(const CBlockIndex* blockindex);
-static RestErr RESTERR(enum HTTPStatusCode status, string message)
+static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, string message)
{
- RestErr re;
- re.status = status;
- re.message = message;
- return re;
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(status, message + "\r\n");
+ return false;
}
-static enum RetFormat ParseDataFormat(vector<string>& params, const string strReq)
+static enum RetFormat ParseDataFormat(std::string& param, const std::string& strReq)
{
- boost::split(params, strReq, boost::is_any_of("."));
- if (params.size() > 1) {
- for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
- if (params[1] == rf_names[i].name)
- return rf_names[i].rf;
+ const std::string::size_type pos = strReq.rfind('.');
+ if (pos == std::string::npos)
+ {
+ param = strReq;
+ return rf_names[0].rf;
}
+ param = strReq.substr(0, pos);
+ const std::string suff(strReq, pos + 1);
+
+ for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
+ if (suff == rf_names[i].name)
+ return rf_names[i].rf;
+
+ /* If no suffix is found, return original string. */
+ param = strReq;
return rf_names[0].rf;
}
@@ -110,37 +117,44 @@ static bool ParseHashStr(const string& strReq, uint256& v)
return true;
}
-static bool rest_headers(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool CheckWarmup(HTTPRequest* req)
{
- vector<string> params;
- const RetFormat rf = ParseDataFormat(params, strURIPart);
+ std::string statusmessage;
+ if (RPCIsInWarmup(&statusmessage))
+ return RESTERR(req, HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
+ return true;
+}
+
+static bool rest_headers(HTTPRequest* req,
+ const std::string& strURIPart)
+{
+ if (!CheckWarmup(req))
+ return false;
+ std::string param;
+ const RetFormat rf = ParseDataFormat(param, strURIPart);
vector<string> path;
- boost::split(path, params[0], boost::is_any_of("/"));
+ boost::split(path, param, boost::is_any_of("/"));
if (path.size() != 2)
- throw RESTERR(HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
+ return RESTERR(req, HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>.");
long count = strtol(path[0].c_str(), NULL, 10);
if (count < 1 || count > 2000)
- throw RESTERR(HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
+ return RESTERR(req, HTTP_BAD_REQUEST, "Header count out of range: " + path[0]);
string hashStr = path[1];
uint256 hash;
if (!ParseHashStr(hashStr, hash))
- throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
- std::vector<CBlockHeader> headers;
+ std::vector<const CBlockIndex *> headers;
headers.reserve(count);
{
LOCK(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL;
while (pindex != NULL && chainActive.Contains(pindex)) {
- headers.push_back(pindex->GetBlockHeader());
+ headers.push_back(pindex);
if (headers.size() == (unsigned long)count)
break;
pindex = chainActive.Next(pindex);
@@ -148,25 +162,36 @@ static bool rest_headers(AcceptedConnection* conn,
}
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION);
- BOOST_FOREACH(const CBlockHeader &header, headers) {
- ssHeader << header;
+ BOOST_FOREACH(const CBlockIndex *pindex, headers) {
+ ssHeader << pindex->GetBlockHeader();
}
switch (rf) {
case RF_BINARY: {
string binaryHeader = ssHeader.str();
- conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, binaryHeader.size(), "application/octet-stream") << binaryHeader << std::flush;
+ req->WriteHeader("Content-Type", "application/octet-stream");
+ req->WriteReply(HTTP_OK, binaryHeader);
return true;
}
case RF_HEX: {
string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(HTTP_OK, strHex);
+ return true;
+ }
+ case RF_JSON: {
+ UniValue jsonHeaders(UniValue::VARR);
+ BOOST_FOREACH(const CBlockIndex *pindex, headers) {
+ jsonHeaders.push_back(blockheaderToJSON(pindex));
+ }
+ string strJSON = jsonHeaders.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
return true;
}
-
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)");
}
}
@@ -174,34 +199,32 @@ static bool rest_headers(AcceptedConnection* conn,
return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_block(AcceptedConnection* conn,
+static bool rest_block(HTTPRequest* req,
const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun,
bool showTxDetails)
{
- vector<string> params;
- const RetFormat rf = ParseDataFormat(params, strURIPart);
+ if (!CheckWarmup(req))
+ return false;
+ std::string hashStr;
+ const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
- string hashStr = params[0];
uint256 hash;
if (!ParseHashStr(hashStr, hash))
- throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
CBlock block;
CBlockIndex* pblockindex = NULL;
{
LOCK(cs_main);
if (mapBlockIndex.count(hash) == 0)
- throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+ return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
pblockindex = mapBlockIndex[hash];
if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0)
- throw RESTERR(HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
+ return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
if (!ReadBlockFromDisk(block, pblockindex))
- throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+ return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
}
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
@@ -210,25 +233,28 @@ static bool rest_block(AcceptedConnection* conn,
switch (rf) {
case RF_BINARY: {
string binaryBlock = ssBlock.str();
- conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, binaryBlock.size(), "application/octet-stream") << binaryBlock << std::flush;
+ req->WriteHeader("Content-Type", "application/octet-stream");
+ req->WriteReply(HTTP_OK, binaryBlock);
return true;
}
case RF_HEX: {
string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(HTTP_OK, strHex);
return true;
}
case RF_JSON: {
- Object objBlock = blockToJSON(block, pblockindex, showTxDetails);
- string strJSON = write_string(Value(objBlock), false) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ UniValue objBlock = blockToJSON(block, pblockindex, showTxDetails);
+ string strJSON = objBlock.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
return true;
}
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
@@ -236,69 +262,106 @@ static bool rest_block(AcceptedConnection* conn,
return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_block_extended(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool rest_block_extended(HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(conn, strURIPart, strRequest, mapHeaders, fRun, true);
+ return rest_block(req, strURIPart, true);
}
-static bool rest_block_notxdetails(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool rest_block_notxdetails(HTTPRequest* req, const std::string& strURIPart)
+{
+ return rest_block(req, strURIPart, false);
+}
+
+static bool rest_chaininfo(HTTPRequest* req, const std::string& strURIPart)
{
- return rest_block(conn, strURIPart, strRequest, mapHeaders, fRun, false);
+ if (!CheckWarmup(req))
+ return false;
+ std::string param;
+ const RetFormat rf = ParseDataFormat(param, strURIPart);
+
+ switch (rf) {
+ case RF_JSON: {
+ UniValue rpcParams(UniValue::VARR);
+ UniValue chainInfoObject = getblockchaininfo(rpcParams, false);
+ string strJSON = chainInfoObject.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
+ return true;
+ }
+ default: {
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
+ }
+ }
+
+ // not reached
+ return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_chaininfo(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool rest_mempool_info(HTTPRequest* req, const std::string& strURIPart)
{
- vector<string> params;
- const RetFormat rf = ParseDataFormat(params, strURIPart);
-
+ if (!CheckWarmup(req))
+ return false;
+ std::string param;
+ const RetFormat rf = ParseDataFormat(param, strURIPart);
+
switch (rf) {
case RF_JSON: {
- Array rpcParams;
- Value chainInfoObject = getblockchaininfo(rpcParams, false);
-
- string strJSON = write_string(chainInfoObject, false) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ UniValue mempoolInfoObject = mempoolInfoToJSON();
+
+ string strJSON = mempoolInfoObject.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
return true;
}
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: json)");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
}
}
-
+
// not reached
return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_tx(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool rest_mempool_contents(HTTPRequest* req, const std::string& strURIPart)
{
- vector<string> params;
- const RetFormat rf = ParseDataFormat(params, strURIPart);
+ if (!CheckWarmup(req))
+ return false;
+ std::string param;
+ const RetFormat rf = ParseDataFormat(param, strURIPart);
+
+ switch (rf) {
+ case RF_JSON: {
+ UniValue mempoolObject = mempoolToJSON(true);
+
+ string strJSON = mempoolObject.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
+ return true;
+ }
+ default: {
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: json)");
+ }
+ }
+
+ // not reached
+ return true; // continue to process further HTTP reqs on this cxn
+}
+
+static bool rest_tx(HTTPRequest* req, const std::string& strURIPart)
+{
+ if (!CheckWarmup(req))
+ return false;
+ std::string hashStr;
+ const RetFormat rf = ParseDataFormat(hashStr, strURIPart);
- string hashStr = params[0];
uint256 hash;
if (!ParseHashStr(hashStr, hash))
- throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
+ return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
CTransaction tx;
uint256 hashBlock = uint256();
if (!GetTransaction(hash, tx, hashBlock, true))
- throw RESTERR(HTTP_NOT_FOUND, hashStr + " not found");
+ return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
ssTx << tx;
@@ -306,26 +369,29 @@ static bool rest_tx(AcceptedConnection* conn,
switch (rf) {
case RF_BINARY: {
string binaryTx = ssTx.str();
- conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, binaryTx.size(), "application/octet-stream") << binaryTx << std::flush;
+ req->WriteHeader("Content-Type", "application/octet-stream");
+ req->WriteReply(HTTP_OK, binaryTx);
return true;
}
case RF_HEX: {
string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(HTTP_OK, strHex);
return true;
}
case RF_JSON: {
- Object objTx;
+ UniValue objTx(UniValue::VOBJ);
TxToJSON(tx, hashBlock, objTx);
- string strJSON = write_string(Value(objTx), false) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ string strJSON = objTx.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
return true;
}
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
@@ -333,86 +399,99 @@ static bool rest_tx(AcceptedConnection* conn,
return true; // continue to process further HTTP reqs on this cxn
}
-static bool rest_getutxos(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+static bool rest_getutxos(HTTPRequest* req, const std::string& strURIPart)
{
- vector<string> params;
- enum RetFormat rf = ParseDataFormat(params, strURIPart);
+ if (!CheckWarmup(req))
+ return false;
+ std::string param;
+ const RetFormat rf = ParseDataFormat(param, strURIPart);
+
+ vector<string> uriParts;
+ if (param.length() > 1)
+ {
+ std::string strUriParams = param.substr(1);
+ boost::split(uriParts, strUriParams, boost::is_any_of("/"));
+ }
// throw exception in case of a empty request
- if (strRequest.length() == 0)
- throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ std::string strRequestMutable = req->ReadBody();
+ if (strRequestMutable.length() == 0 && uriParts.size() == 0)
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ bool fInputParsed = false;
bool fCheckMemPool = false;
vector<COutPoint> vOutPoints;
// parse/deserialize input
// input-format = output-format, rest/getutxos/bin requires binary input, gives binary output, ...
-
- string strRequestMutable = strRequest; //convert const string to string for allowing hex to bin converting
-
+
+ if (uriParts.size() > 0)
+ {
+
+ //inputs is sent over URI scheme (/rest/getutxos/checkmempool/txid1-n/txid2-n/...)
+ if (uriParts.size() > 0 && uriParts[0] == "checkmempool")
+ fCheckMemPool = true;
+
+ for (size_t i = (fCheckMemPool) ? 1 : 0; i < uriParts.size(); i++)
+ {
+ uint256 txid;
+ int32_t nOutput;
+ std::string strTxid = uriParts[i].substr(0, uriParts[i].find("-"));
+ std::string strOutput = uriParts[i].substr(uriParts[i].find("-")+1);
+
+ if (!ParseInt32(strOutput, &nOutput) || !IsHex(strTxid))
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+
+ txid.SetHex(strTxid);
+ vOutPoints.push_back(COutPoint(txid, (uint32_t)nOutput));
+ }
+
+ if (vOutPoints.size() > 0)
+ fInputParsed = true;
+ else
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
+ }
+
switch (rf) {
case RF_HEX: {
// convert hex to bin, continue then with bin part
- std::vector<unsigned char> strRequestV = ParseHex(strRequest);
+ std::vector<unsigned char> strRequestV = ParseHex(strRequestMutable);
strRequestMutable.assign(strRequestV.begin(), strRequestV.end());
}
case RF_BINARY: {
try {
- //deserialize
- CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
- oss << strRequestMutable;
- oss >> fCheckMemPool;
- oss >> vOutPoints;
+ //deserialize only if user sent a request
+ if (strRequestMutable.size() > 0)
+ {
+ if (fInputParsed) //don't allow sending input over URI and HTTP RAW DATA
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Combination of URI scheme inputs and raw post data is not allowed");
+
+ CDataStream oss(SER_NETWORK, PROTOCOL_VERSION);
+ oss << strRequestMutable;
+ oss >> fCheckMemPool;
+ oss >> vOutPoints;
+ }
} catch (const std::ios_base::failure& e) {
// abort in case of unreadable binary data
- throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Parse error");
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Parse error");
}
break;
}
case RF_JSON: {
- try {
- // parse json request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
- throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Parse error");
-
- Object jsonObject = valRequest.get_obj();
- const Value& checkMempoolValue = find_value(jsonObject, "checkmempool");
-
- if (!checkMempoolValue.is_null()) {
- fCheckMemPool = checkMempoolValue.get_bool();
- }
- const Value& outpointsValue = find_value(jsonObject, "outpoints");
- if (!outpointsValue.is_null()) {
- Array outPoints = outpointsValue.get_array();
- BOOST_FOREACH (const Value& outPoint, outPoints) {
- Object outpointObject = outPoint.get_obj();
- uint256 txid = ParseHashO(outpointObject, "txid");
- Value nValue = find_value(outpointObject, "n");
- int nOutput = nValue.get_int();
- vOutPoints.push_back(COutPoint(txid, nOutput));
- }
- }
- } catch (...) {
- // return HTTP 500 if there was a json parsing error
- throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, "Parse error");
- }
+ if (!fInputParsed)
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, "Error: empty request");
break;
}
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
// limit max outpoints
if (vOutPoints.size() > MAX_GETUTXOS_OUTPOINTS)
- throw RESTERR(HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
+ return RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("Error: max outpoints exceeded (max: %d, tried: %d)", MAX_GETUTXOS_OUTPOINTS, vOutPoints.size()));
// check spentness and form a bitmap (as well as a JSON capable human-readble string representation)
vector<unsigned char> bitmap;
@@ -462,7 +541,8 @@ static bool rest_getutxos(AcceptedConnection* conn,
ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
string ssGetUTXOResponseString = ssGetUTXOResponse.str();
- conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, ssGetUTXOResponseString.size(), "application/octet-stream") << ssGetUTXOResponseString << std::flush;
+ req->WriteHeader("Content-Type", "application/octet-stream");
+ req->WriteReply(HTTP_OK, ssGetUTXOResponseString);
return true;
}
@@ -471,12 +551,13 @@ static bool rest_getutxos(AcceptedConnection* conn,
ssGetUTXOResponse << chainActive.Height() << chainActive.Tip()->GetBlockHash() << bitmap << outs;
string strHex = HexStr(ssGetUTXOResponse.begin(), ssGetUTXOResponse.end()) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
+ req->WriteHeader("Content-Type", "text/plain");
+ req->WriteReply(HTTP_OK, strHex);
return true;
}
case RF_JSON: {
- Object objGetUTXOResponse;
+ UniValue objGetUTXOResponse(UniValue::VOBJ);
// pack in some essentials
// use more or less the same output as mentioned in Bip64
@@ -484,15 +565,15 @@ static bool rest_getutxos(AcceptedConnection* conn,
objGetUTXOResponse.push_back(Pair("chaintipHash", chainActive.Tip()->GetBlockHash().GetHex()));
objGetUTXOResponse.push_back(Pair("bitmap", bitmapStringRepresentation));
- Array utxos;
+ UniValue utxos(UniValue::VARR);
BOOST_FOREACH (const CCoin& coin, outs) {
- Object utxo;
+ UniValue utxo(UniValue::VOBJ);
utxo.push_back(Pair("txvers", (int32_t)coin.nTxVer));
utxo.push_back(Pair("height", (int32_t)coin.nHeight));
utxo.push_back(Pair("value", ValueFromAmount(coin.out.nValue)));
// include the script in a json output
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coin.out.scriptPubKey, o, true);
utxo.push_back(Pair("scriptPubKey", o));
utxos.push_back(utxo);
@@ -500,12 +581,13 @@ static bool rest_getutxos(AcceptedConnection* conn,
objGetUTXOResponse.push_back(Pair("utxos", utxos));
// return json string
- string strJSON = write_string(Value(objGetUTXOResponse), false) + "\n";
- conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
+ string strJSON = objGetUTXOResponse.write() + "\n";
+ req->WriteHeader("Content-Type", "application/json");
+ req->WriteReply(HTTP_OK, strJSON);
return true;
}
default: {
- throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
+ return RESTERR(req, HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
}
}
@@ -515,43 +597,31 @@ static bool rest_getutxos(AcceptedConnection* conn,
static const struct {
const char* prefix;
- bool (*handler)(AcceptedConnection* conn,
- const std::string& strURIPart,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun);
+ bool (*handler)(HTTPRequest* req, const std::string& strReq);
} uri_prefixes[] = {
{"/rest/tx/", rest_tx},
{"/rest/block/notxdetails/", rest_block_notxdetails},
{"/rest/block/", rest_block_extended},
{"/rest/chaininfo", rest_chaininfo},
+ {"/rest/mempool/info", rest_mempool_info},
+ {"/rest/mempool/contents", rest_mempool_contents},
{"/rest/headers/", rest_headers},
{"/rest/getutxos", rest_getutxos},
};
-bool HTTPReq_REST(AcceptedConnection* conn,
- const std::string& strURI,
- const string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun)
+bool StartREST()
{
- try {
- std::string statusmessage;
- if (RPCIsInWarmup(&statusmessage))
- throw RESTERR(HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
-
- for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++) {
- unsigned int plen = strlen(uri_prefixes[i].prefix);
- if (strURI.substr(0, plen) == uri_prefixes[i].prefix) {
- string strURIPart = strURI.substr(plen);
- return uri_prefixes[i].handler(conn, strURIPart, strRequest, mapHeaders, fRun);
- }
- }
- } catch (const RestErr& re) {
- conn->stream() << HTTPReply(re.status, re.message + "\r\n", false, false, "text/plain") << std::flush;
- return false;
- }
+ for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)
+ RegisterHTTPHandler(uri_prefixes[i].prefix, false, uri_prefixes[i].handler);
+ return true;
+}
- conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
- return false;
+void InterruptREST()
+{
+}
+
+void StopREST()
+{
+ for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++)
+ UnregisterHTTPHandler(uri_prefixes[i].prefix, false);
}
diff --git a/src/reverselock.h b/src/reverselock.h
new file mode 100644
index 0000000000..567636e16a
--- /dev/null
+++ b/src/reverselock.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef BITCOIN_REVERSELOCK_H
+#define BITCOIN_REVERSELOCK_H
+
+/**
+ * An RAII-style reverse lock. Unlocks on construction and locks on destruction.
+ */
+template<typename Lock>
+class reverse_lock
+{
+public:
+
+ explicit reverse_lock(Lock& lock) : lock(lock) {
+ lock.unlock();
+ }
+
+ ~reverse_lock() {
+ lock.lock();
+ }
+
+private:
+ reverse_lock(reverse_lock const&);
+ reverse_lock& operator=(reverse_lock const&);
+
+ Lock& lock;
+};
+
+#endif // BITCOIN_REVERSELOCK_H
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index ecf8e8bcc6..1c201ef99d 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -3,21 +3,29 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "amount.h"
+#include "chain.h"
+#include "chainparams.h"
#include "checkpoints.h"
+#include "coins.h"
+#include "consensus/validation.h"
#include "main.h"
+#include "primitives/transaction.h"
#include "rpcserver.h"
+#include "streams.h"
#include "sync.h"
+#include "txmempool.h"
#include "util.h"
+#include "utilstrencodings.h"
#include <stdint.h>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
-extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry);
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex);
+extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry);
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex);
double GetDifficulty(const CBlockIndex* blockindex)
{
@@ -50,10 +58,35 @@ double GetDifficulty(const CBlockIndex* blockindex)
return dDiff;
}
+UniValue blockheaderToJSON(const CBlockIndex* blockindex)
+{
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex()));
+ int confirmations = -1;
+ // Only report confirmations if the block is on the main chain
+ if (chainActive.Contains(blockindex))
+ confirmations = chainActive.Height() - blockindex->nHeight + 1;
+ result.push_back(Pair("confirmations", confirmations));
+ result.push_back(Pair("height", blockindex->nHeight));
+ result.push_back(Pair("version", blockindex->nVersion));
+ result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex()));
+ result.push_back(Pair("time", (int64_t)blockindex->nTime));
+ result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce));
+ result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits)));
+ result.push_back(Pair("difficulty", GetDifficulty(blockindex)));
+ result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex()));
-Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
+ if (blockindex->pprev)
+ result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
+ CBlockIndex *pnext = chainActive.Next(blockindex);
+ if (pnext)
+ result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
+ return result;
+}
+
+UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false)
{
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hash", block.GetHash().GetHex()));
int confirmations = -1;
// Only report confirmations if the block is on the main chain
@@ -64,12 +97,12 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
result.push_back(Pair("height", blockindex->nHeight));
result.push_back(Pair("version", block.nVersion));
result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex()));
- Array txs;
+ UniValue txs(UniValue::VARR);
BOOST_FOREACH(const CTransaction&tx, block.vtx)
{
if(txDetails)
{
- Object objTx;
+ UniValue objTx(UniValue::VOBJ);
TxToJSON(tx, uint256(), objTx);
txs.push_back(objTx);
}
@@ -91,8 +124,7 @@ Object blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDe
return result;
}
-
-Value getblockcount(const Array& params, bool fHelp)
+UniValue getblockcount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -109,7 +141,7 @@ Value getblockcount(const Array& params, bool fHelp)
return chainActive.Height();
}
-Value getbestblockhash(const Array& params, bool fHelp)
+UniValue getbestblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -126,7 +158,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
return chainActive.Tip()->GetBlockHash().GetHex();
}
-Value getdifficulty(const Array& params, bool fHelp)
+UniValue getdifficulty(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -143,8 +175,58 @@ Value getdifficulty(const Array& params, bool fHelp)
return GetDifficulty();
}
+UniValue mempoolToJSON(bool fVerbose = false)
+{
+ if (fVerbose)
+ {
+ LOCK(mempool.cs);
+ UniValue o(UniValue::VOBJ);
+ BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx)
+ {
+ const uint256& hash = e.GetTx().GetHash();
+ UniValue info(UniValue::VOBJ);
+ info.push_back(Pair("size", (int)e.GetTxSize()));
+ info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
+ info.push_back(Pair("time", e.GetTime()));
+ info.push_back(Pair("height", (int)e.GetHeight()));
+ info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
+ info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
+ info.push_back(Pair("descendantcount", e.GetCountWithDescendants()));
+ info.push_back(Pair("descendantsize", e.GetSizeWithDescendants()));
+ info.push_back(Pair("descendantfees", e.GetFeesWithDescendants()));
+ const CTransaction& tx = e.GetTx();
+ set<string> setDepends;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ {
+ if (mempool.exists(txin.prevout.hash))
+ setDepends.insert(txin.prevout.hash.ToString());
+ }
-Value getrawmempool(const Array& params, bool fHelp)
+ UniValue depends(UniValue::VARR);
+ BOOST_FOREACH(const string& dep, setDepends)
+ {
+ depends.push_back(dep);
+ }
+
+ info.push_back(Pair("depends", depends));
+ o.push_back(Pair(hash.ToString(), info));
+ }
+ return o;
+ }
+ else
+ {
+ vector<uint256> vtxid;
+ mempool.queryHashes(vtxid);
+
+ UniValue a(UniValue::VARR);
+ BOOST_FOREACH(const uint256& hash, vtxid)
+ a.push_back(hash.ToString());
+
+ return a;
+ }
+}
+
+UniValue getrawmempool(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -161,16 +243,19 @@ Value getrawmempool(const Array& params, bool fHelp)
"{ (json object)\n"
" \"transactionid\" : { (json object)\n"
" \"size\" : n, (numeric) transaction size in bytes\n"
- " \"fee\" : n, (numeric) transaction fee in bitcoins\n"
+ " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n"
" \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n"
" \"height\" : n, (numeric) block height when transaction entered pool\n"
" \"startingpriority\" : n, (numeric) priority when transaction entered pool\n"
" \"currentpriority\" : n, (numeric) transaction priority now\n"
+ " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n"
+ " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n"
+ " \"descendantfees\" : n, (numeric) fees of in-mempool descendants (including this one)\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ]\n"
" }, ...\n"
- "]\n"
+ "}\n"
"\nExamples\n"
+ HelpExampleCli("getrawmempool", "true")
+ HelpExampleRpc("getrawmempool", "true")
@@ -182,48 +267,10 @@ Value getrawmempool(const Array& params, bool fHelp)
if (params.size() > 0)
fVerbose = params[0].get_bool();
- if (fVerbose)
- {
- LOCK(mempool.cs);
- Object o;
- BOOST_FOREACH(const PAIRTYPE(uint256, CTxMemPoolEntry)& entry, mempool.mapTx)
- {
- const uint256& hash = entry.first;
- const CTxMemPoolEntry& e = entry.second;
- Object info;
- info.push_back(Pair("size", (int)e.GetTxSize()));
- info.push_back(Pair("fee", ValueFromAmount(e.GetFee())));
- info.push_back(Pair("time", e.GetTime()));
- info.push_back(Pair("height", (int)e.GetHeight()));
- info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight())));
- info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height())));
- const CTransaction& tx = e.GetTx();
- set<string> setDepends;
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- {
- if (mempool.exists(txin.prevout.hash))
- setDepends.insert(txin.prevout.hash.ToString());
- }
- Array depends(setDepends.begin(), setDepends.end());
- info.push_back(Pair("depends", depends));
- o.push_back(Pair(hash.ToString(), info));
- }
- return o;
- }
- else
- {
- vector<uint256> vtxid;
- mempool.queryHashes(vtxid);
-
- Array a;
- BOOST_FOREACH(const uint256& hash, vtxid)
- a.push_back(hash.ToString());
-
- return a;
- }
+ return mempoolToJSON(fVerbose);
}
-Value getblockhash(const Array& params, bool fHelp)
+UniValue getblockhash(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -248,7 +295,63 @@ Value getblockhash(const Array& params, bool fHelp)
return pblockindex->GetBlockHash().GetHex();
}
-Value getblock(const Array& params, bool fHelp)
+UniValue getblockheader(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "getblockheader \"hash\" ( verbose )\n"
+ "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
+ "If verbose is true, returns an Object with information about blockheader <hash>.\n"
+ "\nArguments:\n"
+ "1. \"hash\" (string, required) The block hash\n"
+ "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
+ "\nResult (for verbose = true):\n"
+ "{\n"
+ " \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
+ " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
+ " \"height\" : n, (numeric) The block height or index\n"
+ " \"version\" : n, (numeric) The block version\n"
+ " \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
+ " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"nonce\" : n, (numeric) The nonce\n"
+ " \"bits\" : \"1d00ffff\", (string) The bits\n"
+ " \"difficulty\" : x.xxx, (numeric) The difficulty\n"
+ " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n"
+ " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n"
+ "}\n"
+ "\nResult (for verbose=false):\n"
+ "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
+ );
+
+ LOCK(cs_main);
+
+ std::string strHash = params[0].get_str();
+ uint256 hash(uint256S(strHash));
+
+ bool fVerbose = true;
+ if (params.size() > 1)
+ fVerbose = params[1].get_bool();
+
+ if (mapBlockIndex.count(hash) == 0)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
+
+ CBlockIndex* pblockindex = mapBlockIndex[hash];
+
+ if (!fVerbose)
+ {
+ CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
+ ssBlock << pblockindex->GetBlockHeader();
+ std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
+ return strHex;
+ }
+
+ return blockheaderToJSON(pblockindex);
+}
+
+UniValue getblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -316,7 +419,7 @@ Value getblock(const Array& params, bool fHelp)
return blockToJSON(block, pblockindex);
}
-Value gettxoutsetinfo(const Array& params, bool fHelp)
+UniValue gettxoutsetinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -338,9 +441,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxoutsetinfo", "")
);
- LOCK(cs_main);
-
- Object ret;
+ UniValue ret(UniValue::VOBJ);
CCoinsStats stats;
FlushStateToDisk();
@@ -356,7 +457,7 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
return ret;
}
-Value gettxout(const Array& params, bool fHelp)
+UniValue gettxout(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 3)
throw runtime_error(
@@ -370,7 +471,7 @@ Value gettxout(const Array& params, bool fHelp)
"{\n"
" \"bestblock\" : \"hash\", (string) the block hash\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
- " \"value\" : x.xxx, (numeric) The transaction value in btc\n"
+ " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"code\", (string) \n"
" \"hex\" : \"hex\", (string) \n"
@@ -396,7 +497,7 @@ Value gettxout(const Array& params, bool fHelp)
LOCK(cs_main);
- Object ret;
+ UniValue ret(UniValue::VOBJ);
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
@@ -410,14 +511,14 @@ Value gettxout(const Array& params, bool fHelp)
LOCK(mempool.cs);
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(hash, coins))
- return Value::null;
+ return NullUniValue;
mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool
} else {
if (!pcoinsTip->GetCoins(hash, coins))
- return Value::null;
+ return NullUniValue;
}
if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull())
- return Value::null;
+ return NullUniValue;
BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock());
CBlockIndex *pindex = it->second;
@@ -427,7 +528,7 @@ Value gettxout(const Array& params, bool fHelp)
else
ret.push_back(Pair("confirmations", pindex->nHeight - coins.nHeight + 1));
ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue)));
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true);
ret.push_back(Pair("scriptPubKey", o));
ret.push_back(Pair("version", coins.nVersion));
@@ -436,7 +537,7 @@ Value gettxout(const Array& params, bool fHelp)
return ret;
}
-Value verifychain(const Array& params, bool fHelp)
+UniValue verifychain(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -464,7 +565,37 @@ Value verifychain(const Array& params, bool fHelp)
return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth);
}
-Value getblockchaininfo(const Array& params, bool fHelp)
+/** Implementation of IsSuperMajority with better feedback */
+static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams)
+{
+ int nFound = 0;
+ CBlockIndex* pstart = pindex;
+ for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++)
+ {
+ if (pstart->nVersion >= minVersion)
+ ++nFound;
+ pstart = pstart->pprev;
+ }
+
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("status", nFound >= nRequired));
+ rv.push_back(Pair("found", nFound));
+ rv.push_back(Pair("required", nRequired));
+ rv.push_back(Pair("window", consensusParams.nMajorityWindow));
+ return rv;
+}
+
+static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams)
+{
+ UniValue rv(UniValue::VOBJ);
+ rv.push_back(Pair("id", name));
+ rv.push_back(Pair("version", version));
+ rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams)));
+ rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams)));
+ return rv;
+}
+
+UniValue getblockchaininfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -479,6 +610,21 @@ Value getblockchaininfo(const Array& params, bool fHelp)
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
+ " \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
+ " \"pruneheight\": xxxxxx, (numeric) heighest block available\n"
+ " \"softforks\": [ (array) status of softforks in progress\n"
+ " {\n"
+ " \"id\": \"xxxx\", (string) name of softfork\n"
+ " \"version\": xx, (numeric) block version\n"
+ " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n"
+ " \"status\": xx, (boolean) true if threshold reached\n"
+ " \"found\": xx, (numeric) number of blocks with the new version found\n"
+ " \"required\": xx, (numeric) number of blocks required to trigger\n"
+ " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n"
+ " },\n"
+ " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n"
+ " }, ...\n"
+ " ]\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getblockchaininfo", "")
@@ -487,7 +633,7 @@ Value getblockchaininfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1));
@@ -496,6 +642,14 @@ Value getblockchaininfo(const Array& params, bool fHelp)
obj.push_back(Pair("verificationprogress", Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.Tip())));
obj.push_back(Pair("chainwork", chainActive.Tip()->nChainWork.GetHex()));
obj.push_back(Pair("pruned", fPruneMode));
+
+ const Consensus::Params& consensusParams = Params().GetConsensus();
+ CBlockIndex* tip = chainActive.Tip();
+ UniValue softforks(UniValue::VARR);
+ softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams));
+ softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams));
+ obj.push_back(Pair("softforks", softforks));
+
if (fPruneMode)
{
CBlockIndex *block = chainActive.Tip();
@@ -522,7 +676,7 @@ struct CompareBlocksByHeight
}
};
-Value getchaintips(const Array& params, bool fHelp)
+UniValue getchaintips(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -574,10 +728,10 @@ Value getchaintips(const Array& params, bool fHelp)
setTips.insert(chainActive.Tip());
/* Construct the output array. */
- Array res;
+ UniValue res(UniValue::VARR);
BOOST_FOREACH(const CBlockIndex* block, setTips)
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("height", block->nHeight));
obj.push_back(Pair("hash", block->phashBlock->GetHex()));
@@ -612,7 +766,17 @@ Value getchaintips(const Array& params, bool fHelp)
return res;
}
-Value getmempoolinfo(const Array& params, bool fHelp)
+UniValue mempoolInfoToJSON()
+{
+ UniValue ret(UniValue::VOBJ);
+ ret.push_back(Pair("size", (int64_t) mempool.size()));
+ ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
+ ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage()));
+
+ return ret;
+}
+
+UniValue getmempoolinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -622,20 +786,17 @@ Value getmempoolinfo(const Array& params, bool fHelp)
"{\n"
" \"size\": xxxxx (numeric) Current tx count\n"
" \"bytes\": xxxxx (numeric) Sum of all tx sizes\n"
+ " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getmempoolinfo", "")
+ HelpExampleRpc("getmempoolinfo", "")
);
- Object ret;
- ret.push_back(Pair("size", (int64_t) mempool.size()));
- ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize()));
-
- return ret;
+ return mempoolInfoToJSON();
}
-Value invalidateblock(const Array& params, bool fHelp)
+UniValue invalidateblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -670,10 +831,10 @@ Value invalidateblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}
- return Value::null;
+ return NullUniValue;
}
-Value reconsiderblock(const Array& params, bool fHelp)
+UniValue reconsiderblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -709,5 +870,5 @@ Value reconsiderblock(const Array& params, bool fHelp)
throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason());
}
- return Value::null;
+ return NullUniValue;
}
diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp
index 4b576b3707..0c8e6d6d66 100644
--- a/src/rpcclient.cpp
+++ b/src/rpcclient.cpp
@@ -11,8 +11,10 @@
#include <set>
#include <stdint.h>
+#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
class CRPCConvertParam
{
@@ -69,6 +71,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "listunspent", 1 },
{ "listunspent", 2 },
{ "getblock", 1 },
+ { "getblockheader", 1 },
{ "gettransaction", 1 },
{ "getrawtransaction", 1 },
{ "createrawtransaction", 0 },
@@ -76,6 +79,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "signrawtransaction", 1 },
{ "signrawtransaction", 2 },
{ "sendrawtransaction", 1 },
+ { "fundrawtransaction", 1 },
{ "gettxout", 1 },
{ "gettxout", 2 },
{ "gettxoutproof", 0 },
@@ -83,6 +87,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "lockunspent", 1 },
{ "importprivkey", 2 },
{ "importaddress", 2 },
+ { "importaddress", 3 },
+ { "importpubkey", 2 },
{ "verifychain", 0 },
{ "verifychain", 1 },
{ "keypoolrefill", 0 },
@@ -91,6 +97,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "estimatepriority", 0 },
{ "prioritisetransaction", 1 },
{ "prioritisetransaction", 2 },
+ { "setban", 2 },
+ { "setban", 3 },
};
class CRPCConvertTable
@@ -119,25 +127,32 @@ CRPCConvertTable::CRPCConvertTable()
static CRPCConvertTable rpcCvtTable;
+/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
+ * as well as objects and arrays.
+ */
+UniValue ParseNonRFCJSONValue(const std::string& strVal)
+{
+ UniValue jVal;
+ if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
+ !jVal.isArray() || jVal.size()!=1)
+ throw runtime_error(string("Error parsing JSON:")+strVal);
+ return jVal[0];
+}
+
/** Convert strings to command-specific RPC representation */
-Array RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
+UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
- Array params;
+ UniValue params(UniValue::VARR);
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
const std::string& strVal = strParams[idx];
- // insert string value directly
if (!rpcCvtTable.convert(strMethod, idx)) {
+ // insert string value directly
params.push_back(strVal);
- }
-
- // parse string as JSON, insert bool/number/object/etc. value
- else {
- Value jVal;
- if (!read_string(strVal, jVal))
- throw runtime_error(string("Error parsing JSON:")+strVal);
- params.push_back(jVal);
+ } else {
+ // parse string as JSON, insert bool/number/object/etc. value
+ params.push_back(ParseNonRFCJSONValue(strVal));
}
}
diff --git a/src/rpcclient.h b/src/rpcclient.h
index 42fa2d06fe..d68b4ed6ae 100644
--- a/src/rpcclient.h
+++ b/src/rpcclient.h
@@ -6,10 +6,12 @@
#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include "univalue/univalue.h"
-json_spirit::Array RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
+/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
+ * as well as objects and arrays.
+ */
+UniValue ParseNonRFCJSONValue(const std::string& strVal);
#endif // BITCOIN_RPCCLIENT_H
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 24b865150a..91de37fdcc 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -4,8 +4,10 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h"
+#include "chain.h"
#include "chainparams.h"
#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
#include "main.h"
@@ -13,21 +15,18 @@
#include "net.h"
#include "pow.h"
#include "rpcserver.h"
+#include "txmempool.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "validationinterface.h"
-#ifdef ENABLE_WALLET
-#include "wallet/db.h"
-#include "wallet/wallet.h"
-#endif
#include <stdint.h>
#include <boost/assign/list_of.hpp>
+#include <boost/shared_ptr.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
/**
@@ -35,7 +34,7 @@ using namespace std;
* or from the last difficulty change if 'lookup' is nonpositive.
* If 'height' is nonnegative, compute the estimate at the time when a given block was found.
*/
-Value GetNetworkHashPS(int lookup, int height) {
+UniValue GetNetworkHashPS(int lookup, int height) {
CBlockIndex *pb = chainActive.Tip();
if (height >= 0 && height < chainActive.Height())
@@ -72,7 +71,7 @@ Value GetNetworkHashPS(int lookup, int height) {
return (int64_t)(workDiff.getdouble() / timeDiff);
}
-Value getnetworkhashps(const Array& params, bool fHelp)
+UniValue getnetworkhashps(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -94,8 +93,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
-#ifdef ENABLE_WALLET
-Value getgenerate(const Array& params, bool fHelp)
+UniValue getgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -114,14 +112,14 @@ Value getgenerate(const Array& params, bool fHelp)
return GetBoolArg("-gen", false);
}
-Value generate(const Array& params, bool fHelp)
+UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"generate numblocks\n"
"\nMine blocks immediately (before the RPC call returns)\n"
"\nNote: this function can only be used on the regtest network\n"
- "1. numblocks (numeric) How many blocks are generated immediately.\n"
+ "1. numblocks (numeric, required) How many blocks are generated immediately.\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
@@ -129,8 +127,6 @@ Value generate(const Array& params, bool fHelp)
+ HelpExampleCli("generate", "11")
);
- if (pwalletMain == NULL)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (!Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest");
@@ -138,7 +134,17 @@ Value generate(const Array& params, bool fHelp)
int nHeightEnd = 0;
int nHeight = 0;
int nGenerate = params[0].get_int();
- CReserveKey reservekey(pwalletMain);
+
+ boost::shared_ptr<CReserveScript> coinbaseScript;
+ GetMainSignals().ScriptForMining(coinbaseScript);
+
+ // If the keypool is exhausted, no script is returned at all. Catch this.
+ if (!coinbaseScript)
+ throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
+
+ //throw an error if no script was provided
+ if (coinbaseScript->reserveScript.empty())
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "No coinbase script available (mining requires a wallet)");
{ // Don't keep cs_main locked
LOCK(cs_main);
@@ -147,12 +153,12 @@ Value generate(const Array& params, bool fHelp)
nHeightEnd = nHeightStart+nGenerate;
}
unsigned int nExtraNonce = 0;
- Array blockHashes;
+ UniValue blockHashes(UniValue::VARR);
while (nHeight < nHeightEnd)
{
- auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));
+ auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet keypool empty");
+ throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
@@ -164,16 +170,18 @@ Value generate(const Array& params, bool fHelp)
++pblock->nNonce;
}
CValidationState state;
- if (!ProcessNewBlock(state, NULL, pblock))
+ if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
blockHashes.push_back(pblock->GetHash().GetHex());
+
+ //mark script as important because it was used at least for one coinbase output
+ coinbaseScript->KeepScript();
}
return blockHashes;
}
-
-Value setgenerate(const Array& params, bool fHelp)
+UniValue setgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -195,8 +203,6 @@ Value setgenerate(const Array& params, bool fHelp)
+ HelpExampleRpc("setgenerate", "true, 1")
);
- if (pwalletMain == NULL)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network");
@@ -214,14 +220,12 @@ Value setgenerate(const Array& params, bool fHelp)
mapArgs["-gen"] = (fGenerate ? "1" : "0");
mapArgs ["-genproclimit"] = itostr(nGenProcLimit);
- GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
+ GenerateBitcoins(fGenerate, nGenProcLimit, Params());
- return Value::null;
+ return NullUniValue;
}
-#endif
-
-Value getmininginfo(const Array& params, bool fHelp)
+UniValue getmininginfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -248,7 +252,7 @@ Value getmininginfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
@@ -259,15 +263,13 @@ Value getmininginfo(const Array& params, bool fHelp)
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
-#ifdef ENABLE_WALLET
obj.push_back(Pair("generate", getgenerate(params, false)));
-#endif
return obj;
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
-Value prioritisetransaction(const Array& params, bool fHelp)
+UniValue prioritisetransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
@@ -299,10 +301,10 @@ Value prioritisetransaction(const Array& params, bool fHelp)
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
-static Value BIP22ValidationResult(const CValidationState& state)
+static UniValue BIP22ValidationResult(const CValidationState& state)
{
if (state.IsValid())
- return Value::null;
+ return NullUniValue;
std::string strRejectReason = state.GetRejectReason();
if (state.IsError())
@@ -317,7 +319,7 @@ static Value BIP22ValidationResult(const CValidationState& state)
return "valid?";
}
-Value getblocktemplate(const Array& params, bool fHelp)
+UniValue getblocktemplate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -382,14 +384,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
LOCK(cs_main);
std::string strMode = "template";
- Value lpval = Value::null;
+ UniValue lpval = NullUniValue;
if (params.size() > 0)
{
- const Object& oparam = params[0].get_obj();
- const Value& modeval = find_value(oparam, "mode");
- if (modeval.type() == str_type)
+ const UniValue& oparam = params[0].get_obj();
+ const UniValue& modeval = find_value(oparam, "mode");
+ if (modeval.isStr())
strMode = modeval.get_str();
- else if (modeval.type() == null_type)
+ else if (modeval.isNull())
{
/* Do nothing */
}
@@ -399,8 +401,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
if (strMode == "proposal")
{
- const Value& dataval = find_value(oparam, "data");
- if (dataval.type() != str_type)
+ const UniValue& dataval = find_value(oparam, "data");
+ if (!dataval.isStr())
throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
CBlock block;
@@ -439,14 +441,14 @@ Value getblocktemplate(const Array& params, bool fHelp)
static unsigned int nTransactionsUpdatedLast;
- if (lpval.type() != null_type)
+ if (!lpval.isNull())
{
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
boost::system_time checktxtime;
unsigned int nTransactionsUpdatedLastLP;
- if (lpval.type() == str_type)
+ if (lpval.isStr())
{
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
@@ -520,26 +522,25 @@ Value getblocktemplate(const Array& params, bool fHelp)
UpdateTime(pblock, Params().GetConsensus(), pindexPrev);
pblock->nNonce = 0;
- static const Array aCaps = boost::assign::list_of("proposal");
+ UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
- Array transactions;
+ UniValue transactions(UniValue::VARR);
map<uint256, int64_t> setTxIndex;
int i = 0;
- BOOST_FOREACH (CTransaction& tx, pblock->vtx)
- {
+ BOOST_FOREACH (const CTransaction& tx, pblock->vtx) {
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
if (tx.IsCoinBase())
continue;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("data", EncodeHexTx(tx)));
entry.push_back(Pair("hash", txHash.GetHex()));
- Array deps;
+ UniValue deps(UniValue::VARR);
BOOST_FOREACH (const CTxIn &in, tx.vin)
{
if (setTxIndex.count(in.prevout.hash))
@@ -554,12 +555,12 @@ Value getblocktemplate(const Array& params, bool fHelp)
transactions.push_back(entry);
}
- Object aux;
+ UniValue aux(UniValue::VOBJ);
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
- static Array aMutable;
+ static UniValue aMutable(UniValue::VARR);
if (aMutable.empty())
{
aMutable.push_back("time");
@@ -567,7 +568,7 @@ Value getblocktemplate(const Array& params, bool fHelp)
aMutable.push_back("prevblock");
}
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("capabilities", aCaps));
result.push_back(Pair("version", pblock->nVersion));
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
@@ -606,7 +607,7 @@ protected:
};
};
-Value submitblock(const Array& params, bool fHelp)
+UniValue submitblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -650,7 +651,7 @@ Value submitblock(const Array& params, bool fHelp)
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
- bool fAccepted = ProcessNewBlock(state, NULL, &block);
+ bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL);
UnregisterValidationInterface(&sc);
if (fBlockPresent)
{
@@ -667,26 +668,25 @@ Value submitblock(const Array& params, bool fHelp)
return BIP22ValidationResult(state);
}
-Value estimatefee(const Array& params, bool fHelp)
+UniValue estimatefee(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatefee nblocks\n"
- "\nEstimates the approximate fee per kilobyte\n"
- "needed for a transaction to begin confirmation\n"
- "within nblocks blocks.\n"
+ "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
+ "confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
- "n : (numeric) estimated fee-per-kilobyte\n"
+ "n (numeric) estimated fee-per-kilobyte\n"
"\n"
- "-1.0 is returned if not enough transactions and\n"
- "blocks have been observed to make an estimate.\n"
+ "A negative value is returned if not enough transactions and blocks\n"
+ "have been observed to make an estimate.\n"
"\nExample:\n"
+ HelpExampleCli("estimatefee", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
@@ -699,26 +699,25 @@ Value estimatefee(const Array& params, bool fHelp)
return ValueFromAmount(feeRate.GetFeePerK());
}
-Value estimatepriority(const Array& params, bool fHelp)
+UniValue estimatepriority(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
- "\nEstimates the approximate priority\n"
- "a zero-fee transaction needs to begin confirmation\n"
- "within nblocks blocks.\n"
+ "\nEstimates the approximate priority a zero-fee transaction needs to begin\n"
+ "confirmation within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
- "n : (numeric) estimated priority\n"
+ "n (numeric) estimated priority\n"
"\n"
- "-1.0 is returned if not enough transactions and\n"
- "blocks have been observed to make an estimate.\n"
+ "A negative value is returned if not enough transactions and blocks\n"
+ "have been observed to make an estimate.\n"
"\nExample:\n"
+ HelpExampleCli("estimatepriority", "6")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index f5bef2a077..e2b6d5826c 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -12,6 +12,7 @@
#include "rpcserver.h"
#include "timedata.h"
#include "util.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
@@ -20,10 +21,9 @@
#include <stdint.h>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
-using namespace json_spirit;
+#include "univalue/univalue.h"
+
using namespace std;
/**
@@ -39,7 +39,7 @@ using namespace std;
*
* Or alternatively, create a specific query method for the information.
**/
-Value getinfo(const Array& params, bool fHelp)
+UniValue getinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -60,8 +60,8 @@ Value getinfo(const Array& params, bool fHelp)
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
- " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in btc/kb\n"
- " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee set in " + CURRENCY_UNIT + "/kB\n"
+ " \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n"
@@ -78,7 +78,7 @@ Value getinfo(const Array& params, bool fHelp)
proxyType proxy;
GetProxy(NET_IPV4, proxy);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET
@@ -108,41 +108,34 @@ Value getinfo(const Array& params, bool fHelp)
}
#ifdef ENABLE_WALLET
-class DescribeAddressVisitor : public boost::static_visitor<Object>
+class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
-private:
- isminetype mine;
-
public:
- DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
+ UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
- Object operator()(const CNoDestination &dest) const { return Object(); }
-
- Object operator()(const CKeyID &keyID) const {
- Object obj;
+ UniValue operator()(const CKeyID &keyID) const {
+ UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
- if (mine == ISMINE_SPENDABLE) {
- pwalletMain->GetPubKey(keyID, vchPubKey);
+ if (pwalletMain->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
return obj;
}
- Object operator()(const CScriptID &scriptID) const {
- Object obj;
+ UniValue operator()(const CScriptID &scriptID) const {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
obj.push_back(Pair("isscript", true));
- if (mine != ISMINE_NO) {
- CScript subscript;
- pwalletMain->GetCScript(scriptID, subscript);
+ if (pwalletMain->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
- Array a;
+ UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
@@ -154,7 +147,7 @@ public:
};
#endif
-Value validateaddress(const Array& params, bool fHelp)
+UniValue validateaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -164,13 +157,14 @@ Value validateaddress(const Array& params, bool fHelp)
"1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n"
"\nResult:\n"
"{\n"
- " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
+ " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
- " \"ismine\" : true|false, (boolean) If the address is yours or not\n"
- " \"isscript\" : true|false, (boolean) If the key is a script\n"
+ " \"ismine\" : true|false, (boolean) If the address is yours or not\n"
+ " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
+ " \"isscript\" : true|false, (boolean) If the key is a script\n"
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
- " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
+ " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
" \"account\" : \"account\" (string) DEPRECATED. The account associated with the address, \"\" is the default account\n"
"}\n"
"\nExamples:\n"
@@ -187,7 +181,7 @@ Value validateaddress(const Array& params, bool fHelp)
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
- Object ret;
+ UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid)
{
@@ -201,11 +195,9 @@ Value validateaddress(const Array& params, bool fHelp)
#ifdef ENABLE_WALLET
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
- if (mine != ISMINE_NO) {
- ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
- Object detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
- ret.insert(ret.end(), detail.begin(), detail.end());
- }
+ ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
+ UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest);
+ ret.pushKVs(detail);
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
@@ -216,10 +208,10 @@ Value validateaddress(const Array& params, bool fHelp)
/**
* Used by addmultisigaddress / createmultisig:
*/
-CScript _createmultisig_redeemScript(const Array& params)
+CScript _createmultisig_redeemScript(const UniValue& params)
{
int nRequired = params[0].get_int();
- const Array& keys = params[1].get_array();
+ const UniValue& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
@@ -277,7 +269,7 @@ CScript _createmultisig_redeemScript(const Array& params)
return result;
}
-Value createmultisig(const Array& params, bool fHelp)
+UniValue createmultisig(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 2)
{
@@ -313,14 +305,14 @@ Value createmultisig(const Array& params, bool fHelp)
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("address", address.ToString()));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
}
-Value verifymessage(const Array& params, bool fHelp)
+UniValue verifymessage(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
@@ -374,7 +366,7 @@ Value verifymessage(const Array& params, bool fHelp)
return (pubkey.GetID() == keyID);
}
-Value setmocktime(const Array& params, bool fHelp)
+UniValue setmocktime(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -388,10 +380,19 @@ Value setmocktime(const Array& params, bool fHelp)
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
- LOCK(cs_main);
+ // cs_vNodes is locked and node send/receive times are updated
+ // atomically with the time change to prevent peers from being
+ // disconnected because we think we haven't communicated with them
+ // in a long time.
+ LOCK2(cs_main, cs_vNodes);
- RPCTypeCheck(params, boost::assign::list_of(int_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64());
- return Value::null;
+ uint64_t t = GetTime();
+ BOOST_FOREACH(CNode* pnode, vNodes) {
+ pnode->nLastSend = pnode->nLastRecv = t;
+ }
+
+ return NullUniValue;
}
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index bdee5b9f2e..5d490c70ca 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -4,6 +4,7 @@
#include "rpcserver.h"
+#include "chainparams.h"
#include "clientversion.h"
#include "main.h"
#include "net.h"
@@ -11,17 +12,18 @@
#include "protocol.h"
#include "sync.h"
#include "timedata.h"
+#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "version.h"
#include <boost/foreach.hpp>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
-using namespace json_spirit;
using namespace std;
-Value getconnectioncount(const Array& params, bool fHelp)
+UniValue getconnectioncount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -39,7 +41,7 @@ Value getconnectioncount(const Array& params, bool fHelp)
return (int)vNodes.size();
}
-Value ping(const Array& params, bool fHelp)
+UniValue ping(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -59,7 +61,7 @@ Value ping(const Array& params, bool fHelp)
pNode->fPingQueued = true;
}
- return Value::null;
+ return NullUniValue;
}
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
@@ -75,7 +77,7 @@ static void CopyNodeStats(std::vector<CNodeStats>& vstats)
}
}
-Value getpeerinfo(const Array& params, bool fHelp)
+UniValue getpeerinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -95,6 +97,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
" \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"timeoffset\": ttt, (numeric) The time offset in seconds\n"
" \"pingtime\": n, (numeric) ping time\n"
+ " \"minping\": n, (numeric) minimum observed ping time\n"
" \"pingwait\": n, (numeric) ping wait\n"
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Satoshi:0.8.5/\", (string) The string version\n"
@@ -120,10 +123,10 @@ Value getpeerinfo(const Array& params, bool fHelp)
vector<CNodeStats> vstats;
CopyNodeStats(vstats);
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(const CNodeStats& stats, vstats) {
- Object obj;
+ UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj.push_back(Pair("id", stats.nodeid));
@@ -138,6 +141,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("conntime", stats.nTimeConnected));
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
obj.push_back(Pair("pingtime", stats.dPingTime));
+ obj.push_back(Pair("minping", stats.dPingMin));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
@@ -151,7 +155,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
obj.push_back(Pair("banscore", statestats.nMisbehavior));
obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
- Array heights;
+ UniValue heights(UniValue::VARR);
BOOST_FOREACH(int height, statestats.vHeightInFlight) {
heights.push_back(height);
}
@@ -165,7 +169,7 @@ Value getpeerinfo(const Array& params, bool fHelp)
return ret;
}
-Value addnode(const Array& params, bool fHelp)
+UniValue addnode(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() == 2)
@@ -190,7 +194,7 @@ Value addnode(const Array& params, bool fHelp)
{
CAddress addr;
OpenNetworkConnection(addr, NULL, strNode.c_str());
- return Value::null;
+ return NullUniValue;
}
LOCK(cs_vAddedNodes);
@@ -212,10 +216,32 @@ Value addnode(const Array& params, bool fHelp)
vAddedNodes.erase(it);
}
- return Value::null;
+ return NullUniValue;
}
-Value getaddednodeinfo(const Array& params, bool fHelp)
+UniValue disconnectnode(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 1)
+ throw runtime_error(
+ "disconnectnode \"node\" \n"
+ "\nImmediately disconnects from the specified node.\n"
+ "\nArguments:\n"
+ "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
+ "\nExamples:\n"
+ + HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ + HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
+ );
+
+ CNode* pNode = FindNode(params[0].get_str());
+ if (pNode == NULL)
+ throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
+
+ pNode->fDisconnect = true;
+
+ return NullUniValue;
+}
+
+UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -254,29 +280,29 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
if (params.size() == 1)
{
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes)
laddedNodes.push_back(strAddNode);
}
else
{
string strNode = params[1].get_str();
LOCK(cs_vAddedNodes);
- BOOST_FOREACH(string& strAddNode, vAddedNodes)
+ BOOST_FOREACH(const std::string& strAddNode, vAddedNodes) {
if (strAddNode == strNode)
{
laddedNodes.push_back(strAddNode);
break;
}
+ }
if (laddedNodes.size() == 0)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
}
- Array ret;
+ UniValue ret(UniValue::VARR);
if (!fDns)
{
- BOOST_FOREACH(string& strAddNode, laddedNodes)
- {
- Object obj;
+ BOOST_FOREACH (const std::string& strAddNode, laddedNodes) {
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
ret.push_back(obj);
}
@@ -284,17 +310,16 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
}
list<pair<string, vector<CService> > > laddedAddreses(0);
- BOOST_FOREACH(string& strAddNode, laddedNodes)
- {
+ BOOST_FOREACH(const std::string& strAddNode, laddedNodes) {
vector<CService> vservNode(0);
if(Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
laddedAddreses.push_back(make_pair(strAddNode, vservNode));
else
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
obj.push_back(Pair("connected", false));
- Array addresses;
+ UniValue addresses(UniValue::VARR);
obj.push_back(Pair("addresses", addresses));
}
}
@@ -302,17 +327,16 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
LOCK(cs_vNodes);
for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++)
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", it->first));
- Array addresses;
+ UniValue addresses(UniValue::VARR);
bool fConnected = false;
- BOOST_FOREACH(CService& addrNode, it->second)
- {
+ BOOST_FOREACH(const CService& addrNode, it->second) {
bool fFound = false;
- Object node;
+ UniValue node(UniValue::VOBJ);
node.push_back(Pair("address", addrNode.ToString()));
- BOOST_FOREACH(CNode* pnode, vNodes)
+ BOOST_FOREACH(CNode* pnode, vNodes) {
if (pnode->addr == addrNode)
{
fFound = true;
@@ -320,6 +344,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
break;
}
+ }
if (!fFound)
node.push_back(Pair("connected", "false"));
addresses.push_back(node);
@@ -332,7 +357,7 @@ Value getaddednodeinfo(const Array& params, bool fHelp)
return ret;
}
-Value getnettotals(const Array& params, bool fHelp)
+UniValue getnettotals(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -350,23 +375,23 @@ Value getnettotals(const Array& params, bool fHelp)
+ HelpExampleRpc("getnettotals", "")
);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
return obj;
}
-static Array GetNetworksInfo()
+static UniValue GetNetworksInfo()
{
- Array networks;
+ UniValue networks(UniValue::VARR);
for(int n=0; n<NET_MAX; ++n)
{
enum Network network = static_cast<enum Network>(n);
if(network == NET_UNROUTABLE)
continue;
proxyType proxy;
- Object obj;
+ UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy);
obj.push_back(Pair("name", GetNetworkName(network)));
obj.push_back(Pair("limited", IsLimited(network)));
@@ -378,7 +403,7 @@ static Array GetNetworksInfo()
return networks;
}
-Value getnetworkinfo(const Array& params, bool fHelp)
+UniValue getnetworkinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -401,7 +426,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
" }\n"
" ,...\n"
" ],\n"
- " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in btc/kb\n"
+ " \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"
@@ -410,6 +435,7 @@ Value getnetworkinfo(const Array& params, bool fHelp)
" }\n"
" ,...\n"
" ]\n"
+ " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getnetworkinfo", "")
@@ -418,22 +444,21 @@ Value getnetworkinfo(const Array& params, bool fHelp)
LOCK(cs_main);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
- obj.push_back(Pair("subversion",
- FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, std::vector<string>())));
+ obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion",PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
- Array localAddresses;
+ UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
BOOST_FOREACH(const PAIRTYPE(CNetAddr, LocalServiceInfo) &item, mapLocalHost)
{
- Object rec;
+ UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", item.first.ToString()));
rec.push_back(Pair("port", item.second.nPort));
rec.push_back(Pair("score", item.second.nScore));
@@ -441,5 +466,121 @@ Value getnetworkinfo(const Array& params, bool fHelp)
}
}
obj.push_back(Pair("localaddresses", localAddresses));
+ obj.push_back(Pair("warnings", GetWarnings("statusbar")));
return obj;
}
+
+UniValue setban(const UniValue& params, bool fHelp)
+{
+ string strCommand;
+ if (params.size() >= 2)
+ strCommand = params[1].get_str();
+ if (fHelp || params.size() < 2 ||
+ (strCommand != "add" && strCommand != "remove"))
+ throw runtime_error(
+ "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
+ "\nAttempts add or remove a IP/Subnet from the banned list.\n"
+ "\nArguments:\n"
+ "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
+ "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
+ "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
+ "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
+ "\nExamples:\n"
+ + HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400")
+ );
+
+ CSubNet subNet;
+ CNetAddr netAddr;
+ bool isSubnet = false;
+
+ if (params[0].get_str().find("/") != string::npos)
+ isSubnet = true;
+
+ if (!isSubnet)
+ netAddr = CNetAddr(params[0].get_str());
+ else
+ subNet = CSubNet(params[0].get_str());
+
+ if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
+ throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
+
+ if (strCommand == "add")
+ {
+ if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
+ throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
+
+ int64_t banTime = 0; //use standard bantime if not specified
+ if (params.size() >= 3 && !params[2].isNull())
+ banTime = params[2].get_int64();
+
+ bool absolute = false;
+ if (params.size() == 4 && params[3].isTrue())
+ absolute = true;
+
+ isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
+
+ //disconnect possible nodes
+ while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
+ bannedNode->fDisconnect = true;
+ }
+ else if(strCommand == "remove")
+ {
+ if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
+ throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
+ }
+
+ DumpBanlist(); //store banlist to disk
+ uiInterface.BannedListChanged();
+
+ return NullUniValue;
+}
+
+UniValue listbanned(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "listbanned\n"
+ "\nList all banned IPs/Subnets.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("listbanned", "")
+ + HelpExampleRpc("listbanned", "")
+ );
+
+ banmap_t banMap;
+ CNode::GetBanned(banMap);
+
+ UniValue bannedAddresses(UniValue::VARR);
+ for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
+ {
+ CBanEntry banEntry = (*it).second;
+ UniValue rec(UniValue::VOBJ);
+ rec.push_back(Pair("address", (*it).first.ToString()));
+ rec.push_back(Pair("banned_until", banEntry.nBanUntil));
+ rec.push_back(Pair("ban_created", banEntry.nCreateTime));
+ rec.push_back(Pair("ban_reason", banEntry.banReasonToString()));
+
+ bannedAddresses.push_back(rec);
+ }
+
+ return bannedAddresses;
+}
+
+UniValue clearbanned(const UniValue& params, bool fHelp)
+{
+ if (fHelp || params.size() != 0)
+ throw runtime_error(
+ "clearbanned\n"
+ "\nClear all banned IPs.\n"
+ "\nExamples:\n"
+ + HelpExampleCli("clearbanned", "")
+ + HelpExampleRpc("clearbanned", "")
+ );
+
+ CNode::ClearBanned();
+ DumpBanlist(); //store banlist to disk
+ uiInterface.BannedListChanged();
+
+ return NullUniValue;
+}
diff --git a/src/rpcprotocol.cpp b/src/rpcprotocol.cpp
index 95d6b9e531..d83cd87f94 100644
--- a/src/rpcprotocol.cpp
+++ b/src/rpcprotocol.cpp
@@ -5,7 +5,7 @@
#include "rpcprotocol.h"
-#include "clientversion.h"
+#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
@@ -13,278 +13,115 @@
#include "version.h"
#include <stdint.h>
-
-#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
-#include <boost/bind.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/foreach.hpp>
-#include <boost/iostreams/concepts.hpp>
-#include <boost/iostreams/stream.hpp>
-#include <boost/shared_ptr.hpp>
-#include "json/json_spirit_writer_template.h"
+#include <fstream>
using namespace std;
-using namespace json_spirit;
-
-//! Number of bytes to allocate and read at most at once in post data
-const size_t POST_READ_SIZE = 256 * 1024;
/**
- * HTTP protocol
+ * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
+ * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
+ * unspecified (HTTP errors and contents of 'error').
*
- * This ain't Apache. We're just using HTTP header for the length field
- * and to be compatible with other JSON-RPC implementations.
+ * 1.0 spec: http://json-rpc.org/wiki/specification
+ * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
*/
-string HTTPPost(const string& strMsg, const map<string,string>& mapRequestHeaders)
+string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
{
- ostringstream s;
- s << "POST / HTTP/1.1\r\n"
- << "User-Agent: bitcoin-json-rpc/" << FormatFullVersion() << "\r\n"
- << "Host: 127.0.0.1\r\n"
- << "Content-Type: application/json\r\n"
- << "Content-Length: " << strMsg.size() << "\r\n"
- << "Connection: close\r\n"
- << "Accept: application/json\r\n";
- BOOST_FOREACH(const PAIRTYPE(string, string)& item, mapRequestHeaders)
- s << item.first << ": " << item.second << "\r\n";
- s << "\r\n" << strMsg;
-
- return s.str();
+ UniValue request(UniValue::VOBJ);
+ request.push_back(Pair("method", strMethod));
+ request.push_back(Pair("params", params));
+ request.push_back(Pair("id", id));
+ return request.write() + "\n";
}
-static string rfc1123Time()
+UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
- return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
+ UniValue reply(UniValue::VOBJ);
+ if (!error.isNull())
+ reply.push_back(Pair("result", NullUniValue));
+ else
+ reply.push_back(Pair("result", result));
+ reply.push_back(Pair("error", error));
+ reply.push_back(Pair("id", id));
+ return reply;
}
-static const char *httpStatusDescription(int nStatus)
+string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
- switch (nStatus) {
- case HTTP_OK: return "OK";
- case HTTP_BAD_REQUEST: return "Bad Request";
- case HTTP_FORBIDDEN: return "Forbidden";
- case HTTP_NOT_FOUND: return "Not Found";
- case HTTP_INTERNAL_SERVER_ERROR: return "Internal Server Error";
- default: return "";
- }
+ UniValue reply = JSONRPCReplyObj(result, error, id);
+ return reply.write() + "\n";
}
-string HTTPError(int nStatus, bool keepalive, bool headersOnly)
+UniValue JSONRPCError(int code, const string& message)
{
- if (nStatus == HTTP_UNAUTHORIZED)
- return strprintf("HTTP/1.0 401 Authorization Required\r\n"
- "Date: %s\r\n"
- "Server: bitcoin-json-rpc/%s\r\n"
- "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
- "Content-Type: text/html\r\n"
- "Content-Length: 296\r\n"
- "\r\n"
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
- "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
- "<HTML>\r\n"
- "<HEAD>\r\n"
- "<TITLE>Error</TITLE>\r\n"
- "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
- "</HEAD>\r\n"
- "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
- "</HTML>\r\n", rfc1123Time(), FormatFullVersion());
-
- return HTTPReply(nStatus, httpStatusDescription(nStatus), keepalive,
- headersOnly, "text/plain");
+ UniValue error(UniValue::VOBJ);
+ error.push_back(Pair("code", code));
+ error.push_back(Pair("message", message));
+ return error;
}
-string HTTPReplyHeader(int nStatus, bool keepalive, size_t contentLength, const char *contentType)
-{
- return strprintf(
- "HTTP/1.1 %d %s\r\n"
- "Date: %s\r\n"
- "Connection: %s\r\n"
- "Content-Length: %u\r\n"
- "Content-Type: %s\r\n"
- "Server: bitcoin-json-rpc/%s\r\n"
- "\r\n",
- nStatus,
- httpStatusDescription(nStatus),
- rfc1123Time(),
- keepalive ? "keep-alive" : "close",
- contentLength,
- contentType,
- FormatFullVersion());
-}
+/** Username used when cookie authentication is in use (arbitrary, only for
+ * recognizability in debugging/logging purposes)
+ */
+static const std::string COOKIEAUTH_USER = "__cookie__";
+/** Default name for auth cookie file */
+static const std::string COOKIEAUTH_FILE = ".cookie";
-string HTTPReply(int nStatus, const string& strMsg, bool keepalive,
- bool headersOnly, const char *contentType)
+boost::filesystem::path GetAuthCookieFile()
{
- if (headersOnly)
- {
- return HTTPReplyHeader(nStatus, keepalive, 0, contentType);
- } else {
- return HTTPReplyHeader(nStatus, keepalive, strMsg.size(), contentType) + strMsg;
- }
+ boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
+ if (!path.is_complete()) path = GetDataDir() / path;
+ return path;
}
-bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
- string& http_method, string& http_uri)
+bool GenerateAuthCookie(std::string *cookie_out)
{
- string str;
- getline(stream, str);
-
- // HTTP request line is space-delimited
- vector<string> vWords;
- boost::split(vWords, str, boost::is_any_of(" "));
- if (vWords.size() < 2)
+ unsigned char rand_pwd[32];
+ GetRandBytes(rand_pwd, 32);
+ std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
+
+ /** the umask determines what permissions are used to create this file -
+ * these are set to 077 in init.cpp unless overridden with -sysperms.
+ */
+ std::ofstream file;
+ boost::filesystem::path filepath = GetAuthCookieFile();
+ file.open(filepath.string().c_str());
+ if (!file.is_open()) {
+ LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
return false;
+ }
+ file << cookie;
+ file.close();
+ LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
- // HTTP methods permitted: GET, POST
- http_method = vWords[0];
- if (http_method != "GET" && http_method != "POST")
- return false;
-
- // HTTP URI must be an absolute path, relative to current host
- http_uri = vWords[1];
- if (http_uri.size() == 0 || http_uri[0] != '/')
- return false;
-
- // parse proto, if present
- string strProto = "";
- if (vWords.size() > 2)
- strProto = vWords[2];
-
- proto = 0;
- const char *ver = strstr(strProto.c_str(), "HTTP/1.");
- if (ver != NULL)
- proto = atoi(ver+7);
-
+ if (cookie_out)
+ *cookie_out = cookie;
return true;
}
-int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
+bool GetAuthCookie(std::string *cookie_out)
{
- string str;
- getline(stream, str);
- vector<string> vWords;
- boost::split(vWords, str, boost::is_any_of(" "));
- if (vWords.size() < 2)
- return HTTP_INTERNAL_SERVER_ERROR;
- proto = 0;
- const char *ver = strstr(str.c_str(), "HTTP/1.");
- if (ver != NULL)
- proto = atoi(ver+7);
- return atoi(vWords[1].c_str());
-}
+ std::ifstream file;
+ std::string cookie;
+ boost::filesystem::path filepath = GetAuthCookieFile();
+ file.open(filepath.string().c_str());
+ if (!file.is_open())
+ return false;
+ std::getline(file, cookie);
+ file.close();
-int ReadHTTPHeaders(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
-{
- int nLen = 0;
- while (true)
- {
- string str;
- std::getline(stream, str);
- if (str.empty() || str == "\r")
- break;
- string::size_type nColon = str.find(":");
- if (nColon != string::npos)
- {
- string strHeader = str.substr(0, nColon);
- boost::trim(strHeader);
- boost::to_lower(strHeader);
- string strValue = str.substr(nColon+1);
- boost::trim(strValue);
- mapHeadersRet[strHeader] = strValue;
- if (strHeader == "content-length")
- nLen = atoi(strValue.c_str());
- }
- }
- return nLen;
+ if (cookie_out)
+ *cookie_out = cookie;
+ return true;
}
-
-int ReadHTTPMessage(std::basic_istream<char>& stream, map<string,
- string>& mapHeadersRet, string& strMessageRet,
- int nProto, size_t max_size)
+void DeleteAuthCookie()
{
- mapHeadersRet.clear();
- strMessageRet = "";
-
- // Read header
- int nLen = ReadHTTPHeaders(stream, mapHeadersRet);
- if (nLen < 0 || (size_t)nLen > max_size)
- return HTTP_INTERNAL_SERVER_ERROR;
-
- // Read message
- if (nLen > 0)
- {
- vector<char> vch;
- size_t ptr = 0;
- while (ptr < (size_t)nLen)
- {
- size_t bytes_to_read = std::min((size_t)nLen - ptr, POST_READ_SIZE);
- vch.resize(ptr + bytes_to_read);
- stream.read(&vch[ptr], bytes_to_read);
- if (!stream) // Connection lost while reading
- return HTTP_INTERNAL_SERVER_ERROR;
- ptr += bytes_to_read;
- }
- strMessageRet = string(vch.begin(), vch.end());
- }
-
- string sConHdr = mapHeadersRet["connection"];
-
- if ((sConHdr != "close") && (sConHdr != "keep-alive"))
- {
- if (nProto >= 1)
- mapHeadersRet["connection"] = "keep-alive";
- else
- mapHeadersRet["connection"] = "close";
+ try {
+ boost::filesystem::remove(GetAuthCookieFile());
+ } catch (const boost::filesystem::filesystem_error& e) {
+ LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
}
-
- return HTTP_OK;
-}
-
-/**
- * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
- * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
- * unspecified (HTTP errors and contents of 'error').
- *
- * 1.0 spec: http://json-rpc.org/wiki/specification
- * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
- * http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
- */
-
-string JSONRPCRequest(const string& strMethod, const Array& params, const Value& id)
-{
- Object request;
- request.push_back(Pair("method", strMethod));
- request.push_back(Pair("params", params));
- request.push_back(Pair("id", id));
- return write_string(Value(request), false) + "\n";
}
-Object JSONRPCReplyObj(const Value& result, const Value& error, const Value& id)
-{
- Object reply;
- if (error.type() != null_type)
- reply.push_back(Pair("result", Value::null));
- else
- reply.push_back(Pair("result", result));
- reply.push_back(Pair("error", error));
- reply.push_back(Pair("id", id));
- return reply;
-}
-
-string JSONRPCReply(const Value& result, const Value& error, const Value& id)
-{
- Object reply = JSONRPCReplyObj(result, error, id);
- return write_string(Value(reply), false) + "\n";
-}
-
-Object JSONRPCError(int code, const string& message)
-{
- Object error;
- error.push_back(Pair("code", code));
- error.push_back(Pair("message", message));
- return error;
-}
diff --git a/src/rpcprotocol.h b/src/rpcprotocol.h
index 4f3f70fb37..5381e4bcfd 100644
--- a/src/rpcprotocol.h
+++ b/src/rpcprotocol.h
@@ -10,14 +10,9 @@
#include <map>
#include <stdint.h>
#include <string>
-#include <boost/iostreams/concepts.hpp>
-#include <boost/iostreams/stream.hpp>
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
+#include <boost/filesystem.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include "univalue/univalue.h"
//! HTTP status codes
enum HTTPStatusCode
@@ -27,6 +22,7 @@ enum HTTPStatusCode
HTTP_UNAUTHORIZED = 401,
HTTP_FORBIDDEN = 403,
HTTP_NOT_FOUND = 404,
+ HTTP_BAD_METHOD = 405,
HTTP_INTERNAL_SERVER_ERROR = 500,
HTTP_SERVICE_UNAVAILABLE = 503,
};
@@ -65,6 +61,8 @@ enum RPCErrorCode
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
+ RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
+ RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
//! Wallet errors
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
@@ -78,91 +76,18 @@ enum RPCErrorCode
RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
};
-/**
- * IOStream device that speaks SSL but can also speak non-SSL
- */
-template <typename Protocol>
-class SSLIOStreamDevice : public boost::iostreams::device<boost::iostreams::bidirectional> {
-public:
- SSLIOStreamDevice(boost::asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
- {
- fUseSSL = fUseSSLIn;
- fNeedHandshake = fUseSSLIn;
- }
+std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
+UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
+std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
+UniValue JSONRPCError(int code, const std::string& message);
- void handshake(boost::asio::ssl::stream_base::handshake_type role)
- {
- if (!fNeedHandshake) return;
- fNeedHandshake = false;
- stream.handshake(role);
- }
- std::streamsize read(char* s, std::streamsize n)
- {
- handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first
- if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n));
- return stream.next_layer().read_some(boost::asio::buffer(s, n));
- }
- std::streamsize write(const char* s, std::streamsize n)
- {
- handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first
- if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n));
- return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n));
- }
- bool connect(const std::string& server, const std::string& port)
- {
- using namespace boost::asio::ip;
- tcp::resolver resolver(stream.get_io_service());
- tcp::resolver::iterator endpoint_iterator;
-#if BOOST_VERSION >= 104300
- try {
-#endif
- // The default query (flags address_configured) tries IPv6 if
- // non-localhost IPv6 configured, and IPv4 if non-localhost IPv4
- // configured.
- tcp::resolver::query query(server.c_str(), port.c_str());
- endpoint_iterator = resolver.resolve(query);
-#if BOOST_VERSION >= 104300
- } catch (const boost::system::system_error&) {
- // If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces)
- tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags());
- endpoint_iterator = resolver.resolve(query);
- }
-#endif
- boost::system::error_code error = boost::asio::error::host_not_found;
- tcp::resolver::iterator end;
- while (error && endpoint_iterator != end)
- {
- stream.lowest_layer().close();
- stream.lowest_layer().connect(*endpoint_iterator++, error);
- }
- if (error)
- return false;
- return true;
- }
-
-private:
- bool fNeedHandshake;
- bool fUseSSL;
- boost::asio::ssl::stream<typename Protocol::socket>& stream;
-};
-
-std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
-std::string HTTPError(int nStatus, bool keepalive,
- bool headerOnly = false);
-std::string HTTPReplyHeader(int nStatus, bool keepalive, size_t contentLength,
- const char *contentType = "application/json");
-std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
- bool headerOnly = false,
- const char *contentType = "application/json");
-bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
- std::string& http_method, std::string& http_uri);
-int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
-int ReadHTTPHeaders(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet);
-int ReadHTTPMessage(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet,
- std::string& strMessageRet, int nProto, size_t max_size);
-std::string JSONRPCRequest(const std::string& strMethod, const json_spirit::Array& params, const json_spirit::Value& id);
-json_spirit::Object JSONRPCReplyObj(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
-std::string JSONRPCReply(const json_spirit::Value& result, const json_spirit::Value& error, const json_spirit::Value& id);
-json_spirit::Object JSONRPCError(int code, const std::string& message);
+/** Get name of RPC authentication cookie file */
+boost::filesystem::path GetAuthCookieFile();
+/** Generate a new RPC authentication cookie and write it to disk */
+bool GenerateAuthCookie(std::string *cookie_out);
+/** Read the RPC authentication cookie from disk */
+bool GetAuthCookie(std::string *cookie_out);
+/** Delete RPC authentication cookie from disk */
+void DeleteAuthCookie();
#endif // BITCOIN_RPCPROTOCOL_H
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index e84d2693a2..9eeca5b7d9 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -4,19 +4,25 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
-#include "primitives/transaction.h"
+#include "chain.h"
+#include "coins.h"
+#include "consensus/validation.h"
#include "core_io.h"
#include "init.h"
#include "keystore.h"
#include "main.h"
#include "merkleblock.h"
#include "net.h"
+#include "policy/policy.h"
+#include "primitives/transaction.h"
#include "rpcserver.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "script/standard.h"
+#include "txmempool.h"
#include "uint256.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#endif
@@ -24,13 +30,12 @@
#include <stdint.h>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
-using namespace json_spirit;
+#include "univalue/univalue.h"
+
using namespace std;
-void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeHex)
+void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex)
{
txnouttype type;
vector<CTxDestination> addresses;
@@ -48,26 +53,26 @@ void ScriptPubKeyToJSON(const CScript& scriptPubKey, Object& out, bool fIncludeH
out.push_back(Pair("reqSigs", nRequired));
out.push_back(Pair("type", GetTxnOutputType(type)));
- Array a;
+ UniValue a(UniValue::VARR);
BOOST_FOREACH(const CTxDestination& addr, addresses)
a.push_back(CBitcoinAddress(addr).ToString());
out.push_back(Pair("addresses", a));
}
-void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
+void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry)
{
entry.push_back(Pair("txid", tx.GetHash().GetHex()));
entry.push_back(Pair("version", tx.nVersion));
entry.push_back(Pair("locktime", (int64_t)tx.nLockTime));
- Array vin;
+ UniValue vin(UniValue::VARR);
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- Object in;
+ UniValue in(UniValue::VOBJ);
if (tx.IsCoinBase())
in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
else {
in.push_back(Pair("txid", txin.prevout.hash.GetHex()));
in.push_back(Pair("vout", (int64_t)txin.prevout.n));
- Object o;
+ UniValue o(UniValue::VOBJ);
o.push_back(Pair("asm", txin.scriptSig.ToString()));
o.push_back(Pair("hex", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
in.push_back(Pair("scriptSig", o));
@@ -76,13 +81,13 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
vin.push_back(in);
}
entry.push_back(Pair("vin", vin));
- Array vout;
+ UniValue vout(UniValue::VARR);
for (unsigned int i = 0; i < tx.vout.size(); i++) {
const CTxOut& txout = tx.vout[i];
- Object out;
+ UniValue out(UniValue::VOBJ);
out.push_back(Pair("value", ValueFromAmount(txout.nValue)));
out.push_back(Pair("n", (int64_t)i));
- Object o;
+ UniValue o(UniValue::VOBJ);
ScriptPubKeyToJSON(txout.scriptPubKey, o, true);
out.push_back(Pair("scriptPubKey", o));
vout.push_back(out);
@@ -105,7 +110,7 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, Object& entry)
}
}
-Value getrawtransaction(const Array& params, bool fHelp)
+UniValue getrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -144,7 +149,7 @@ Value getrawtransaction(const Array& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
- " \"value\" : x.xxx, (numeric) The value in btc\n"
+ " \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -189,13 +194,13 @@ Value getrawtransaction(const Array& params, bool fHelp)
if (!fVerbose)
return strHex;
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", strHex));
TxToJSON(tx, hashBlock, result);
return result;
}
-Value gettxoutproof(const Array& params, bool fHelp)
+UniValue gettxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 1 && params.size() != 2))
throw runtime_error(
@@ -219,8 +224,9 @@ Value gettxoutproof(const Array& params, bool fHelp)
set<uint256> setTxids;
uint256 oneTxid;
- Array txids = params[0].get_array();
- BOOST_FOREACH(Value& txid, txids) {
+ UniValue txids = params[0].get_array();
+ for (unsigned int idx = 0; idx < txids.size(); idx++) {
+ const UniValue& txid = txids[idx];
if (txid.get_str().length() != 64 || !IsHex(txid.get_str()))
throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str());
uint256 hash(uint256S(txid.get_str()));
@@ -275,7 +281,7 @@ Value gettxoutproof(const Array& params, bool fHelp)
return strHex;
}
-Value verifytxoutproof(const Array& params, bool fHelp)
+UniValue verifytxoutproof(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -292,7 +298,7 @@ Value verifytxoutproof(const Array& params, bool fHelp)
CMerkleBlock merkleBlock;
ssMB >> merkleBlock;
- Array res;
+ UniValue res(UniValue::VARR);
vector<uint256> vMatch;
if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot)
@@ -308,12 +314,13 @@ Value verifytxoutproof(const Array& params, bool fHelp)
return res;
}
-Value createrawtransaction(const Array& params, bool fHelp)
+UniValue createrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 2)
throw runtime_error(
- "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n"
- "\nCreate a transaction spending the given inputs and sending to the given addresses.\n"
+ "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,\"data\":\"hex\",...}\n"
+ "\nCreate a transaction spending the given inputs and creating new outputs.\n"
+ "Outputs can be addresses or data.\n"
"Returns hex-encoded raw transaction.\n"
"Note that the transaction's inputs are not signed, and\n"
"it is not stored in the wallet or transmitted to the network.\n"
@@ -322,40 +329,43 @@ Value createrawtransaction(const Array& params, bool fHelp)
"1. \"transactions\" (string, required) A json array of json objects\n"
" [\n"
" {\n"
- " \"txid\":\"id\", (string, required) The transaction id\n"
+ " \"txid\":\"id\", (string, required) The transaction id\n"
" \"vout\":n (numeric, required) The output number\n"
" }\n"
" ,...\n"
" ]\n"
- "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n"
+ "2. \"outputs\" (string, required) a json object with outputs\n"
" {\n"
- " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n"
- " ,...\n"
+ " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the " + CURRENCY_UNIT + " amount\n"
+ " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n"
+ " ...\n"
" }\n"
-
"\nResult:\n"
"\"transaction\" (string) hex string of the transaction\n"
"\nExamples\n"
+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"")
+ + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"data\\\":\\\"00010203\\\"}\"")
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
+ + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"data\\\":\\\"00010203\\\"}\"")
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
- Array inputs = params[0].get_array();
- Object sendTo = params[1].get_obj();
+ UniValue inputs = params[0].get_array();
+ UniValue sendTo = params[1].get_obj();
CMutableTransaction rawTx;
- BOOST_FOREACH(const Value& input, inputs) {
- const Object& o = input.get_obj();
+ for (unsigned int idx = 0; idx < inputs.size(); idx++) {
+ const UniValue& input = inputs[idx];
+ const UniValue& o = input.get_obj();
uint256 txid = ParseHashO(o, "txid");
- const Value& vout_v = find_value(o, "vout");
- if (vout_v.type() != int_type)
+ const UniValue& vout_v = find_value(o, "vout");
+ if (!vout_v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");
int nOutput = vout_v.get_int();
if (nOutput < 0)
@@ -366,26 +376,35 @@ Value createrawtransaction(const Array& params, bool fHelp)
}
set<CBitcoinAddress> setAddress;
- BOOST_FOREACH(const Pair& s, sendTo) {
- CBitcoinAddress address(s.name_);
- if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
+ vector<string> addrList = sendTo.getKeys();
+ BOOST_FOREACH(const string& name_, addrList) {
+
+ if (name_ == "data") {
+ std::vector<unsigned char> data = ParseHexV(sendTo[name_].getValStr(),"Data");
- if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
- setAddress.insert(address);
+ CTxOut out(0, CScript() << OP_RETURN << data);
+ rawTx.vout.push_back(out);
+ } else {
+ CBitcoinAddress address(name_);
+ if (!address.IsValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
- CScript scriptPubKey = GetScriptForDestination(address.Get());
- CAmount nAmount = AmountFromValue(s.value_);
+ if (setAddress.count(address))
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
+ setAddress.insert(address);
- CTxOut out(nAmount, scriptPubKey);
- rawTx.vout.push_back(out);
+ CScript scriptPubKey = GetScriptForDestination(address.Get());
+ CAmount nAmount = AmountFromValue(sendTo[name_]);
+
+ CTxOut out(nAmount, scriptPubKey);
+ rawTx.vout.push_back(out);
+ }
}
return EncodeHexTx(rawTx);
}
-Value decoderawtransaction(const Array& params, bool fHelp)
+UniValue decoderawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -414,7 +433,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
" ],\n"
" \"vout\" : [ (array of json objects)\n"
" {\n"
- " \"value\" : x.xxx, (numeric) The value in btc\n"
+ " \"value\" : x.xxx, (numeric) The value in " + CURRENCY_UNIT + "\n"
" \"n\" : n, (numeric) index\n"
" \"scriptPubKey\" : { (json object)\n"
" \"asm\" : \"asm\", (string) the asm\n"
@@ -437,20 +456,20 @@ Value decoderawtransaction(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
CTransaction tx;
if (!DecodeHexTx(tx, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
- Object result;
+ UniValue result(UniValue::VOBJ);
TxToJSON(tx, uint256(), result);
return result;
}
-Value decodescript(const Array& params, bool fHelp)
+UniValue decodescript(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -476,9 +495,9 @@ Value decodescript(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR));
- Object r;
+ UniValue r(UniValue::VOBJ);
CScript script;
if (params[0].get_str().size() > 0){
vector<unsigned char> scriptData(ParseHexV(params[0], "argument"));
@@ -493,9 +512,9 @@ Value decodescript(const Array& params, bool fHelp)
}
/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */
-static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::string& strMessage)
+static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", txin.prevout.hash.ToString()));
entry.push_back(Pair("vout", (uint64_t)txin.prevout.n));
entry.push_back(Pair("scriptSig", HexStr(txin.scriptSig.begin(), txin.scriptSig.end())));
@@ -504,7 +523,7 @@ static void TxInErrorToJSON(const CTxIn& txin, Array& vErrorsRet, const std::str
vErrorsRet.push_back(entry);
}
-Value signrawtransaction(const Array& params, bool fHelp)
+UniValue signrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 4)
throw runtime_error(
@@ -569,7 +588,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#else
LOCK(cs_main);
#endif
- RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION);
@@ -612,10 +631,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fGivenKeys = false;
CBasicKeyStore tempKeystore;
- if (params.size() > 2 && params[2].type() != null_type) {
+ if (params.size() > 2 && !params[2].isNull()) {
fGivenKeys = true;
- Array keys = params[2].get_array();
- BOOST_FOREACH(Value k, keys) {
+ UniValue keys = params[2].get_array();
+ for (unsigned int idx = 0; idx < keys.size(); idx++) {
+ UniValue k = keys[idx];
CBitcoinSecret vchSecret;
bool fGood = vchSecret.SetString(k.get_str());
if (!fGood)
@@ -632,15 +652,16 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif
// Add previous txouts given in the RPC call:
- if (params.size() > 1 && params[1].type() != null_type) {
- Array prevTxs = params[1].get_array();
- BOOST_FOREACH(Value& p, prevTxs) {
- if (p.type() != obj_type)
+ if (params.size() > 1 && !params[1].isNull()) {
+ UniValue prevTxs = params[1].get_array();
+ for (unsigned int idx = 0; idx < prevTxs.size(); idx++) {
+ const UniValue& p = prevTxs[idx];
+ if (!p.isObject())
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}");
- Object prevOut = p.get_obj();
+ UniValue prevOut = p.get_obj();
- RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type));
+ RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR));
uint256 txid = ParseHashO(prevOut, "txid");
@@ -668,9 +689,9 @@ Value signrawtransaction(const Array& params, bool fHelp)
// if redeemScript given and not using the local wallet (private keys
// given), add redeemScript to the tempKeystore so it can be signed:
if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) {
- RPCTypeCheck(prevOut, boost::assign::map_list_of("txid", str_type)("vout", int_type)("scriptPubKey", str_type)("redeemScript",str_type));
- Value v = find_value(prevOut, "redeemScript");
- if (!(v == Value::null)) {
+ RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR));
+ UniValue v = find_value(prevOut, "redeemScript");
+ if (!v.isNull()) {
vector<unsigned char> rsData(ParseHexV(v, "redeemScript"));
CScript redeemScript(rsData.begin(), rsData.end());
tempKeystore.AddCScript(redeemScript);
@@ -686,7 +707,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
#endif
int nHashType = SIGHASH_ALL;
- if (params.size() > 3 && params[3].type() != null_type) {
+ if (params.size() > 3 && !params[3].isNull()) {
static map<string, int> mapSigHashValues =
boost::assign::map_list_of
(string("ALL"), int(SIGHASH_ALL))
@@ -706,7 +727,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
// Script verification errors
- Array vErrors;
+ UniValue vErrors(UniValue::VARR);
// Sign what we can:
for (unsigned int i = 0; i < mergedTx.vin.size(); i++) {
@@ -734,7 +755,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
bool fComplete = vErrors.empty();
- Object result;
+ UniValue result(UniValue::VOBJ);
result.push_back(Pair("hex", EncodeHexTx(mergedTx)));
result.push_back(Pair("complete", fComplete));
if (!vErrors.empty()) {
@@ -744,7 +765,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
return result;
}
-Value sendrawtransaction(const Array& params, bool fHelp)
+UniValue sendrawtransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -768,7 +789,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
);
LOCK(cs_main);
- RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
// parse hex string from parameter
CTransaction tx;
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 3f74517a67..b831d3d3b2 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -12,13 +12,9 @@
#include "ui_interface.h"
#include "util.h"
#include "utilstrencodings.h"
-#ifdef ENABLE_WALLET
-#include "wallet/wallet.h"
-#endif
-#include <boost/algorithm/string.hpp>
-#include <boost/asio.hpp>
-#include <boost/asio/ssl.hpp>
+#include "univalue/univalue.h"
+
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
@@ -27,28 +23,20 @@
#include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
-#include "json/json_spirit_writer_template.h"
+#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
-using namespace boost::asio;
-using namespace json_spirit;
using namespace RPCServer;
using namespace std;
-static std::string strRPCUserColonPass;
-
static bool fRPCRunning = false;
static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
-
-//! These are created by StartRPCThreads, destroyed in StopRPCThreads
-static boost::asio::io_service* rpc_io_service = NULL;
-static map<string, boost::shared_ptr<deadline_timer> > deadlineTimers;
-static ssl::context* rpc_ssl_context = NULL;
-static boost::thread_group* rpc_worker_group = NULL;
-static boost::asio::io_service::work *rpc_dummy_work = NULL;
-static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
-static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
+/* Timer-creating functions */
+static std::vector<RPCTimerInterface*> timerInterfaces;
+/* 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;
static struct CRPCSignals
{
@@ -78,71 +66,72 @@ void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
}
-void RPCTypeCheck(const Array& params,
- const list<Value_type>& typesExpected,
+void RPCTypeCheck(const UniValue& params,
+ const list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
- BOOST_FOREACH(Value_type t, typesExpected)
+ BOOST_FOREACH(UniValue::VType t, typesExpected)
{
if (params.size() <= i)
break;
- const Value& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
+ const UniValue& v = params[i];
+ if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s, got %s",
- Value_type_name[t], Value_type_name[v.type()]);
+ uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
i++;
}
}
-void RPCTypeCheck(const Object& o,
- const map<string, Value_type>& typesExpected,
+void RPCTypeCheckObj(const UniValue& o,
+ const map<string, UniValue::VType>& typesExpected,
bool fAllowNull)
{
- BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
+ BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected)
{
- const Value& v = find_value(o, t.first);
- if (!fAllowNull && v.type() == null_type)
+ const UniValue& v = find_value(o, t.first);
+ if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
- if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
+ if (!((v.type() == t.second) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s for %s, got %s",
- Value_type_name[t.second], t.first, Value_type_name[v.type()]);
+ uvTypeName(t.second), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
}
-static inline int64_t roundint64(double d)
-{
- return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
-CAmount AmountFromValue(const Value& value)
+CAmount AmountFromValue(const UniValue& value)
{
- double dAmount = value.get_real();
- if (dAmount <= 0.0 || dAmount > 21000000.0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- CAmount nAmount = roundint64(dAmount * COIN);
- if (!MoneyRange(nAmount))
+ if (!value.isNum() && !value.isStr())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
+ CAmount amount;
+ if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- return nAmount;
+ if (!MoneyRange(amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
+ return amount;
}
-Value ValueFromAmount(const CAmount& amount)
+UniValue ValueFromAmount(const CAmount& amount)
{
- return (double)amount / (double)COIN;
+ bool sign = amount < 0;
+ int64_t n_abs = (sign ? -amount : amount);
+ int64_t quotient = n_abs / COIN;
+ int64_t remainder = n_abs % COIN;
+ return UniValue(UniValue::VNUM,
+ strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
-uint256 ParseHashV(const Value& v, string strName)
+uint256 ParseHashV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
@@ -150,30 +139,29 @@ uint256 ParseHashV(const Value& v, string strName)
result.SetHex(strHex);
return result;
}
-uint256 ParseHashO(const Object& o, string strKey)
+uint256 ParseHashO(const UniValue& o, string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
-vector<unsigned char> ParseHexV(const Value& v, string strName)
+vector<unsigned char> ParseHexV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
return ParseHex(strHex);
}
-vector<unsigned char> ParseHexO(const Object& o, string strKey)
+vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
-
/**
* Note: This interface may still be subject to change.
*/
-string CRPCTable::help(string strCommand) const
+std::string CRPCTable::help(const std::string& strCommand) const
{
string strRet;
string category;
@@ -195,7 +183,7 @@ string CRPCTable::help(string strCommand) const
continue;
try
{
- Array params;
+ UniValue params;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
@@ -228,7 +216,7 @@ string CRPCTable::help(string strCommand) const
return strRet;
}
-Value help(const Array& params, bool fHelp)
+UniValue help(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -248,7 +236,7 @@ Value help(const Array& params, bool fHelp)
}
-Value stop(const Array& params, bool fHelp)
+UniValue stop(const UniValue& params, bool fHelp)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1)
@@ -260,8 +248,6 @@ Value stop(const Array& params, bool fHelp)
return "Bitcoin server stopping";
}
-
-
/**
* Call Table
*/
@@ -276,11 +262,15 @@ static const CRPCCommand vRPCCommands[] =
/* P2P networking */
{ "network", "getnetworkinfo", &getnetworkinfo, true },
{ "network", "addnode", &addnode, true },
+ { "network", "disconnectnode", &disconnectnode, true },
{ "network", "getaddednodeinfo", &getaddednodeinfo, true },
{ "network", "getconnectioncount", &getconnectioncount, true },
{ "network", "getnettotals", &getnettotals, true },
{ "network", "getpeerinfo", &getpeerinfo, true },
{ "network", "ping", &ping, true },
+ { "network", "setban", &setban, true },
+ { "network", "listbanned", &listbanned, true },
+ { "network", "clearbanned", &clearbanned, true },
/* Block chain and UTXO */
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true },
@@ -288,6 +278,7 @@ static const CRPCCommand vRPCCommands[] =
{ "blockchain", "getblockcount", &getblockcount, true },
{ "blockchain", "getblock", &getblock, true },
{ "blockchain", "getblockhash", &getblockhash, true },
+ { "blockchain", "getblockheader", &getblockheader, true },
{ "blockchain", "getchaintips", &getchaintips, true },
{ "blockchain", "getdifficulty", &getdifficulty, true },
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true },
@@ -305,12 +296,10 @@ static const CRPCCommand vRPCCommands[] =
{ "mining", "prioritisetransaction", &prioritisetransaction, true },
{ "mining", "submitblock", &submitblock, true },
-#ifdef ENABLE_WALLET
/* Coin generation */
{ "generating", "getgenerate", &getgenerate, true },
{ "generating", "setgenerate", &setgenerate, true },
{ "generating", "generate", &generate, true },
-#endif
/* Raw transactions */
{ "rawtransactions", "createrawtransaction", &createrawtransaction, true },
@@ -319,6 +308,9 @@ static const CRPCCommand vRPCCommands[] =
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
+#ifdef ENABLE_WALLET
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
+#endif
/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },
@@ -356,6 +348,7 @@ static const CRPCCommand vRPCCommands[] =
{ "wallet", "importprivkey", &importprivkey, true },
{ "wallet", "importwallet", &importwallet, true },
{ "wallet", "importaddress", &importaddress, true },
+ { "wallet", "importpubkey", &importpubkey, true },
{ "wallet", "keypoolrefill", &keypoolrefill, true },
{ "wallet", "listaccounts", &listaccounts, false },
{ "wallet", "listaddressgroupings", &listaddressgroupings, false },
@@ -391,7 +384,7 @@ CRPCTable::CRPCTable()
}
}
-const CRPCCommand *CRPCTable::operator[](string name) const
+const CRPCCommand *CRPCTable::operator[](const std::string &name) const
{
map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
@@ -399,381 +392,26 @@ const CRPCCommand *CRPCTable::operator[](string name) const
return (*it).second;
}
-
-bool HTTPAuthorized(map<string, string>& mapHeaders)
-{
- string strAuth = mapHeaders["authorization"];
- if (strAuth.substr(0,6) != "Basic ")
- return false;
- string strUserPass64 = strAuth.substr(6); boost::trim(strUserPass64);
- string strUserPass = DecodeBase64(strUserPass64);
- return TimingResistantEqual(strUserPass, strRPCUserColonPass);
-}
-
-void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
-{
- // Send error reply from json-rpc error object
- int nStatus = HTTP_INTERNAL_SERVER_ERROR;
- int code = find_value(objError, "code").get_int();
- if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
- else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
- string strReply = JSONRPCReply(Value::null, objError, id);
- stream << HTTPReply(nStatus, strReply, false) << std::flush;
-}
-
-CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address)
+bool StartRPC()
{
- CNetAddr netaddr;
- // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses
- if (address.is_v6()
- && (address.to_v6().is_v4_compatible()
- || address.to_v6().is_v4_mapped()))
- address = address.to_v6().to_v4();
-
- if(address.is_v4())
- {
- boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes();
- netaddr.SetRaw(NET_IPV4, &bytes[0]);
- }
- else
- {
- boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes();
- netaddr.SetRaw(NET_IPV6, &bytes[0]);
- }
- return netaddr;
-}
-
-bool ClientAllowed(const boost::asio::ip::address& address)
-{
- CNetAddr netaddr = BoostAsioToCNetAddr(address);
- BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
- if (subnet.Match(netaddr))
- return true;
- return false;
-}
-
-template <typename Protocol>
-class AcceptedConnectionImpl : public AcceptedConnection
-{
-public:
- AcceptedConnectionImpl(
- boost::asio::io_service& io_service,
- ssl::context &context,
- bool fUseSSL) :
- sslStream(io_service, context),
- _d(sslStream, fUseSSL),
- _stream(_d)
- {
- }
-
- virtual std::iostream& stream()
- {
- return _stream;
- }
-
- virtual std::string peer_address_to_string() const
- {
- return peer.address().to_string();
- }
-
- virtual void close()
- {
- _stream.close();
- }
-
- typename Protocol::endpoint peer;
- boost::asio::ssl::stream<typename Protocol::socket> sslStream;
-
-private:
- SSLIOStreamDevice<Protocol> _d;
- boost::iostreams::stream< SSLIOStreamDevice<Protocol> > _stream;
-};
-
-void ServiceConnection(AcceptedConnection *conn);
-
-//! Forward declaration required for RPCListen
-template <typename Protocol, typename SocketAcceptorService>
-static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
- ssl::context& context,
- bool fUseSSL,
- boost::shared_ptr< AcceptedConnection > conn,
- const boost::system::error_code& error);
-
-/**
- * Sets up I/O resources to accept and handle a new connection.
- */
-template <typename Protocol, typename SocketAcceptorService>
-static void RPCListen(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
- ssl::context& context,
- const bool fUseSSL)
-{
- // Accept connection
- boost::shared_ptr< AcceptedConnectionImpl<Protocol> > conn(new AcceptedConnectionImpl<Protocol>(acceptor->get_io_service(), context, fUseSSL));
-
- acceptor->async_accept(
- conn->sslStream.lowest_layer(),
- conn->peer,
- boost::bind(&RPCAcceptHandler<Protocol, SocketAcceptorService>,
- acceptor,
- boost::ref(context),
- fUseSSL,
- conn,
- _1));
-}
-
-
-/**
- * Accept and handle incoming connection.
- */
-template <typename Protocol, typename SocketAcceptorService>
-static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol, SocketAcceptorService> > acceptor,
- ssl::context& context,
- const bool fUseSSL,
- boost::shared_ptr< AcceptedConnection > conn,
- const boost::system::error_code& error)
-{
- // Immediately start accepting new connections, except when we're cancelled or our socket is closed.
- if (error != boost::asio::error::operation_aborted && acceptor->is_open())
- RPCListen(acceptor, context, fUseSSL);
-
- AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn.get());
-
- if (error)
- {
- // TODO: Actually handle errors
- LogPrintf("%s: Error: %s\n", __func__, error.message());
- }
- // Restrict callers by IP. It is important to
- // do this before starting client thread, to filter out
- // certain DoS and misbehaving clients.
- else if (tcp_conn && !ClientAllowed(tcp_conn->peer.address()))
- {
- // Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
- if (!fUseSSL)
- conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush;
- conn->close();
- }
- else {
- ServiceConnection(conn.get());
- conn->close();
- }
-}
-
-static ip::tcp::endpoint ParseEndpoint(const std::string &strEndpoint, int defaultPort)
-{
- std::string addr;
- int port = defaultPort;
- SplitHostPort(strEndpoint, port, addr);
- return ip::tcp::endpoint(boost::asio::ip::address::from_string(addr), port);
-}
-
-void StartRPCThreads()
-{
- rpc_allow_subnets.clear();
- rpc_allow_subnets.push_back(CSubNet("127.0.0.0/8")); // always allow IPv4 local subnet
- rpc_allow_subnets.push_back(CSubNet("::1")); // always allow IPv6 localhost
- if (mapMultiArgs.count("-rpcallowip"))
- {
- const vector<string>& vAllow = mapMultiArgs["-rpcallowip"];
- BOOST_FOREACH(string strAllow, vAllow)
- {
- CSubNet subnet(strAllow);
- if(!subnet.IsValid())
- {
- uiInterface.ThreadSafeMessageBox(
- strprintf("Invalid -rpcallowip subnet specification: %s. Valid 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).", strAllow),
- "", CClientUIInterface::MSG_ERROR);
- StartShutdown();
- return;
- }
- rpc_allow_subnets.push_back(subnet);
- }
- }
- std::string strAllowed;
- BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets)
- strAllowed += subnet.ToString() + " ";
- LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
-
- strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
- if (((mapArgs["-rpcpassword"] == "") ||
- (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
- {
- unsigned char rand_pwd[32];
- GetRandBytes(rand_pwd, 32);
- uiInterface.ThreadSafeMessageBox(strprintf(
- _("To use bitcoind, or the -server option to bitcoin-qt, you must set an rpcpassword in the configuration file:\n"
- "%s\n"
- "It is recommended you use the following random password:\n"
- "rpcuser=bitcoinrpc\n"
- "rpcpassword=%s\n"
- "(you do not need to remember this password)\n"
- "The username and password MUST NOT be the same.\n"
- "If the file does not exist, create it with owner-readable-only file permissions.\n"
- "It is also recommended to set alertnotify so you are notified of problems;\n"
- "for example: alertnotify=echo %%s | mail -s \"Bitcoin Alert\" admin@foo.com\n"),
- GetConfigFile().string(),
- EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
- "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
- StartShutdown();
- return;
- }
-
- assert(rpc_io_service == NULL);
- rpc_io_service = new boost::asio::io_service();
- rpc_ssl_context = new ssl::context(*rpc_io_service, ssl::context::sslv23);
-
- const bool fUseSSL = GetBoolArg("-rpcssl", false);
-
- if (fUseSSL)
- {
- rpc_ssl_context->set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
-
- boost::filesystem::path pathCertFile(GetArg("-rpcsslcertificatechainfile", "server.cert"));
- if (!pathCertFile.is_complete()) pathCertFile = boost::filesystem::path(GetDataDir()) / pathCertFile;
- if (boost::filesystem::exists(pathCertFile)) rpc_ssl_context->use_certificate_chain_file(pathCertFile.string());
- else LogPrintf("ThreadRPCServer ERROR: missing server certificate file %s\n", pathCertFile.string());
-
- boost::filesystem::path pathPKFile(GetArg("-rpcsslprivatekeyfile", "server.pem"));
- if (!pathPKFile.is_complete()) pathPKFile = boost::filesystem::path(GetDataDir()) / pathPKFile;
- if (boost::filesystem::exists(pathPKFile)) rpc_ssl_context->use_private_key_file(pathPKFile.string(), ssl::context::pem);
- else LogPrintf("ThreadRPCServer ERROR: missing server private key file %s\n", pathPKFile.string());
-
- string strCiphers = GetArg("-rpcsslciphers", "TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH");
- SSL_CTX_set_cipher_list(rpc_ssl_context->impl(), strCiphers.c_str());
- }
-
- std::vector<ip::tcp::endpoint> vEndpoints;
- bool bBindAny = false;
- int defaultPort = GetArg("-rpcport", BaseParams().RPCPort());
- if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs
- {
- vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v6::loopback(), defaultPort));
- vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v4::loopback(), defaultPort));
- if (mapArgs.count("-rpcbind"))
- {
- LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n");
- }
- } else if (mapArgs.count("-rpcbind")) // Specific bind address
- {
- BOOST_FOREACH(const std::string &addr, mapMultiArgs["-rpcbind"])
- {
- try {
- vEndpoints.push_back(ParseEndpoint(addr, defaultPort));
- }
- catch (const boost::system::system_error&)
- {
- uiInterface.ThreadSafeMessageBox(
- strprintf(_("Could not parse -rpcbind value %s as network address"), addr),
- "", CClientUIInterface::MSG_ERROR);
- StartShutdown();
- return;
- }
- }
- } else { // No specific bind address specified, bind to any
- vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v6::any(), defaultPort));
- vEndpoints.push_back(ip::tcp::endpoint(boost::asio::ip::address_v4::any(), defaultPort));
- // Prefer making the socket dual IPv6/IPv4 instead of binding
- // to both addresses seperately.
- bBindAny = true;
- }
-
- bool fListening = false;
- std::string strerr;
- std::string straddress;
- BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints)
- {
- try {
- boost::asio::ip::address bindAddress = endpoint.address();
- straddress = bindAddress.to_string();
- LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", straddress, endpoint.port(), bBindAny);
- boost::system::error_code v6_only_error;
- boost::shared_ptr<ip::tcp::acceptor> acceptor(new ip::tcp::acceptor(*rpc_io_service));
-
- acceptor->open(endpoint.protocol());
- acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
-
- // Try making the socket dual IPv6/IPv4 when listening on the IPv6 "any" address
- acceptor->set_option(boost::asio::ip::v6_only(
- !bBindAny || bindAddress != boost::asio::ip::address_v6::any()), v6_only_error);
-
- acceptor->bind(endpoint);
- acceptor->listen(socket_base::max_connections);
-
- RPCListen(acceptor, *rpc_ssl_context, fUseSSL);
-
- fListening = true;
- rpc_acceptors.push_back(acceptor);
- // If dual IPv6/IPv4 bind successful, skip binding to IPv4 separately
- if(bBindAny && bindAddress == boost::asio::ip::address_v6::any() && !v6_only_error)
- break;
- }
- catch (const boost::system::system_error& e)
- {
- LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", straddress, endpoint.port(), e.what());
- strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), straddress, endpoint.port(), e.what());
- }
- }
-
- if (!fListening) {
- uiInterface.ThreadSafeMessageBox(strerr, "", CClientUIInterface::MSG_ERROR);
- StartShutdown();
- return;
- }
-
- rpc_worker_group = new boost::thread_group();
- for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
- rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
+ LogPrint("rpc", "Starting RPC\n");
fRPCRunning = true;
g_rpcSignals.Started();
+ return true;
}
-void StartDummyRPCThread()
+void InterruptRPC()
{
- if(rpc_io_service == NULL)
- {
- rpc_io_service = new boost::asio::io_service();
- /* Create dummy "work" to keep the thread from exiting when no timeouts active,
- * see http://www.boost.org/doc/libs/1_51_0/doc/html/boost_asio/reference/io_service.html#boost_asio.reference.io_service.stopping_the_io_service_from_running_out_of_work */
- rpc_dummy_work = new boost::asio::io_service::work(*rpc_io_service);
- rpc_worker_group = new boost::thread_group();
- rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
- fRPCRunning = true;
- }
+ LogPrint("rpc", "Interrupting RPC\n");
+ // Interrupt e.g. running longpolls
+ fRPCRunning = false;
}
-void StopRPCThreads()
+void StopRPC()
{
- if (rpc_io_service == NULL) return;
- // Set this to false first, so that longpolling loops will exit when woken up
- fRPCRunning = false;
-
- // First, cancel all timers and acceptors
- // This is not done automatically by ->stop(), and in some cases the destructor of
- // boost::asio::io_service can hang if this is skipped.
- boost::system::error_code ec;
- BOOST_FOREACH(const boost::shared_ptr<ip::tcp::acceptor> &acceptor, rpc_acceptors)
- {
- acceptor->cancel(ec);
- if (ec)
- LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message());
- }
- rpc_acceptors.clear();
- BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr<deadline_timer>) &timer, deadlineTimers)
- {
- timer.second->cancel(ec);
- if (ec)
- LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message());
- }
+ LogPrint("rpc", "Stopping RPC\n");
deadlineTimers.clear();
-
- rpc_io_service->stop();
g_rpcSignals.Stopped();
- if (rpc_worker_group != NULL)
- rpc_worker_group->join_all();
- delete rpc_dummy_work; rpc_dummy_work = NULL;
- delete rpc_worker_group; rpc_worker_group = NULL;
- delete rpc_ssl_context; rpc_ssl_context = NULL;
- delete rpc_io_service; rpc_io_service = NULL;
}
bool IsRPCRunning()
@@ -802,210 +440,78 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
-void RPCRunHandler(const boost::system::error_code& err, boost::function<void(void)> func)
-{
- if (!err)
- func();
-}
-
-void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
-{
- assert(rpc_io_service != NULL);
-
- if (deadlineTimers.count(name) == 0)
- {
- deadlineTimers.insert(make_pair(name,
- boost::shared_ptr<deadline_timer>(new deadline_timer(*rpc_io_service))));
- }
- deadlineTimers[name]->expires_from_now(boost::posix_time::seconds(nSeconds));
- deadlineTimers[name]->async_wait(boost::bind(RPCRunHandler, _1, func));
-}
-
-class JSONRequest
-{
-public:
- Value id;
- string strMethod;
- Array params;
-
- JSONRequest() { id = Value::null; }
- void parse(const Value& valRequest);
-};
-
-void JSONRequest::parse(const Value& valRequest)
+void JSONRequest::parse(const UniValue& valRequest)
{
// Parse request
- if (valRequest.type() != obj_type)
+ if (!valRequest.isObject())
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
- const Object& request = valRequest.get_obj();
+ const UniValue& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
id = find_value(request, "id");
// Parse method
- Value valMethod = find_value(request, "method");
- if (valMethod.type() == null_type)
+ UniValue valMethod = find_value(request, "method");
+ if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
- if (valMethod.type() != str_type)
+ if (!valMethod.isStr())
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate")
LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
- Value valParams = find_value(request, "params");
- if (valParams.type() == array_type)
+ UniValue valParams = find_value(request, "params");
+ if (valParams.isArray())
params = valParams.get_array();
- else if (valParams.type() == null_type)
- params = Array();
+ else if (valParams.isNull())
+ params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
}
-
-static Object JSONRPCExecOne(const Value& req)
+static UniValue JSONRPCExecOne(const UniValue& req)
{
- Object rpc_result;
+ UniValue rpc_result(UniValue::VOBJ);
JSONRequest jreq;
try {
jreq.parse(req);
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
- rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
- catch (const Object& objError)
+ catch (const UniValue& objError)
{
- rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
+ rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
}
catch (const std::exception& e)
{
- rpc_result = JSONRPCReplyObj(Value::null,
+ rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
}
return rpc_result;
}
-static string JSONRPCExecBatch(const Array& vReq)
+std::string JSONRPCExecBatch(const UniValue& vReq)
{
- Array ret;
+ UniValue ret(UniValue::VARR);
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
- return write_string(Value(ret), false) + "\n";
+ return ret.write() + "\n";
}
-static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
- string& strRequest,
- map<string, string>& mapHeaders,
- bool fRun)
+UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
{
- // Check authorization
- if (mapHeaders.count("authorization") == 0)
+ // Return immediately if in warmup
{
- conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
- return false;
+ LOCK(cs_rpcWarmup);
+ if (fRPCInWarmup)
+ throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
}
- if (!HTTPAuthorized(mapHeaders))
- {
- LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string());
- /* Deter brute-forcing
- We don't support exposing the RPC port, so this shouldn't result
- in a DoS. */
- MilliSleep(250);
-
- conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush;
- return false;
- }
-
- JSONRequest jreq;
- try
- {
- // Parse request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
- throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
-
- // Return immediately if in warmup
- {
- LOCK(cs_rpcWarmup);
- if (fRPCInWarmup)
- throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
- }
-
- string strReply;
-
- // singleton request
- if (valRequest.type() == obj_type) {
- jreq.parse(valRequest);
-
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
-
- // Send reply
- strReply = JSONRPCReply(result, Value::null, jreq.id);
-
- // array of requests
- } else if (valRequest.type() == array_type)
- strReply = JSONRPCExecBatch(valRequest.get_array());
- else
- throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
-
- conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush;
- }
- catch (const Object& objError)
- {
- ErrorReply(conn->stream(), objError, jreq.id);
- return false;
- }
- catch (const std::exception& e)
- {
- ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
- return false;
- }
- return true;
-}
-
-void ServiceConnection(AcceptedConnection *conn)
-{
- bool fRun = true;
- while (fRun && !ShutdownRequested())
- {
- int nProto = 0;
- map<string, string> mapHeaders;
- string strRequest, strMethod, strURI;
-
- // Read HTTP request line
- if (!ReadHTTPRequestLine(conn->stream(), nProto, strMethod, strURI))
- break;
-
- // Read HTTP message headers and body
- ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE);
-
- // HTTP Keep-Alive is false; close connection immediately
- if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", true)))
- fRun = false;
-
- // Process via JSON-RPC API
- if (strURI == "/") {
- if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun))
- break;
-
- // Process via HTTP REST API
- } else if (strURI.substr(0, 6) == "/rest/" && GetBoolArg("-rest", false)) {
- if (!HTTPReq_REST(conn, strURI, strRequest, mapHeaders, fRun))
- break;
-
- } else {
- conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush;
- break;
- }
- }
-}
-
-json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array &params) const
-{
// Find method
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
@@ -1026,13 +532,37 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
g_rpcSignals.PostCommand(*pcmd);
}
-std::string HelpExampleCli(string methodname, string args){
+std::string HelpExampleCli(const std::string& methodname, const std::string& args)
+{
return "> bitcoin-cli " + methodname + " " + args + "\n";
}
-std::string HelpExampleRpc(string methodname, string args){
+std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
+{
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/\n";
}
+void RPCRegisterTimerInterface(RPCTimerInterface *iface)
+{
+ timerInterfaces.push_back(iface);
+}
+
+void RPCUnregisterTimerInterface(RPCTimerInterface *iface)
+{
+ std::vector<RPCTimerInterface*>::iterator i = std::find(timerInterfaces.begin(), timerInterfaces.end(), iface);
+ assert(i != timerInterfaces.end());
+ timerInterfaces.erase(i);
+}
+
+void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
+{
+ if (timerInterfaces.empty())
+ 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, timerInterface->NewTimer(func, nSeconds*1000)));
+}
+
const CRPCTable tableRPC;
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 30a5b28db7..83cc37918b 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -15,9 +15,9 @@
#include <stdint.h>
#include <string>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+#include <boost/function.hpp>
+
+#include "univalue/univalue.h"
class CRPCCommand;
@@ -32,30 +32,21 @@ namespace RPCServer
class CBlockIndex;
class CNetAddr;
-class AcceptedConnection
+class JSONRequest
{
public:
- virtual ~AcceptedConnection() {}
+ UniValue id;
+ std::string strMethod;
+ UniValue params;
- virtual std::iostream& stream() = 0;
- virtual std::string peer_address_to_string() const = 0;
- virtual void close() = 0;
+ JSONRequest() { id = NullUniValue; }
+ void parse(const UniValue& valRequest);
};
-/** Start RPC threads */
-void StartRPCThreads();
-/**
- * Alternative to StartRPCThreads for the GUI, when no server is
- * used. The RPC thread in this case is only used to handle timeouts.
- * If real RPC threads have already been started this is a no-op.
- */
-void StartDummyRPCThread();
-/** Stop RPC threads */
-void StopRPCThreads();
/** Query whether RPC is running */
bool IsRPCRunning();
-/**
+/**
* Set the RPC warmup status. When this is done, all RPC calls will error out
* immediately with RPC_IN_WARMUP.
*/
@@ -71,25 +62,56 @@ bool RPCIsInWarmup(std::string *statusOut);
* the right number of arguments are passed, just that any passed are the correct type.
* Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
*/
-void RPCTypeCheck(const json_spirit::Array& params,
- const std::list<json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
+void RPCTypeCheck(const UniValue& params,
+ const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
+
+/*
+ Check for expected keys/value types in an Object.
+ Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type));
+*/
+void RPCTypeCheckObj(const UniValue& o,
+ const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false);
+
+/** Opaque base class for timers returned by NewTimerFunc.
+ * This provides no methods at the moment, but makes sure that delete
+ * cleans up the whole state.
+ */
+class RPCTimerBase
+{
+public:
+ virtual ~RPCTimerBase() {}
+};
+
/**
- * Check for expected keys/value types in an Object.
- * Use like: RPCTypeCheck(object, boost::assign::map_list_of("name", str_type)("value", int_type));
+ * RPC timer "driver".
*/
-void RPCTypeCheck(const json_spirit::Object& o,
- const std::map<std::string, json_spirit::Value_type>& typesExpected, bool fAllowNull=false);
+class RPCTimerInterface
+{
+public:
+ virtual ~RPCTimerInterface() {}
+ /** Implementation name */
+ virtual const char *Name() = 0;
+ /** Factory function for timers.
+ * RPC will call the function to create a timer that will call func in *millis* milliseconds.
+ * @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
+ * This is needed to cope with the case in which there is no HTTP server, but
+ * only GUI RPC console, and to break the dependency of pcserver on httprpc.
+ */
+ 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);
/**
- * Run func nSeconds from now. Uses boost deadline timers.
+ * Run func nSeconds from now.
* Overrides previous timer <name> (if any).
*/
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
-//! Convert boost::asio address to CNetAddr
-extern CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address);
-
-typedef json_spirit::Value(*rpcfn_type)(const json_spirit::Array& params, bool fHelp);
+typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
class CRPCCommand
{
@@ -109,17 +131,17 @@ private:
std::map<std::string, const CRPCCommand*> mapCommands;
public:
CRPCTable();
- const CRPCCommand* operator[](std::string name) const;
- std::string help(std::string name) const;
+ const CRPCCommand* operator[](const std::string& name) const;
+ std::string help(const std::string& name) const;
/**
* Execute a method.
* @param method Method to execute
- * @param params Array of arguments (JSON objects)
+ * @param params UniValue Array of arguments (JSON objects)
* @returns Result of the call.
- * @throws an exception (json_spirit::Value) when an error happens.
+ * @throws an exception (UniValue) when an error happens.
*/
- json_spirit::Value execute(const std::string &method, const json_spirit::Array &params) const;
+ UniValue execute(const std::string &method, const UniValue &params) const;
};
extern const CRPCTable tableRPC;
@@ -128,119 +150,121 @@ extern const CRPCTable tableRPC;
* Utilities: convert hex-encoded Values
* (throws error if not hex).
*/
-extern uint256 ParseHashV(const json_spirit::Value& v, std::string strName);
-extern uint256 ParseHashO(const json_spirit::Object& o, std::string strKey);
-extern std::vector<unsigned char> ParseHexV(const json_spirit::Value& v, std::string strName);
-extern std::vector<unsigned char> ParseHexO(const json_spirit::Object& o, std::string strKey);
-
-extern void InitRPCMining();
-extern void ShutdownRPCMining();
+extern uint256 ParseHashV(const UniValue& v, std::string strName);
+extern uint256 ParseHashO(const UniValue& o, std::string strKey);
+extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
+extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern int64_t nWalletUnlockTime;
-extern CAmount AmountFromValue(const json_spirit::Value& value);
-extern json_spirit::Value ValueFromAmount(const CAmount& amount);
+extern CAmount AmountFromValue(const UniValue& value);
+extern UniValue ValueFromAmount(const CAmount& amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
extern std::string HelpRequiringPassphrase();
-extern std::string HelpExampleCli(std::string methodname, std::string args);
-extern std::string HelpExampleRpc(std::string methodname, std::string args);
+extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
+extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
extern void EnsureWalletIsUnlocked();
-extern json_spirit::Value getconnectioncount(const json_spirit::Array& params, bool fHelp); // in rpcnet.cpp
-extern json_spirit::Value getpeerinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value ping(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value addnode(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaddednodeinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnettotals(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value dumpprivkey(const json_spirit::Array& params, bool fHelp); // in rpcdump.cpp
-extern json_spirit::Value importprivkey(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value importaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value dumpwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value importwallet(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getgenerate(const json_spirit::Array& params, bool fHelp); // in rpcmining.cpp
-extern json_spirit::Value setgenerate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value generate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnetworkhashps(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getmininginfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value prioritisetransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblocktemplate(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value submitblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value estimatefee(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value estimatepriority(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getnewaddress(const json_spirit::Array& params, bool fHelp); // in rpcwallet.cpp
-extern json_spirit::Value getaccountaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getrawchangeaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value setaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getaddressesbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendtoaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value signmessage(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifymessage(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getbalance(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getunconfirmedbalance(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value movecmd(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendfrom(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendmany(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value addmultisigaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value createmultisig(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listreceivedbyaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listreceivedbyaccount(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listtransactions(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listaddressgroupings(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listaccounts(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listsinceblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value backupwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value keypoolrefill(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletpassphrase(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletpassphrasechange(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value walletlock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value encryptwallet(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value validateaddress(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getwalletinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblockchaininfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getnetworkinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value setmocktime(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value resendwallettransactions(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getrawtransaction(const json_spirit::Array& params, bool fHelp); // in rcprawtransaction.cpp
-extern json_spirit::Value listunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value lockunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value listlockunspent(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value createrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value decoderawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value decodescript(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value signrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value sendrawtransaction(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettxoutproof(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifytxoutproof(const json_spirit::Array& params, bool fHelp);
-
-extern json_spirit::Value getblockcount(const json_spirit::Array& params, bool fHelp); // in rpcblockchain.cpp
-extern json_spirit::Value getbestblockhash(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getdifficulty(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value settxfee(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getmempoolinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getrawmempool(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblockhash(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettxoutsetinfo(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value gettxout(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value verifychain(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value getchaintips(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value invalidateblock(const json_spirit::Array& params, bool fHelp);
-extern json_spirit::Value reconsiderblock(const json_spirit::Array& params, bool fHelp);
-
-// in rest.cpp
-extern bool HTTPReq_REST(AcceptedConnection *conn,
- const std::string& strURI,
- const std::string& strRequest,
- const std::map<std::string, std::string>& mapHeaders,
- bool fRun);
+extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpcnet.cpp
+extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
+extern UniValue ping(const UniValue& params, bool fHelp);
+extern UniValue addnode(const UniValue& params, bool fHelp);
+extern UniValue disconnectnode(const UniValue& params, bool fHelp);
+extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
+extern UniValue getnettotals(const UniValue& params, bool fHelp);
+extern UniValue setban(const UniValue& params, bool fHelp);
+extern UniValue listbanned(const UniValue& params, bool fHelp);
+extern UniValue clearbanned(const UniValue& params, bool fHelp);
+
+extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
+extern UniValue importprivkey(const UniValue& params, bool fHelp);
+extern UniValue importaddress(const UniValue& params, bool fHelp);
+extern UniValue importpubkey(const UniValue& params, bool fHelp);
+extern UniValue dumpwallet(const UniValue& params, bool fHelp);
+extern UniValue importwallet(const UniValue& params, bool fHelp);
+
+extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpcmining.cpp
+extern UniValue setgenerate(const UniValue& params, bool fHelp);
+extern UniValue generate(const UniValue& params, bool fHelp);
+extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
+extern UniValue getmininginfo(const UniValue& params, bool fHelp);
+extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
+extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
+extern UniValue submitblock(const UniValue& params, bool fHelp);
+extern UniValue estimatefee(const UniValue& params, bool fHelp);
+extern UniValue estimatepriority(const UniValue& params, bool fHelp);
+
+extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
+extern UniValue getaccountaddress(const UniValue& params, bool fHelp);
+extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp);
+extern UniValue setaccount(const UniValue& params, bool fHelp);
+extern UniValue getaccount(const UniValue& params, bool fHelp);
+extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp);
+extern UniValue sendtoaddress(const UniValue& params, bool fHelp);
+extern UniValue signmessage(const UniValue& params, bool fHelp);
+extern UniValue verifymessage(const UniValue& params, bool fHelp);
+extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp);
+extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp);
+extern UniValue getbalance(const UniValue& params, bool fHelp);
+extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp);
+extern UniValue movecmd(const UniValue& params, bool fHelp);
+extern UniValue sendfrom(const UniValue& params, bool fHelp);
+extern UniValue sendmany(const UniValue& params, bool fHelp);
+extern UniValue addmultisigaddress(const UniValue& params, bool fHelp);
+extern UniValue createmultisig(const UniValue& params, bool fHelp);
+extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp);
+extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp);
+extern UniValue listtransactions(const UniValue& params, bool fHelp);
+extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
+extern UniValue listaccounts(const UniValue& params, bool fHelp);
+extern UniValue listsinceblock(const UniValue& params, bool fHelp);
+extern UniValue gettransaction(const UniValue& params, bool fHelp);
+extern UniValue backupwallet(const UniValue& params, bool fHelp);
+extern UniValue keypoolrefill(const UniValue& params, bool fHelp);
+extern UniValue walletpassphrase(const UniValue& params, bool fHelp);
+extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp);
+extern UniValue walletlock(const UniValue& params, bool fHelp);
+extern UniValue encryptwallet(const UniValue& params, bool fHelp);
+extern UniValue validateaddress(const UniValue& params, bool fHelp);
+extern UniValue getinfo(const UniValue& params, bool fHelp);
+extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
+extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
+extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
+extern UniValue setmocktime(const UniValue& params, bool fHelp);
+extern UniValue resendwallettransactions(const UniValue& params, bool fHelp);
+
+extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rcprawtransaction.cpp
+extern UniValue listunspent(const UniValue& params, bool fHelp);
+extern UniValue lockunspent(const UniValue& params, bool fHelp);
+extern UniValue listlockunspent(const UniValue& params, bool fHelp);
+extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
+extern UniValue decodescript(const UniValue& params, bool fHelp);
+extern UniValue fundrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
+extern UniValue gettxoutproof(const UniValue& params, bool fHelp);
+extern UniValue verifytxoutproof(const UniValue& params, bool fHelp);
+
+extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp
+extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
+extern UniValue getdifficulty(const UniValue& params, bool fHelp);
+extern UniValue settxfee(const UniValue& params, bool fHelp);
+extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
+extern UniValue getrawmempool(const UniValue& params, bool fHelp);
+extern UniValue getblockhash(const UniValue& params, bool fHelp);
+extern UniValue getblockheader(const UniValue& params, bool fHelp);
+extern UniValue getblock(const UniValue& params, bool fHelp);
+extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
+extern UniValue gettxout(const UniValue& params, bool fHelp);
+extern UniValue verifychain(const UniValue& params, bool fHelp);
+extern UniValue getchaintips(const UniValue& params, bool fHelp);
+extern UniValue invalidateblock(const UniValue& params, bool fHelp);
+extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
+
+bool StartRPC();
+void InterruptRPC();
+void StopRPC();
+std::string JSONRPCExecBatch(const UniValue& vReq);
#endif // BITCOIN_RPCSERVER_H
diff --git a/src/scheduler.cpp b/src/scheduler.cpp
new file mode 100644
index 0000000000..184ddc28ab
--- /dev/null
+++ b/src/scheduler.cpp
@@ -0,0 +1,131 @@
+// 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.
+
+#include "scheduler.h"
+
+#include "reverselock.h"
+
+#include <assert.h>
+#include <boost/bind.hpp>
+#include <utility>
+
+CScheduler::CScheduler() : nThreadsServicingQueue(0), stopRequested(false), stopWhenEmpty(false)
+{
+}
+
+CScheduler::~CScheduler()
+{
+ assert(nThreadsServicingQueue == 0);
+}
+
+
+#if BOOST_VERSION < 105000
+static boost::system_time toPosixTime(const boost::chrono::system_clock::time_point& t)
+{
+ return boost::posix_time::from_time_t(boost::chrono::system_clock::to_time_t(t));
+}
+#endif
+
+void CScheduler::serviceQueue()
+{
+ boost::unique_lock<boost::mutex> lock(newTaskMutex);
+ ++nThreadsServicingQueue;
+
+ // newTaskMutex is locked throughout this loop EXCEPT
+ // when the thread is waiting or when the user's function
+ // is called.
+ while (!shouldStop()) {
+ try {
+ while (!shouldStop() && taskQueue.empty()) {
+ // Wait until there is something to do.
+ newTaskScheduled.wait(lock);
+ }
+
+ // Wait until either there is a new task, or until
+ // the time of the first item on the queue:
+
+// wait_until needs boost 1.50 or later; older versions have timed_wait:
+#if BOOST_VERSION < 105000
+ while (!shouldStop() && !taskQueue.empty() &&
+ newTaskScheduled.timed_wait(lock, toPosixTime(taskQueue.begin()->first))) {
+ // Keep waiting until timeout
+ }
+#else
+ // Some boost versions have a conflicting overload of wait_until that returns void.
+ // Explicitly use a template here to avoid hitting that overload.
+ while (!shouldStop() && !taskQueue.empty() &&
+ newTaskScheduled.wait_until<>(lock, taskQueue.begin()->first) != boost::cv_status::timeout) {
+ // Keep waiting until timeout
+ }
+#endif
+ // If there are multiple threads, the queue can empty while we're waiting (another
+ // thread may service the task we were waiting on).
+ if (shouldStop() || taskQueue.empty())
+ continue;
+
+ Function f = taskQueue.begin()->second;
+ taskQueue.erase(taskQueue.begin());
+
+ {
+ // Unlock before calling f, so it can reschedule itself or another task
+ // without deadlocking:
+ reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
+ f();
+ }
+ } catch (...) {
+ --nThreadsServicingQueue;
+ throw;
+ }
+ }
+ --nThreadsServicingQueue;
+}
+
+void CScheduler::stop(bool drain)
+{
+ {
+ boost::unique_lock<boost::mutex> lock(newTaskMutex);
+ if (drain)
+ stopWhenEmpty = true;
+ else
+ stopRequested = true;
+ }
+ newTaskScheduled.notify_all();
+}
+
+void CScheduler::schedule(CScheduler::Function f, boost::chrono::system_clock::time_point t)
+{
+ {
+ boost::unique_lock<boost::mutex> lock(newTaskMutex);
+ taskQueue.insert(std::make_pair(t, f));
+ }
+ newTaskScheduled.notify_one();
+}
+
+void CScheduler::scheduleFromNow(CScheduler::Function f, int64_t deltaSeconds)
+{
+ schedule(f, boost::chrono::system_clock::now() + boost::chrono::seconds(deltaSeconds));
+}
+
+static void Repeat(CScheduler* s, CScheduler::Function f, int64_t deltaSeconds)
+{
+ f();
+ s->scheduleFromNow(boost::bind(&Repeat, s, f, deltaSeconds), deltaSeconds);
+}
+
+void CScheduler::scheduleEvery(CScheduler::Function f, int64_t deltaSeconds)
+{
+ scheduleFromNow(boost::bind(&Repeat, this, f, deltaSeconds), deltaSeconds);
+}
+
+size_t CScheduler::getQueueInfo(boost::chrono::system_clock::time_point &first,
+ boost::chrono::system_clock::time_point &last) const
+{
+ boost::unique_lock<boost::mutex> lock(newTaskMutex);
+ size_t result = taskQueue.size();
+ if (!taskQueue.empty()) {
+ first = taskQueue.begin()->first;
+ last = taskQueue.rbegin()->first;
+ }
+ return result;
+}
diff --git a/src/scheduler.h b/src/scheduler.h
new file mode 100644
index 0000000000..436659e58b
--- /dev/null
+++ b/src/scheduler.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef BITCOIN_SCHEDULER_H
+#define BITCOIN_SCHEDULER_H
+
+//
+// NOTE:
+// boost::thread / boost::function / boost::chrono should be ported to
+// std::thread / std::function / std::chrono when we support C++11.
+//
+#include <boost/function.hpp>
+#include <boost/chrono/chrono.hpp>
+#include <boost/thread.hpp>
+#include <map>
+
+//
+// Simple class for background tasks that should be run
+// periodically or once "after a while"
+//
+// Usage:
+//
+// CScheduler* s = new CScheduler();
+// s->scheduleFromNow(doSomething, 11); // Assuming a: void doSomething() { }
+// s->scheduleFromNow(boost::bind(Class::func, this, argument), 3);
+// boost::thread* t = new boost::thread(boost::bind(CScheduler::serviceQueue, s));
+//
+// ... then at program shutdown, clean up the thread running serviceQueue:
+// t->interrupt();
+// t->join();
+// delete t;
+// delete s; // Must be done after thread is interrupted/joined.
+//
+
+class CScheduler
+{
+public:
+ CScheduler();
+ ~CScheduler();
+
+ typedef boost::function<void(void)> Function;
+
+ // Call func at/after time t
+ void schedule(Function f, boost::chrono::system_clock::time_point t);
+
+ // Convenience method: call f once deltaSeconds from now
+ void scheduleFromNow(Function f, int64_t deltaSeconds);
+
+ // Another convenience method: call f approximately
+ // every deltaSeconds forever, starting deltaSeconds from now.
+ // To be more precise: every time f is finished, it
+ // is rescheduled to run deltaSeconds later. If you
+ // need more accurate scheduling, don't use this method.
+ void scheduleEvery(Function f, int64_t deltaSeconds);
+
+ // To keep things as simple as possible, there is no unschedule.
+
+ // Services the queue 'forever'. Should be run in a thread,
+ // and interrupted using boost::interrupt_thread
+ void serviceQueue();
+
+ // Tell any threads running serviceQueue to stop as soon as they're
+ // done servicing whatever task they're currently servicing (drain=false)
+ // or when there is no work left to be done (drain=true)
+ void stop(bool drain=false);
+
+ // Returns number of tasks waiting to be serviced,
+ // and first and last task times
+ size_t getQueueInfo(boost::chrono::system_clock::time_point &first,
+ boost::chrono::system_clock::time_point &last) const;
+
+private:
+ std::multimap<boost::chrono::system_clock::time_point, Function> taskQueue;
+ boost::condition_variable newTaskScheduled;
+ mutable boost::mutex newTaskMutex;
+ int nThreadsServicingQueue;
+ bool stopRequested;
+ bool stopWhenEmpty;
+ bool shouldStop() { return stopRequested || (stopWhenEmpty && taskQueue.empty()); }
+};
+
+#endif
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
index 84a7432fdb..bd5e54b33f 100644
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -335,9 +335,51 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Control
//
case OP_NOP:
- break;
+ break;
+
+ case OP_CHECKLOCKTIMEVERIFY:
+ {
+ if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
+ // not enabled; treat as a NOP2
+ if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
+ return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
+ }
+ break;
+ }
+
+ if (stack.size() < 1)
+ return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
+
+ // Note that elsewhere numeric opcodes are limited to
+ // operands in the range -2**31+1 to 2**31-1, however it is
+ // legal for opcodes to produce results exceeding that
+ // range. This limitation is implemented by CScriptNum's
+ // default 4-byte limit.
+ //
+ // If we kept to that limit we'd have a year 2038 problem,
+ // even though the nLockTime field in transactions
+ // themselves is uint32 which only becomes meaningless
+ // after the year 2106.
+ //
+ // Thus as a special case we tell CScriptNum to accept up
+ // to 5-byte bignums, which are good until 2**39-1, well
+ // beyond the 2**32-1 limit of the nLockTime field itself.
+ const CScriptNum nLockTime(stacktop(-1), fRequireMinimal, 5);
+
+ // In the rare event that the argument may be < 0 due to
+ // some arithmetic being done first, you can always use
+ // 0 MAX CHECKLOCKTIMEVERIFY.
+ if (nLockTime < 0)
+ return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);
+
+ // Actually compare the specified lock time with the transaction.
+ if (!checker.CheckLockTime(nLockTime))
+ return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);
+
+ break;
+ }
- case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
+ case OP_NOP1: case OP_NOP3: case OP_NOP4: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
@@ -1084,6 +1126,43 @@ bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn
return true;
}
+bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const
+{
+ // There are two kinds of nLockTime: lock-by-blockheight
+ // and lock-by-blocktime, distinguished by whether
+ // nLockTime < LOCKTIME_THRESHOLD.
+ //
+ // We want to compare apples to apples, so fail the script
+ // unless the type of nLockTime being tested is the same as
+ // the nLockTime in the transaction.
+ if (!(
+ (txTo->nLockTime < LOCKTIME_THRESHOLD && nLockTime < LOCKTIME_THRESHOLD) ||
+ (txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
+ ))
+ return false;
+
+ // Now that we know we're comparing apples-to-apples, the
+ // comparison is a simple numeric one.
+ if (nLockTime > (int64_t)txTo->nLockTime)
+ return false;
+
+ // Finally the nLockTime feature can be disabled and thus
+ // CHECKLOCKTIMEVERIFY bypassed if every txin has been
+ // finalized by setting nSequence to maxint. The
+ // transaction would be allowed into the blockchain, making
+ // the opcode ineffective.
+ //
+ // Testing if this vin is not final is sufficient to
+ // prevent this condition. Alternatively we could test all
+ // inputs, but testing just this input minimizes the data
+ // required to prove correct CHECKLOCKTIMEVERIFY execution.
+ if (txTo->vin[nIn].IsFinal())
+ return false;
+
+ return true;
+}
+
+
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index fc64438f68..35d572f0ad 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -76,6 +76,11 @@ enum
// (softfork safe, BIP62 rule 6)
// Note: CLEANSTACK should never be used without P2SH.
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
+
+ // Verify CHECKLOCKTIMEVERIFY
+ //
+ // See BIP65 for details.
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
};
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
@@ -88,6 +93,11 @@ public:
return false;
}
+ virtual bool CheckLockTime(const CScriptNum& nLockTime) const
+ {
+ return false;
+ }
+
virtual ~BaseSignatureChecker() {}
};
@@ -103,6 +113,7 @@ protected:
public:
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
+ bool CheckLockTime(const CScriptNum& nLockTime) const;
};
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
diff --git a/src/script/script.h b/src/script/script.h
index ed456f5c5a..e39ca57f4f 100644
--- a/src/script/script.h
+++ b/src/script/script.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_SCRIPT_SCRIPT_H
#define BITCOIN_SCRIPT_SCRIPT_H
+#include "crypto/common.h"
+
#include <assert.h>
#include <climits>
#include <limits>
@@ -14,10 +16,13 @@
#include <string.h>
#include <string>
#include <vector>
-#include "crypto/common.h"
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
+// Threshold for nLockTime: below this value it is interpreted as block number,
+// otherwise as UNIX timestamp.
+static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
+
template <typename T>
std::vector<unsigned char> ToByteVector(const T& in)
{
@@ -150,6 +155,7 @@ enum opcodetype
// expansion
OP_NOP1 = 0xb0,
OP_NOP2 = 0xb1,
+ OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
OP_NOP3 = 0xb2,
OP_NOP4 = 0xb3,
OP_NOP5 = 0xb4,
@@ -195,7 +201,10 @@ public:
m_value = n;
}
- explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal)
+ static const size_t nDefaultMaxNumSize = 4;
+
+ explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal,
+ const size_t nMaxNumSize = nDefaultMaxNumSize)
{
if (vch.size() > nMaxNumSize) {
throw scriptnum_error("script number overflow");
@@ -318,8 +327,6 @@ public:
return result;
}
- static const size_t nMaxNumSize = 4;
-
private:
static int64_t set_vch(const std::vector<unsigned char>& vch)
{
@@ -602,4 +609,13 @@ public:
}
};
+class CReserveScript
+{
+public:
+ CScript reserveScript;
+ virtual void KeepScript() {}
+ CReserveScript() {}
+ virtual ~CReserveScript() {}
+};
+
#endif // BITCOIN_SCRIPT_SCRIPT_H
diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp
index d8ecfde1d7..f1aa1fb408 100644
--- a/src/script/script_error.cpp
+++ b/src/script/script_error.cpp
@@ -47,6 +47,10 @@ const char* ScriptErrorString(const ScriptError serror)
return "OP_RETURN was encountered";
case SCRIPT_ERR_UNBALANCED_CONDITIONAL:
return "Invalid OP_IF construction";
+ case SCRIPT_ERR_NEGATIVE_LOCKTIME:
+ return "Negative locktime";
+ case SCRIPT_ERR_UNSATISFIED_LOCKTIME:
+ return "Locktime requirement not satisfied";
case SCRIPT_ERR_SIG_HASHTYPE:
return "Signature hash type missing or not understood";
case SCRIPT_ERR_SIG_DER:
diff --git a/src/script/script_error.h b/src/script/script_error.h
index 6365680b29..bb10b8a293 100644
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -35,6 +35,10 @@ typedef enum ScriptError_t
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
+ /* OP_CHECKLOCKTIMEVERIFY */
+ SCRIPT_ERR_NEGATIVE_LOCKTIME,
+ SCRIPT_ERR_UNSATISFIED_LOCKTIME,
+
/* BIP62 */
SCRIPT_ERR_SIG_HASHTYPE,
SCRIPT_ERR_SIG_DER,
diff --git a/src/script/sign.cpp b/src/script/sign.cpp
index eab629cd91..8b43183b6d 100644
--- a/src/script/sign.cpp
+++ b/src/script/sign.cpp
@@ -5,9 +5,10 @@
#include "script/sign.h"
-#include "primitives/transaction.h"
#include "key.h"
#include "keystore.h"
+#include "policy/policy.h"
+#include "primitives/transaction.h"
#include "script/standard.h"
#include "uint256.h"
@@ -275,3 +276,39 @@ CScript CombineSignatures(const CScript& scriptPubKey, const BaseSignatureChecke
return CombineSignatures(scriptPubKey, checker, txType, vSolutions, stack1, stack2);
}
+
+namespace {
+/** Dummy signature checker which accepts all signatures. */
+class DummySignatureChecker : public BaseSignatureChecker
+{
+public:
+ DummySignatureChecker() {}
+
+ bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
+ {
+ return true;
+ }
+};
+const DummySignatureChecker dummyChecker;
+}
+
+const BaseSignatureChecker& DummySignatureCreator::Checker() const
+{
+ return dummyChecker;
+}
+
+bool DummySignatureCreator::CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const
+{
+ // Create a dummy signature that is a valid DER-encoding
+ vchSig.assign(72, '\000');
+ vchSig[0] = 0x30;
+ vchSig[1] = 69;
+ vchSig[2] = 0x02;
+ vchSig[3] = 33;
+ vchSig[4] = 0x01;
+ vchSig[4 + 33] = 0x02;
+ vchSig[5 + 33] = 32;
+ vchSig[6 + 33] = 0x01;
+ vchSig[6 + 33 + 32] = SIGHASH_ALL;
+ return true;
+}
diff --git a/src/script/sign.h b/src/script/sign.h
index 0c4cf61e5e..13f45007dd 100644
--- a/src/script/sign.h
+++ b/src/script/sign.h
@@ -43,6 +43,14 @@ public:
bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
};
+/** A signature creator that just produces 72-byte empty signatyres. */
+class DummySignatureCreator : public BaseSignatureCreator {
+public:
+ DummySignatureCreator(const CKeyStore* keystoreIn) : BaseSignatureCreator(keystoreIn) {}
+ const BaseSignatureChecker& Checker() const;
+ bool CreateSig(std::vector<unsigned char>& vchSig, const CKeyID& keyid, const CScript& scriptCode) const;
+};
+
/** Produce a script signature using a generic signature creator. */
bool ProduceSignature(const BaseSignatureCreator& creator, const CScript& scriptPubKey, CScript& scriptSig);
diff --git a/src/script/standard.cpp b/src/script/standard.cpp
index ce50e3aad8..1d5aac7b34 100644
--- a/src/script/standard.cpp
+++ b/src/script/standard.cpp
@@ -180,26 +180,6 @@ int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned c
return -1;
}
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
-{
- vector<valtype> vSolutions;
- if (!Solver(scriptPubKey, whichType, vSolutions))
- return false;
-
- if (whichType == TX_MULTISIG)
- {
- unsigned char m = vSolutions.front()[0];
- unsigned char n = vSolutions.back()[0];
- // Support up to x-of-3 multisig txns as standard
- if (n < 1 || n > 3)
- return false;
- if (m < 1 || m > n)
- return false;
- }
-
- return whichType != TX_NONSTANDARD;
-}
-
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
vector<valtype> vSolutions;
@@ -306,6 +286,11 @@ CScript GetScriptForDestination(const CTxDestination& dest)
return script;
}
+CScript GetScriptForRawPubKey(const CPubKey& pubKey)
+{
+ return CScript() << std::vector<unsigned char>(pubKey.begin(), pubKey.end()) << OP_CHECKSIG;
+}
+
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
{
CScript script;
diff --git a/src/script/standard.h b/src/script/standard.h
index a8b0acc981..9e17dac700 100644
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -39,22 +39,6 @@ extern unsigned nMaxDatacarrierBytes;
*/
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
-/**
- * Standard script verification flags that standard transactions will comply
- * with. However scripts violating these flags may still be present in valid
- * blocks and we must accept those blocks.
- */
-static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
- SCRIPT_VERIFY_DERSIG |
- SCRIPT_VERIFY_STRICTENC |
- SCRIPT_VERIFY_MINIMALDATA |
- SCRIPT_VERIFY_NULLDUMMY |
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS |
- SCRIPT_VERIFY_CLEANSTACK;
-
-/** For convenience, standard but not mandatory verify flags. */
-static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
-
enum txnouttype
{
TX_NONSTANDARD,
@@ -85,11 +69,11 @@ const char* GetTxnOutputType(txnouttype t);
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
-bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
CScript GetScriptForDestination(const CTxDestination& dest);
+CScript GetScriptForRawPubKey(const CPubKey& pubkey);
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
#endif // BITCOIN_SCRIPT_STANDARD_H
diff --git a/src/serialize.h b/src/serialize.h
index 741f78f8b4..53d8af142f 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -6,6 +6,8 @@
#ifndef BITCOIN_SERIALIZE_H
#define BITCOIN_SERIALIZE_H
+#include "compat/endian.h"
+
#include <algorithm>
#include <assert.h>
#include <ios>
@@ -18,8 +20,6 @@
#include <utility>
#include <vector>
-#include "compat/endian.h"
-
class CScript;
static const unsigned int MAX_SIZE = 0x02000000;
diff --git a/src/support/pagelocker.h b/src/support/pagelocker.h
index 3fd793072f..88b95cce73 100644
--- a/src/support/pagelocker.h
+++ b/src/support/pagelocker.h
@@ -37,7 +37,6 @@ public:
~LockedPageManagerBase()
{
- assert(this->GetLockedPageCount() == 0);
}
diff --git a/src/sync.cpp b/src/sync.cpp
index a422939964..1837e8d53d 100644
--- a/src/sync.cpp
+++ b/src/sync.cpp
@@ -33,20 +33,22 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
//
struct CLockLocation {
- CLockLocation(const char* pszName, const char* pszFile, int nLine)
+ CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
{
mutexName = pszName;
sourceFile = pszFile;
sourceLine = nLine;
+ fTry = fTryIn;
}
std::string ToString() const
{
- return mutexName + " " + sourceFile + ":" + itostr(sourceLine);
+ return mutexName + " " + sourceFile + ":" + itostr(sourceLine) + (fTry ? " (TRY)" : "");
}
std::string MutexName() const { return mutexName; }
+ bool fTry;
private:
std::string mutexName;
std::string sourceFile;
@@ -62,23 +64,52 @@ static boost::thread_specific_ptr<LockStack> lockstack;
static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
+ // We attempt to not assert on probably-not deadlocks by assuming that
+ // a try lock will immediately have otherwise bailed if it had
+ // failed to get the lock
+ // We do this by, for the locks which triggered the potential deadlock,
+ // in either lockorder, checking that the second of the two which is locked
+ // is only a TRY_LOCK, ignoring locks if they are reentrant.
+ bool firstLocked = false;
+ bool secondLocked = false;
+ bool onlyMaybeDeadlock = false;
+
LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
LogPrintf("Previous lock order was:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s2) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ firstLocked = false;
+ secondLocked = false;
LogPrintf("Current lock order is:\n");
BOOST_FOREACH (const PAIRTYPE(void*, CLockLocation) & i, s1) {
- if (i.first == mismatch.first)
+ if (i.first == mismatch.first) {
LogPrintf(" (1)");
- if (i.first == mismatch.second)
+ if (!firstLocked && secondLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ firstLocked = true;
+ }
+ if (i.first == mismatch.second) {
LogPrintf(" (2)");
+ if (!secondLocked && firstLocked && i.second.fTry)
+ onlyMaybeDeadlock = true;
+ secondLocked = true;
+ }
LogPrintf(" %s\n", i.second.ToString());
}
+ assert(onlyMaybeDeadlock);
}
static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
@@ -101,10 +132,8 @@ static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
lockorders[p1] = (*lockstack);
std::pair<void*, void*> p2 = std::make_pair(c, i.first);
- if (lockorders.count(p2)) {
+ if (lockorders.count(p2))
potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
- break;
- }
}
}
dd_mutex.unlock();
@@ -119,7 +148,7 @@ static void pop_lock()
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
- push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
+ push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}
void LeaveCritical()
diff --git a/src/sync.h b/src/sync.h
index 78b9043477..68a9443084 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -16,7 +16,7 @@
////////////////////////////////////////////////
// //
-// THE SIMPLE DEFINITON, EXCLUDING DEBUG CODE //
+// THE SIMPLE DEFINITION, EXCLUDING DEBUG CODE //
// //
////////////////////////////////////////////////
@@ -101,7 +101,7 @@ void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
/** Wrapper around boost::unique_lock<Mutex> */
template <typename Mutex>
-class CMutexLock
+class SCOPED_LOCKABLE CMutexLock
{
private:
boost::unique_lock<Mutex> lock;
@@ -129,7 +129,7 @@ private:
}
public:
- CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) : lock(mutexIn, boost::defer_lock)
+ CMutexLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(mutexIn) : lock(mutexIn, boost::defer_lock)
{
if (fTry)
TryEnter(pszName, pszFile, nLine);
@@ -137,7 +137,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
+ CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) EXCLUSIVE_LOCK_FUNCTION(pmutexIn)
{
if (!pmutexIn) return;
@@ -148,7 +148,7 @@ public:
Enter(pszName, pszFile, nLine);
}
- ~CMutexLock()
+ ~CMutexLock() UNLOCK_FUNCTION()
{
if (lock.owns_lock())
LeaveCritical();
diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp
index 642ce13bcd..0a23c430ed 100644
--- a/src/test/Checkpoints_tests.cpp
+++ b/src/test/Checkpoints_tests.cpp
@@ -20,22 +20,8 @@ BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(sanity)
{
- const Checkpoints::CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
- uint256 p11111 = uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d");
- uint256 p134444 = uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe");
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444));
-
-
- // Wrong hashes at checkpoints should fail:
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444));
- BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111));
-
- // ... but any hash not at a checkpoint should succeed:
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111+1, p134444));
- BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444+1, p11111));
-
+ const CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints();
BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444);
-}
+}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/DoS_tests.cpp b/src/test/DoS_tests.cpp
index bf25548755..da296a0461 100644
--- a/src/test/DoS_tests.cpp
+++ b/src/test/DoS_tests.cpp
@@ -2,12 +2,9 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
// Unit tests for denial-of-service detection/prevention code
-//
-
-
+#include "chainparams.h"
#include "keystore.h"
#include "main.h"
#include "net.h"
diff --git a/src/test/README.md b/src/test/README.md
index 7efce6f052..e36112bd4f 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -18,4 +18,16 @@ uint256_tests.cpp.
For further reading, I found the following website to be helpful in
explaining how the boost unit test framework works:
-[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/). \ No newline at end of file
+[http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/](http://www.alittlemadness.com/2009/03/31/c-unit-testing-with-boosttest/).
+
+test_bitcoin has some built-in command-line arguments; for
+example, to run just the getarg_tests verbosely:
+
+ test_bitcoin --log_level=all --run_test=getarg_tests
+
+... or to run just the doubledash test:
+
+ test_bitcoin --run_test=getarg_tests/doubledash
+
+Run test_bitcoin --help for the full list.
+
diff --git a/src/test/alert_tests.cpp b/src/test/alert_tests.cpp
index 6b6df5199a..dd3c51d09b 100644
--- a/src/test/alert_tests.cpp
+++ b/src/test/alert_tests.cpp
@@ -2,15 +2,14 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
// Unit tests for alert system
-//
#include "alert.h"
+#include "chain.h"
+#include "chainparams.h"
#include "clientversion.h"
#include "data/alertTests.raw.h"
-
-#include "chainparams.h"
+#include "main.h" // For PartitionCheck
#include "serialize.h"
#include "streams.h"
#include "util.h"
@@ -163,8 +162,8 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
SetMockTime(11);
const std::vector<unsigned char>& alertKey = Params(CBaseChainParams::MAIN).AlertKey();
- boost::filesystem::path temp = GetTempPath() / "alertnotify.txt";
- boost::filesystem::remove(temp);
+ boost::filesystem::path temp = GetTempPath() /
+ boost::filesystem::unique_path("alertnotify-%%%%.txt");
mapArgs["-alertnotify"] = std::string("echo %s >> ") + temp.string();
@@ -193,4 +192,63 @@ BOOST_AUTO_TEST_CASE(AlertNotify)
SetMockTime(0);
}
+static bool falseFunc() { return false; }
+
+BOOST_AUTO_TEST_CASE(PartitionAlert)
+{
+ // Test PartitionCheck
+ CCriticalSection csDummy;
+ CBlockIndex indexDummy[100];
+ CChainParams& params = Params(CBaseChainParams::MAIN);
+ int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
+
+ // Generate fake blockchain timestamps relative to
+ // an arbitrary time:
+ int64_t now = 1427379054;
+ SetMockTime(now);
+ for (int i = 0; i < 100; i++)
+ {
+ indexDummy[i].phashBlock = NULL;
+ if (i == 0) indexDummy[i].pprev = NULL;
+ else indexDummy[i].pprev = &indexDummy[i-1];
+ indexDummy[i].nHeight = i;
+ indexDummy[i].nTime = now - (100-i)*nPowTargetSpacing;
+ // Other members don't matter, the partition check code doesn't
+ // use them
+ }
+
+ // Test 1: chain with blocks every nPowTargetSpacing seconds,
+ // as normal, no worries:
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
+ BOOST_CHECK(strMiscWarning.empty());
+
+ // Test 2: go 3.5 hours without a block, expect a warning:
+ now += 3*60*60+30*60;
+ SetMockTime(now);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
+ BOOST_CHECK(!strMiscWarning.empty());
+ BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
+ strMiscWarning = "";
+
+ // Test 3: test the "partition alerts only go off once per day"
+ // code:
+ now += 60*10;
+ SetMockTime(now);
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
+ BOOST_CHECK(strMiscWarning.empty());
+
+ // Test 4: get 2.5 times as many blocks as expected:
+ now += 60*60*24; // Pretend it is a day later
+ SetMockTime(now);
+ int64_t quickSpacing = nPowTargetSpacing*2/5;
+ for (int i = 0; i < 100; i++) // Tweak chain timestamps:
+ indexDummy[i].nTime = now - (100-i)*quickSpacing;
+ PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
+ BOOST_CHECK(!strMiscWarning.empty());
+ BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
+ strMiscWarning = "";
+
+ SetMockTime(0);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/base58_tests.cpp b/src/test/base58_tests.cpp
index f07dd7a7db..9e74f5f427 100644
--- a/src/test/base58_tests.cpp
+++ b/src/test/base58_tests.cpp
@@ -17,23 +17,20 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
BOOST_FIXTURE_TEST_SUITE(base58_tests, BasicTestingSetup)
// Goal: test low-level base58 encoding functionality
BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -50,13 +47,12 @@ BOOST_AUTO_TEST_CASE(base58_EncodeBase58)
// Goal: test low-level base58 decoding functionality
BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
{
- Array tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
+ UniValue tests = read_json(std::string(json_tests::base58_encode_decode, json_tests::base58_encode_decode + sizeof(json_tests::base58_encode_decode)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 2) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -124,16 +120,15 @@ public:
// Goal: check that parsed keys match test payload
BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
SelectParams(CBaseChainParams::MAIN);
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -141,7 +136,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -183,12 +178,12 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_parse)
// Goal: check that generated keys match test vectors
BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
{
- Array tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
+ UniValue tests = read_json(std::string(json_tests::base58_keys_valid, json_tests::base58_keys_valid + sizeof(json_tests::base58_keys_valid)));
std::vector<unsigned char> result;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 3) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
@@ -196,7 +191,7 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
}
std::string exp_base58string = test[0].get_str();
std::vector<unsigned char> exp_payload = ParseHex(test[1].get_str());
- const Object &metadata = test[2].get_obj();
+ const UniValue &metadata = test[2].get_obj();
bool isPrivkey = find_value(metadata, "isPrivkey").get_bool();
bool isTestnet = find_value(metadata, "isTestnet").get_bool();
if (isTestnet)
@@ -251,15 +246,14 @@ BOOST_AUTO_TEST_CASE(base58_keys_valid_gen)
// Goal: check that base58 parsing code is robust against a variety of corrupted data
BOOST_AUTO_TEST_CASE(base58_keys_invalid)
{
- Array tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
+ UniValue tests = read_json(std::string(json_tests::base58_keys_invalid, json_tests::base58_keys_invalid + sizeof(json_tests::base58_keys_invalid))); // Negative testcases
std::vector<unsigned char> result;
CBitcoinSecret secret;
CBitcoinAddress addr;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/bip32_tests.cpp b/src/test/bip32_tests.cpp
index 0d815c27fd..69084213a2 100644
--- a/src/test/bip32_tests.cpp
+++ b/src/test/bip32_tests.cpp
@@ -88,12 +88,23 @@ void RunTest(const TestVector &test) {
unsigned char data[74];
key.Encode(data);
pubkey.Encode(data);
+
// Test private key
CBitcoinExtKey b58key; b58key.SetKey(key);
BOOST_CHECK(b58key.ToString() == derive.prv);
+
+ CBitcoinExtKey b58keyDecodeCheck(derive.prv);
+ CExtKey checkKey = b58keyDecodeCheck.GetKey();
+ assert(checkKey == key); //ensure a base58 decoded key also matches
+
// Test public key
CBitcoinExtPubKey b58pubkey; b58pubkey.SetKey(pubkey);
BOOST_CHECK(b58pubkey.ToString() == derive.pub);
+
+ CBitcoinExtPubKey b58PubkeyDecodeCheck(derive.pub);
+ CExtPubKey checkPubKey = b58PubkeyDecodeCheck.GetKey();
+ assert(checkPubKey == pubkey); //ensure a base58 decoded pubkey also matches
+
// Derive new keys
CExtKey keyNew;
BOOST_CHECK(key.Derive(keyNew, derive.nChild));
diff --git a/src/test/bloom_tests.cpp b/src/test/bloom_tests.cpp
index 1bda8a7ea1..6b30d6aa8a 100644
--- a/src/test/bloom_tests.cpp
+++ b/src/test/bloom_tests.cpp
@@ -469,7 +469,7 @@ static std::vector<unsigned char> RandomData()
BOOST_AUTO_TEST_CASE(rolling_bloom)
{
// last-100-entry, 1% false positive:
- CRollingBloomFilter rb1(100, 0.01, 0);
+ CRollingBloomFilter rb1(100, 0.01);
// Overfill:
static const int DATASIZE=399;
@@ -500,7 +500,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
BOOST_CHECK(nHits < 175);
BOOST_CHECK(rb1.contains(data[DATASIZE-1]));
- rb1.clear();
+ rb1.reset();
BOOST_CHECK(!rb1.contains(data[DATASIZE-1]));
// Now roll through data, make sure last 100 entries
@@ -527,7 +527,7 @@ BOOST_AUTO_TEST_CASE(rolling_bloom)
BOOST_CHECK(nHits < 100);
// last-1000-entry, 0.01% false positive:
- CRollingBloomFilter rb2(1000, 0.001, 0);
+ CRollingBloomFilter rb2(1000, 0.001);
for (int i = 0; i < DATASIZE; i++) {
rb2.insert(data[i]);
}
diff --git a/src/test/checkblock_tests.cpp b/src/test/checkblock_tests.cpp
index 7abfad151e..f7e2470617 100644
--- a/src/test/checkblock_tests.cpp
+++ b/src/test/checkblock_tests.cpp
@@ -2,16 +2,12 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-//
-// Unit tests for block.CheckBlock()
-//
-
-
-
#include "clientversion.h"
-#include "main.h"
-#include "utiltime.h"
+#include "consensus/validation.h"
+#include "main.h" // For CheckBlock
+#include "primitives/block.h"
#include "test/test_bitcoin.h"
+#include "utiltime.h"
#include <cstdio>
diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp
index 2e2cc2214b..13d848311a 100644
--- a/src/test/coins_tests.cpp
+++ b/src/test/coins_tests.cpp
@@ -59,6 +59,24 @@ public:
bool GetStats(CCoinsStats& stats) const { return false; }
};
+
+class CCoinsViewCacheTest : public CCoinsViewCache
+{
+public:
+ CCoinsViewCacheTest(CCoinsView* base) : CCoinsViewCache(base) {}
+
+ void SelfTest() const
+ {
+ // Manually recompute the dynamic usage of the whole data, and compare it.
+ size_t ret = memusage::DynamicUsage(cacheCoins);
+ for (CCoinsMap::iterator it = cacheCoins.begin(); it != cacheCoins.end(); it++) {
+ ret += it->second.coins.DynamicMemoryUsage();
+ }
+ BOOST_CHECK_EQUAL(DynamicMemoryUsage(), ret);
+ }
+
+};
+
}
BOOST_FIXTURE_TEST_SUITE(coins_tests, BasicTestingSetup)
@@ -90,8 +108,8 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
// The cache stack.
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
- std::vector<CCoinsViewCache*> stack; // A stack of CCoinsViewCaches on top.
- stack.push_back(new CCoinsViewCache(&base)); // Start with one cache.
+ std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
+ stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
// Use a limited set of random transaction ids, so we do test overwriting entries.
std::vector<uint256> txids;
@@ -136,6 +154,9 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
missed_an_entry = true;
}
}
+ BOOST_FOREACH(const CCoinsViewCacheTest *test, stack) {
+ test->SelfTest();
+ }
}
if (insecure_rand() % 100 == 0) {
@@ -152,7 +173,7 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
} else {
removed_all_caches = true;
}
- stack.push_back(new CCoinsViewCache(tip));
+ stack.push_back(new CCoinsViewCacheTest(tip));
if (stack.size() == 4) {
reached_4_caches = true;
}
diff --git a/src/test/data/bitcoin-util-test.json b/src/test/data/bitcoin-util-test.json
index 6090421cb6..3bf80ca434 100644
--- a/src/test/data/bitcoin-util-test.json
+++ b/src/test/data/bitcoin-util-test.json
@@ -52,9 +52,39 @@
["-create",
"in=4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485:0",
"set=privatekeys:[\"5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf\"]",
- "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\"}]",
+ "set=prevtxs:[{\"txid\":\"4d49a71ec9da436f71ec4ee231d04f292a29cd316f598bb7068feccabdc59485\",\"vout\":0,\"scriptPubKey\":\"76a91491b24bf9f5288532960ac687abb035127b1d28a588ac\"}]",
"sign=ALL",
"outaddr=0.001:193P6LtvS4nCnkDvM9uXn1gsSRqh4aDAz7"],
"output_cmp": "txcreatesign.hex"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "outdata=4:badhexdata"],
+ "return_code": 1
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "outdata=badhexdata"],
+ "return_code": 1
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "outdata=4:54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
+ "output_cmp": "txcreatedata1.hex"
+ },
+ { "exec": "./bitcoin-tx",
+ "args":
+ ["-create",
+ "in=5897de6bd6027a475eadd57019d4e6872c396d0716c4875a5f1a6fcfdf385c1f:0",
+ "outaddr=0.18:13tuJJDR2RgArmgfv6JScSdreahzgc4T6o",
+ "outdata=54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e"],
+ "output_cmp": "txcreatedata2.hex"
}
]
diff --git a/src/test/data/tx_invalid.json b/src/test/data/tx_invalid.json
index 31d33c63fb..5cad5af7c3 100644
--- a/src/test/data/tx_invalid.json
+++ b/src/test/data/tx_invalid.json
@@ -120,6 +120,78 @@
[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "IF CODESEPARATOR ENDIF 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 CHECKSIGVERIFY CODESEPARATOR 1"]],
"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a9000000004a483045022100fa4a74ba9fd59c59f46c3960cf90cbe0d2b743c471d24a3d5d6db6002af5eebb02204d70ec490fd0f7055a7c45f86514336e3a7f03503dacecabb247fc23f15c83510100ffffffff010000000000000000016a00000000", "P2SH"],
+["CHECKLOCKTIMEVERIFY tests"],
+
+["By-height locks, with argument just beyond tx nLockTime"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000fe64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000001 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument missing"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000001b1010000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument negative with by-blockheight nLockTime=0"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument negative with by-blocktime nLockTime=500,000,000"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "-1 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000004005194b1010000000100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Input locked"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000ffffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1ffffffff0100000000000000000002000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Another input being unlocked isn't sufficient; the CHECKLOCKTIMEVERIFY-using input must be unlocked"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"] ,
+ ["0000000000000000000000000000000000000000000000000000000000000200", 1, "1"]],
+"010000000200010000000000000000000000000000000000000000000000000000000000000000000000ffffffff00020000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument/tx height/time mismatch, both versions"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b100000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Argument 2^32 with nLockTime=2^32-1"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967296 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Same, but with nLockTime=2^31-1"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483648 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffff7f", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["6 byte non-minimally-encoded arguments are invalid even if their contents are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x06 0x000000000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Failure due to failing CHECKLOCKTIMEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Failure due to failing CHECKLOCKTIMEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/tx_valid.json b/src/test/data/tx_valid.json
index 182b88ef67..9744a3c848 100644
--- a/src/test/data/tx_valid.json
+++ b/src/test/data/tx_valid.json
@@ -187,5 +187,47 @@
"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"],
+["CHECKLOCKTIMEVERIFY tests"],
+
+["By-height locks, with argument == 0 and == tx nLockTime"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ff64cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["By-time locks, with argument just beyond tx nLockTime (but within numerical boundaries)"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "4294967295 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "500000000 NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000ffffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Any non-maxint nSequence is fine"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000feffffff0100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["The argument can be calculated rather than created directly by a PUSHDATA"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "499999999 1ADD NOP2 1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000065cd1d", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Perhaps even by an ADD producing a 5-byte result that is out of bounds for other opcodes"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "2147483647 2147483647 ADD NOP2 1"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000feffffff", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["5 byte non-minimally-encoded arguments are valid"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x05 0x0000000000 NOP2 1"]],
+"010000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in scriptSig"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "1"]],
+"01000000010001000000000000000000000000000000000000000000000000000000000000000000000251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
+["Valid CHECKLOCKTIMEVERIFY in redeemScript"],
+[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xc5b93064159b3b2d6ab506a41b1f50463771b988 EQUAL"]],
+"0100000001000100000000000000000000000000000000000000000000000000000000000000000000030251b1000000000100000000000000000001000000", "P2SH,CHECKLOCKTIMEVERIFY"],
+
["Make diffs cleaner by leaving a comment here without comma at the end"]
]
diff --git a/src/test/data/txcreatedata1.hex b/src/test/data/txcreatedata1.hex
new file mode 100644
index 0000000000..eccc7604e6
--- /dev/null
+++ b/src/test/data/txcreatedata1.hex
@@ -0,0 +1 @@
+01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0084d71700000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/src/test/data/txcreatedata2.hex b/src/test/data/txcreatedata2.hex
new file mode 100644
index 0000000000..3c7644c297
--- /dev/null
+++ b/src/test/data/txcreatedata2.hex
@@ -0,0 +1 @@
+01000000011f5c38dfcf6f1a5f5a87c416076d392c87e6d41970d5ad5e477a02d66bde97580000000000ffffffff0280a81201000000001976a9141fc11f39be1729bf973a7ab6a615ca4729d6457488ac0000000000000000526a4c4f54686973204f505f52455455524e207472616e73616374696f6e206f7574707574207761732063726561746564206279206d6f646966696564206372656174657261777472616e73616374696f6e2e00000000
diff --git a/src/test/data/txcreatesign.hex b/src/test/data/txcreatesign.hex
index 56ce28a865..a46fcc88cb 100644
--- a/src/test/data/txcreatesign.hex
+++ b/src/test/data/txcreatesign.hex
@@ -1 +1 @@
-01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d0000000000ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
+01000000018594c5bdcaec8f06b78b596f31cd292a294fd031e24eec716f43dac91ea7494d000000008b48304502210096a75056c9e2cc62b7214777b3d2a592cfda7092520126d4ebfcd6d590c99bd8022051bb746359cf98c0603f3004477eac68701132380db8facba19c89dc5ab5c5e201410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ffffffff01a0860100000000001976a9145834479edbbe0539b31ffd3a8f8ebadc2165ed0188ac00000000
diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp
index a0c5592a95..eb61a2884d 100644
--- a/src/test/getarg_tests.cpp
+++ b/src/test/getarg_tests.cpp
@@ -60,18 +60,18 @@ BOOST_AUTO_TEST_CASE(boolarg)
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
- ResetArgs("-foo -nofoo"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
-
- ResetArgs("-foo=1 -nofoo=1"); // -foo should win
- BOOST_CHECK(GetBoolArg("-foo", false));
- BOOST_CHECK(GetBoolArg("-foo", true));
+ ResetArgs("-foo -nofoo"); // -nofoo should win
+ BOOST_CHECK(!GetBoolArg("-foo", false));
+ BOOST_CHECK(!GetBoolArg("-foo", true));
- ResetArgs("-foo=0 -nofoo=0"); // -foo should win
+ ResetArgs("-foo=1 -nofoo=1"); // -nofoo should win
BOOST_CHECK(!GetBoolArg("-foo", false));
BOOST_CHECK(!GetBoolArg("-foo", true));
+ ResetArgs("-foo=0 -nofoo=0"); // -nofoo=0 should win
+ BOOST_CHECK(GetBoolArg("-foo", false));
+ BOOST_CHECK(GetBoolArg("-foo", true));
+
// New 0.6 feature: treat -- same as -:
ResetArgs("--foo=1");
BOOST_CHECK(GetBoolArg("-foo", false));
@@ -150,9 +150,9 @@ BOOST_AUTO_TEST_CASE(boolargno)
BOOST_CHECK(GetBoolArg("-foo", true));
BOOST_CHECK(GetBoolArg("-foo", false));
- ResetArgs("-foo --nofoo");
- BOOST_CHECK(GetBoolArg("-foo", true));
- BOOST_CHECK(GetBoolArg("-foo", false));
+ ResetArgs("-foo --nofoo"); // --nofoo should win
+ BOOST_CHECK(!GetBoolArg("-foo", true));
+ BOOST_CHECK(!GetBoolArg("-foo", false));
ResetArgs("-nofoo -foo"); // foo always wins:
BOOST_CHECK(GetBoolArg("-foo", true));
diff --git a/src/test/limitedmap_tests.cpp b/src/test/limitedmap_tests.cpp
new file mode 100644
index 0000000000..faaddffad8
--- /dev/null
+++ b/src/test/limitedmap_tests.cpp
@@ -0,0 +1,101 @@
+// Copyright (c) 2012-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.
+
+#include "limitedmap.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(limitedmap_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(limitedmap_test)
+{
+ // create a limitedmap capped at 10 items
+ limitedmap<int, int> map(10);
+
+ // check that the max size is 10
+ BOOST_CHECK(map.max_size() == 10);
+
+ // check that it's empty
+ BOOST_CHECK(map.size() == 0);
+
+ // insert (-1, -1)
+ map.insert(std::pair<int, int>(-1, -1));
+
+ // make sure that the size is updated
+ BOOST_CHECK(map.size() == 1);
+
+ // make sure that the new items is in the map
+ BOOST_CHECK(map.count(-1) == 1);
+
+ // insert 10 new items
+ for (int i = 0; i < 10; i++) {
+ map.insert(std::pair<int, int>(i, i + 1));
+ }
+
+ // make sure that the map now contains 10 items...
+ BOOST_CHECK(map.size() == 10);
+
+ // ...and that the first item has been discarded
+ BOOST_CHECK(map.count(-1) == 0);
+
+ // iterate over the map, both with an index and an iterator
+ limitedmap<int, int>::const_iterator it = map.begin();
+ for (int i = 0; i < 10; i++) {
+ // make sure the item is present
+ BOOST_CHECK(map.count(i) == 1);
+
+ // use the iterator to check for the expected key adn value
+ BOOST_CHECK(it->first == i);
+ BOOST_CHECK(it->second == i + 1);
+
+ // use find to check for the value
+ BOOST_CHECK(map.find(i)->second == i + 1);
+
+ // update and recheck
+ map.update(it, i + 2);
+ BOOST_CHECK(map.find(i)->second == i + 2);
+
+ it++;
+ }
+
+ // check that we've exhausted the iterator
+ BOOST_CHECK(it == map.end());
+
+ // resize the map to 5 items
+ map.max_size(5);
+
+ // check that the max size and size are now 5
+ BOOST_CHECK(map.max_size() == 5);
+ BOOST_CHECK(map.size() == 5);
+
+ // check that items less than 5 have been discarded
+ // and items greater than 5 are retained
+ for (int i = 0; i < 10; i++) {
+ if (i < 5) {
+ BOOST_CHECK(map.count(i) == 0);
+ } else {
+ BOOST_CHECK(map.count(i) == 1);
+ }
+ }
+
+ // erase some items not in the map
+ for (int i = 100; i < 1000; i += 100) {
+ map.erase(i);
+ }
+
+ // check that the size is unaffected
+ BOOST_CHECK(map.size() == 5);
+
+ // erase the remaining elements
+ for (int i = 5; i < 10; i++) {
+ map.erase(i);
+ }
+
+ // check that the map is now empty
+ BOOST_CHECK(map.empty());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp
index 9ec533bcca..21ae46d6e9 100644
--- a/src/test/main_tests.cpp
+++ b/src/test/main_tests.cpp
@@ -2,25 +2,58 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "primitives/transaction.h"
+#include "chainparams.h"
#include "main.h"
#include "test/test_bitcoin.h"
+#include <boost/signals2/signal.hpp>
#include <boost/test/unit_test.hpp>
BOOST_FIXTURE_TEST_SUITE(main_tests, TestingSetup)
+static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams)
+{
+ int maxHalvings = 64;
+ CAmount nInitialSubsidy = 50 * COIN;
+
+ CAmount nPreviousSubsidy = nInitialSubsidy * 2; // for height == 0
+ BOOST_CHECK_EQUAL(nPreviousSubsidy, nInitialSubsidy * 2);
+ for (int nHalvings = 0; nHalvings < maxHalvings; nHalvings++) {
+ int nHeight = nHalvings * consensusParams.nSubsidyHalvingInterval;
+ CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
+ BOOST_CHECK(nSubsidy <= nInitialSubsidy);
+ BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2);
+ nPreviousSubsidy = nSubsidy;
+ }
+ BOOST_CHECK_EQUAL(GetBlockSubsidy(maxHalvings * consensusParams.nSubsidyHalvingInterval, consensusParams), 0);
+}
+
+static void TestBlockSubsidyHalvings(int nSubsidyHalvingInterval)
+{
+ Consensus::Params consensusParams;
+ consensusParams.nSubsidyHalvingInterval = nSubsidyHalvingInterval;
+ TestBlockSubsidyHalvings(consensusParams);
+}
+
+BOOST_AUTO_TEST_CASE(block_subsidy_test)
+{
+ TestBlockSubsidyHalvings(Params(CBaseChainParams::MAIN).GetConsensus()); // As in main
+ TestBlockSubsidyHalvings(150); // As in regtest
+ TestBlockSubsidyHalvings(1000); // Just another interval
+}
+
BOOST_AUTO_TEST_CASE(subsidy_limit_test)
{
+ const Consensus::Params& consensusParams = Params(CBaseChainParams::MAIN).GetConsensus();
CAmount nSum = 0;
for (int nHeight = 0; nHeight < 14000000; nHeight += 1000) {
- CAmount nSubsidy = GetBlockValue(nHeight, 0);
+ CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams);
BOOST_CHECK(nSubsidy <= 50 * COIN);
nSum += nSubsidy * 1000;
BOOST_CHECK(MoneyRange(nSum));
}
- BOOST_CHECK(nSum == 2099999997690000ULL);
+ BOOST_CHECK_EQUAL(nSum, 2099999997690000ULL);
}
bool ReturnFalse() { return false; }
diff --git a/src/test/mempool_tests.cpp b/src/test/mempool_tests.cpp
index 0996e13c48..5bf1e98e8f 100644
--- a/src/test/mempool_tests.cpp
+++ b/src/test/mempool_tests.cpp
@@ -2,7 +2,6 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
#include "txmempool.h"
#include "util.h"
@@ -10,6 +9,7 @@
#include <boost/test/unit_test.hpp>
#include <list>
+#include <vector>
BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)
@@ -101,4 +101,184 @@ BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
removed.clear();
}
+void CheckSort(CTxMemPool &pool, std::vector<std::string> &sortedOrder)
+{
+ BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
+ CTxMemPool::indexed_transaction_set::nth_index<1>::type::iterator it = pool.mapTx.get<1>().begin();
+ int count=0;
+ for (; it != pool.mapTx.get<1>().end(); ++it, ++count) {
+ BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
+{
+ CTxMemPool pool(CFeeRate(0));
+
+ /* 3rd highest fee */
+ CMutableTransaction tx1 = CMutableTransaction();
+ tx1.vout.resize(1);
+ tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx1.vout[0].nValue = 10 * COIN;
+ pool.addUnchecked(tx1.GetHash(), CTxMemPoolEntry(tx1, 10000LL, 0, 10.0, 1, true));
+
+ /* highest fee */
+ CMutableTransaction tx2 = CMutableTransaction();
+ tx2.vout.resize(1);
+ tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx2.vout[0].nValue = 2 * COIN;
+ pool.addUnchecked(tx2.GetHash(), CTxMemPoolEntry(tx2, 20000LL, 0, 9.0, 1, true));
+
+ /* lowest fee */
+ CMutableTransaction tx3 = CMutableTransaction();
+ tx3.vout.resize(1);
+ tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx3.vout[0].nValue = 5 * COIN;
+ pool.addUnchecked(tx3.GetHash(), CTxMemPoolEntry(tx3, 0LL, 0, 100.0, 1, true));
+
+ /* 2nd highest fee */
+ CMutableTransaction tx4 = CMutableTransaction();
+ tx4.vout.resize(1);
+ tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx4.vout[0].nValue = 6 * COIN;
+ pool.addUnchecked(tx4.GetHash(), CTxMemPoolEntry(tx4, 15000LL, 0, 1.0, 1, true));
+
+ /* equal fee rate to tx1, but newer */
+ CMutableTransaction tx5 = CMutableTransaction();
+ tx5.vout.resize(1);
+ tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx5.vout[0].nValue = 11 * COIN;
+ pool.addUnchecked(tx5.GetHash(), CTxMemPoolEntry(tx5, 10000LL, 1, 10.0, 1, true));
+ BOOST_CHECK_EQUAL(pool.size(), 5);
+
+ std::vector<std::string> sortedOrder;
+ sortedOrder.resize(5);
+ sortedOrder[0] = tx2.GetHash().ToString(); // 20000
+ sortedOrder[1] = tx4.GetHash().ToString(); // 15000
+ sortedOrder[2] = tx1.GetHash().ToString(); // 10000
+ sortedOrder[3] = tx5.GetHash().ToString(); // 10000
+ sortedOrder[4] = tx3.GetHash().ToString(); // 0
+ CheckSort(pool, sortedOrder);
+
+ /* low fee but with high fee child */
+ /* tx6 -> tx7 -> tx8, tx9 -> tx10 */
+ CMutableTransaction tx6 = CMutableTransaction();
+ tx6.vout.resize(1);
+ tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx6.vout[0].nValue = 20 * COIN;
+ pool.addUnchecked(tx6.GetHash(), CTxMemPoolEntry(tx6, 0LL, 1, 10.0, 1, true));
+ BOOST_CHECK_EQUAL(pool.size(), 6);
+ // Check that at this point, tx6 is sorted low
+ sortedOrder.push_back(tx6.GetHash().ToString());
+ CheckSort(pool, sortedOrder);
+
+ CTxMemPool::setEntries setAncestors;
+ setAncestors.insert(pool.mapTx.find(tx6.GetHash()));
+ CMutableTransaction tx7 = CMutableTransaction();
+ tx7.vin.resize(1);
+ tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
+ tx7.vin[0].scriptSig = CScript() << OP_11;
+ tx7.vout.resize(2);
+ tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx7.vout[0].nValue = 10 * COIN;
+ tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx7.vout[1].nValue = 1 * COIN;
+
+ CTxMemPool::setEntries setAncestorsCalculated;
+ std::string dummy;
+ CTxMemPoolEntry entry7(tx7, 2000000LL, 1, 10.0, 1, true);
+ BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry7, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
+ BOOST_CHECK(setAncestorsCalculated == setAncestors);
+
+ pool.addUnchecked(tx7.GetHash(), CTxMemPoolEntry(tx7, 2000000LL, 1, 10.0, 1, true), setAncestors);
+ BOOST_CHECK_EQUAL(pool.size(), 7);
+
+ // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...
+ sortedOrder.erase(sortedOrder.end()-1);
+ sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
+ CheckSort(pool, sortedOrder);
+
+ /* low fee child of tx7 */
+ CMutableTransaction tx8 = CMutableTransaction();
+ tx8.vin.resize(1);
+ tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0);
+ tx8.vin[0].scriptSig = CScript() << OP_11;
+ tx8.vout.resize(1);
+ tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx8.vout[0].nValue = 10 * COIN;
+ setAncestors.insert(pool.mapTx.find(tx7.GetHash()));
+ pool.addUnchecked(tx8.GetHash(), CTxMemPoolEntry(tx8, 0LL, 2, 10.0, 1, true), setAncestors);
+
+ // Now tx8 should be sorted low, but tx6/tx both high
+ sortedOrder.push_back(tx8.GetHash().ToString());
+ CheckSort(pool, sortedOrder);
+
+ /* low fee child of tx7 */
+ CMutableTransaction tx9 = CMutableTransaction();
+ tx9.vin.resize(1);
+ tx9.vin[0].prevout = COutPoint(tx7.GetHash(), 1);
+ tx9.vin[0].scriptSig = CScript() << OP_11;
+ tx9.vout.resize(1);
+ tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx9.vout[0].nValue = 1 * COIN;
+ pool.addUnchecked(tx9.GetHash(), CTxMemPoolEntry(tx9, 0LL, 3, 10.0, 1, true), setAncestors);
+
+ // tx9 should be sorted low
+ BOOST_CHECK_EQUAL(pool.size(), 9);
+ sortedOrder.push_back(tx9.GetHash().ToString());
+ CheckSort(pool, sortedOrder);
+
+ std::vector<std::string> snapshotOrder = sortedOrder;
+
+ setAncestors.insert(pool.mapTx.find(tx8.GetHash()));
+ setAncestors.insert(pool.mapTx.find(tx9.GetHash()));
+ /* tx10 depends on tx8 and tx9 and has a high fee*/
+ CMutableTransaction tx10 = CMutableTransaction();
+ tx10.vin.resize(2);
+ tx10.vin[0].prevout = COutPoint(tx8.GetHash(), 0);
+ tx10.vin[0].scriptSig = CScript() << OP_11;
+ tx10.vin[1].prevout = COutPoint(tx9.GetHash(), 0);
+ tx10.vin[1].scriptSig = CScript() << OP_11;
+ tx10.vout.resize(1);
+ tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
+ tx10.vout[0].nValue = 10 * COIN;
+
+ setAncestorsCalculated.clear();
+ CTxMemPoolEntry entry10(tx10, 200000LL, 4, 10.0, 1, true);
+ BOOST_CHECK_EQUAL(pool.CalculateMemPoolAncestors(entry10, setAncestorsCalculated, 100, 1000000, 1000, 1000000, dummy), true);
+ BOOST_CHECK(setAncestorsCalculated == setAncestors);
+
+ pool.addUnchecked(tx10.GetHash(), CTxMemPoolEntry(tx10, 200000LL, 4, 10.0, 1, true), setAncestors);
+
+ /**
+ * tx8 and tx9 should both now be sorted higher
+ * Final order after tx10 is added:
+ *
+ * tx7 = 2.2M (4 txs)
+ * tx6 = 2.2M (5 txs)
+ * tx10 = 200k (1 tx)
+ * tx8 = 200k (2 txs)
+ * tx9 = 200k (2 txs)
+ * tx2 = 20000 (1)
+ * tx4 = 15000 (1)
+ * tx1 = 10000 (1)
+ * tx5 = 10000 (1)
+ * tx3 = 0 (1)
+ */
+ sortedOrder.erase(sortedOrder.end()-2, sortedOrder.end()); // take out tx8, tx9 from the end
+ sortedOrder.insert(sortedOrder.begin()+2, tx10.GetHash().ToString()); // tx10 is after tx6
+ sortedOrder.insert(sortedOrder.begin()+3, tx9.GetHash().ToString());
+ sortedOrder.insert(sortedOrder.begin()+3, tx8.GetHash().ToString());
+ CheckSort(pool, sortedOrder);
+
+ // there should be 10 transactions in the mempool
+ BOOST_CHECK_EQUAL(pool.size(), 10);
+
+ // Now try removing tx10 and verify the sort order returns to normal
+ std::list<CTransaction> removed;
+ pool.remove(pool.mapTx.find(tx10.GetHash())->GetTx(), removed, true);
+ CheckSort(pool, snapshotOrder);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp
index d7ea91607c..ad79a558c2 100644
--- a/src/test/miner_tests.cpp
+++ b/src/test/miner_tests.cpp
@@ -2,11 +2,17 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "chainparams.h"
+#include "coins.h"
+#include "consensus/validation.h"
#include "main.h"
#include "miner.h"
#include "pubkey.h"
+#include "script/standard.h"
+#include "txmempool.h"
#include "uint256.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
@@ -73,6 +79,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->nVersion = 1;
pblock->nTime = chainActive.Tip()->GetMedianTimePast()+1;
CMutableTransaction txCoinbase(pblock->vtx[0]);
+ txCoinbase.nVersion = 1;
txCoinbase.vin[0].scriptSig = CScript();
txCoinbase.vin[0].scriptSig.push_back(blockinfo[i].extranonce);
txCoinbase.vin[0].scriptSig.push_back(chainActive.Height());
@@ -83,7 +90,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
pblock->nNonce = blockinfo[i].nonce;
CValidationState state;
- BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
+ BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL));
BOOST_CHECK(state.IsValid());
pblock->hashPrevBlock = pblock->GetHash();
}
@@ -222,7 +229,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx.nLockTime = chainActive.Tip()->nHeight+1;
hash = tx.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!IsFinalTx(tx, chainActive.Tip()->nHeight + 1));
+ BOOST_CHECK(!CheckFinalTx(tx));
// time locked
tx2.vin.resize(1);
@@ -236,7 +243,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
tx2.nLockTime = chainActive.Tip()->GetMedianTimePast()+1;
hash = tx2.GetHash();
mempool.addUnchecked(hash, CTxMemPoolEntry(tx2, 11, GetTime(), 111.0, 11));
- BOOST_CHECK(!IsFinalTx(tx2));
+ BOOST_CHECK(!CheckFinalTx(tx2));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
@@ -248,8 +255,10 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
chainActive.Tip()->nHeight++;
SetMockTime(chainActive.Tip()->GetMedianTimePast()+2);
- BOOST_CHECK(IsFinalTx(tx, chainActive.Tip()->nHeight + 1));
- BOOST_CHECK(IsFinalTx(tx2));
+ // FIXME: we should *actually* create a new block so the following test
+ // works; CheckFinalTx() isn't fooled by monkey-patching nHeight.
+ //BOOST_CHECK(CheckFinalTx(tx));
+ //BOOST_CHECK(CheckFinalTx(tx2));
BOOST_CHECK(pblocktemplate = CreateNewBlock(scriptPubKey));
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx.size(), 3);
diff --git a/src/test/multisig_tests.cpp b/src/test/multisig_tests.cpp
index 6b189a6b55..b65c299adc 100644
--- a/src/test/multisig_tests.cpp
+++ b/src/test/multisig_tests.cpp
@@ -4,7 +4,7 @@
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/interpreter.h"
diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp
index cb357d295c..b1ef0ed24a 100644
--- a/src/test/netbase_tests.cpp
+++ b/src/test/netbase_tests.cpp
@@ -7,6 +7,7 @@
#include <string>
+#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
using namespace std;
@@ -117,6 +118,11 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:8")));
BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8").Match(CNetAddr("1:2:3:4:5:6:7:9")));
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:0/112").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
+ BOOST_CHECK(CSubNet("192.168.0.1/24").Match(CNetAddr("192.168.0.2")));
+ BOOST_CHECK(CSubNet("192.168.0.20/29").Match(CNetAddr("192.168.0.18")));
+ BOOST_CHECK(CSubNet("1.2.2.1/24").Match(CNetAddr("1.2.2.4")));
+ BOOST_CHECK(CSubNet("1.2.2.110/31").Match(CNetAddr("1.2.2.111")));
+ BOOST_CHECK(CSubNet("1.2.2.20/26").Match(CNetAddr("1.2.2.63")));
// All-Matching IPv6 Matches arbitrary IPv4 and IPv6
BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1:2:3:4:5:6:7:1234")));
BOOST_CHECK(CSubNet("::/0").Match(CNetAddr("1.2.3.4")));
@@ -138,6 +144,111 @@ BOOST_AUTO_TEST_CASE(subnet_test)
BOOST_CHECK(CSubNet("1:2:3:4:5:6:7:8/128").IsValid());
BOOST_CHECK(!CSubNet("1:2:3:4:5:6:7:8/129").IsValid());
BOOST_CHECK(!CSubNet("fuzzy").IsValid());
+
+ //CNetAddr constructor test
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).IsValid());
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.1")));
+ BOOST_CHECK(!CSubNet(CNetAddr("127.0.0.1")).Match(CNetAddr("127.0.0.2")));
+ BOOST_CHECK(CSubNet(CNetAddr("127.0.0.1")).ToString() == "127.0.0.1/32");
+
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).IsValid());
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:8")));
+ BOOST_CHECK(!CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).Match(CNetAddr("1:2:3:4:5:6:7:9")));
+ BOOST_CHECK(CSubNet(CNetAddr("1:2:3:4:5:6:7:8")).ToString() == "1:2:3:4:5:6:7:8/128");
+
+ CSubNet subnet = CSubNet("1.2.3.4/255.255.255.255");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/32");
+ subnet = CSubNet("1.2.3.4/255.255.255.254");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/31");
+ subnet = CSubNet("1.2.3.4/255.255.255.252");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.4/30");
+ subnet = CSubNet("1.2.3.4/255.255.255.248");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/29");
+ subnet = CSubNet("1.2.3.4/255.255.255.240");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/28");
+ subnet = CSubNet("1.2.3.4/255.255.255.224");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/27");
+ subnet = CSubNet("1.2.3.4/255.255.255.192");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/26");
+ subnet = CSubNet("1.2.3.4/255.255.255.128");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/25");
+ subnet = CSubNet("1.2.3.4/255.255.255.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.3.0/24");
+ subnet = CSubNet("1.2.3.4/255.255.254.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.2.0/23");
+ subnet = CSubNet("1.2.3.4/255.255.252.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/22");
+ subnet = CSubNet("1.2.3.4/255.255.248.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/21");
+ subnet = CSubNet("1.2.3.4/255.255.240.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/20");
+ subnet = CSubNet("1.2.3.4/255.255.224.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/19");
+ subnet = CSubNet("1.2.3.4/255.255.192.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/18");
+ subnet = CSubNet("1.2.3.4/255.255.128.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/17");
+ subnet = CSubNet("1.2.3.4/255.255.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/16");
+ subnet = CSubNet("1.2.3.4/255.254.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/15");
+ subnet = CSubNet("1.2.3.4/255.252.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/14");
+ subnet = CSubNet("1.2.3.4/255.248.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/13");
+ subnet = CSubNet("1.2.3.4/255.240.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/12");
+ subnet = CSubNet("1.2.3.4/255.224.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/11");
+ subnet = CSubNet("1.2.3.4/255.192.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/10");
+ subnet = CSubNet("1.2.3.4/255.128.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/9");
+ subnet = CSubNet("1.2.3.4/255.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.0.0.0/8");
+ subnet = CSubNet("1.2.3.4/254.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/7");
+ subnet = CSubNet("1.2.3.4/252.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/6");
+ subnet = CSubNet("1.2.3.4/248.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/5");
+ subnet = CSubNet("1.2.3.4/240.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/4");
+ subnet = CSubNet("1.2.3.4/224.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/3");
+ subnet = CSubNet("1.2.3.4/192.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/2");
+ subnet = CSubNet("1.2.3.4/128.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/1");
+ subnet = CSubNet("1.2.3.4/0.0.0.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "0.0.0.0/0");
+
+ subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/128");
+ subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:0000:0000:0000:0000:0000:0000:0000");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16");
+ subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "::/0");
+ subnet = CSubNet("1.2.3.4/255.255.232.0");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0");
+ subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
+ BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
+}
+
+BOOST_AUTO_TEST_CASE(netbase_getgroup)
+{
+ BOOST_CHECK(CNetAddr("127.0.0.1").GetGroup() == boost::assign::list_of(0)); // Local -> !Routable()
+ BOOST_CHECK(CNetAddr("257.0.0.1").GetGroup() == boost::assign::list_of(0)); // !Valid -> !Routable()
+ BOOST_CHECK(CNetAddr("10.0.0.1").GetGroup() == boost::assign::list_of(0)); // RFC1918 -> !Routable()
+ BOOST_CHECK(CNetAddr("169.254.1.1").GetGroup() == boost::assign::list_of(0)); // RFC3927 -> !Routable()
+ BOOST_CHECK(CNetAddr("1.2.3.4").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // IPv4
+ BOOST_CHECK(CNetAddr("::FFFF:0:102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6145
+ BOOST_CHECK(CNetAddr("64:FF9B::102:304").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC6052
+ BOOST_CHECK(CNetAddr("2002:102:304:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC3964
+ BOOST_CHECK(CNetAddr("2001:0:9999:9999:9999:9999:FEFD:FCFB").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV4)(1)(2)); // RFC4380
+ BOOST_CHECK(CNetAddr("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").GetGroup() == boost::assign::list_of((unsigned char)NET_TOR)(239)); // Tor
+ BOOST_CHECK(CNetAddr("2001:470:abcd:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(4)(112)(175)); //he.net
+ BOOST_CHECK(CNetAddr("2001:2001:9999:9999:9999:9999:9999:9999").GetGroup() == boost::assign::list_of((unsigned char)NET_IPV6)(32)(1)(32)(1)); //IPv6
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp
new file mode 100644
index 0000000000..cb64ee7c69
--- /dev/null
+++ b/src/test/policyestimator_tests.cpp
@@ -0,0 +1,186 @@
+// Copyright (c) 2011-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.
+
+#include "policy/fees.h"
+#include "txmempool.h"
+#include "uint256.h"
+#include "util.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
+{
+ CTxMemPool mpool(CFeeRate(1000));
+ CAmount basefee(2000);
+ double basepri = 1e6;
+ CAmount deltaFee(100);
+ double deltaPri=5e5;
+ std::vector<CAmount> feeV[2];
+ std::vector<double> priV[2];
+
+ // Populate vectors of increasing fees or priorities
+ for (int j = 0; j < 10; j++) {
+ //V[0] is for fee transactions
+ feeV[0].push_back(basefee * (j+1));
+ priV[0].push_back(0);
+ //V[1] is for priority transactions
+ feeV[1].push_back(CAmount(0));
+ priV[1].push_back(basepri * pow(10, j+1));
+ }
+
+ // Store the hashes of transactions that have been
+ // added to the mempool by their associate fee/pri
+ // txHashes[j] is populated with transactions either of
+ // fee = basefee * (j+1) OR pri = 10^6 * 10^(j+1)
+ std::vector<uint256> txHashes[10];
+
+ // Create a transaction template
+ CScript garbage;
+ for (unsigned int i = 0; i < 128; i++)
+ garbage.push_back('X');
+ CMutableTransaction tx;
+ std::list<CTransaction> dummyConflicted;
+ tx.vin.resize(1);
+ tx.vin[0].scriptSig = garbage;
+ tx.vout.resize(1);
+ tx.vout[0].nValue=0LL;
+ CFeeRate baseRate(basefee, ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
+
+ // Create a fake block
+ std::vector<CTransaction> block;
+ int blocknum = 0;
+
+ // Loop through 200 blocks
+ // At a decay .998 and 4 fee transactions per block
+ // This makes the tx count about 1.33 per bucket, above the 1 threshold
+ while (blocknum < 200) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ txHashes[j].push_back(hash);
+ }
+ }
+ //Create blocks where higher fee/pri txs are included more often
+ for (int h = 0; h <= blocknum%10; h++) {
+ // 10/10 blocks add highest fee/pri transactions
+ // 9/10 blocks add 2nd highest and so on until ...
+ // 1/10 blocks add lowest fee/pri transactions
+ while (txHashes[9-h].size()) {
+ CTransaction btx;
+ if (mpool.lookup(txHashes[9-h].back(), btx))
+ block.push_back(btx);
+ txHashes[9-h].pop_back();
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ block.clear();
+ if (blocknum == 30) {
+ // At this point we should need to combine 5 buckets to get enough data points
+ // So estimateFee(1) should fail and estimateFee(2) should return somewhere around
+ // 8*baserate
+ BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
+ BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
+ }
+ }
+
+ std::vector<CAmount> origFeeEst;
+ std::vector<double> origPriEst;
+ // Highest feerate is 10*baseRate and gets in all blocks,
+ // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
+ // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
+ // so estimateFee(1) should return 9*baseRate.
+ // Third highest feerate has 90% chance of being included by 2 blocks,
+ // so estimateFee(2) should return 8*baseRate etc...
+ for (int i = 1; i < 10;i++) {
+ origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
+ origPriEst.push_back(mpool.estimatePriority(i));
+ if (i > 1) { // Fee estimates should be monotonically decreasing
+ BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
+ BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
+ }
+ BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee);
+ BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee);
+ BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri);
+ BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri);
+ }
+
+ // Mine 50 more blocks with no transactions happening, estimates shouldn't change
+ // We haven't decayed the moving average enough so we still have enough data points in every bucket
+ while (blocknum < 250)
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+
+ // Mine 15 more blocks with lots of transactions happening and not getting mined
+ // Estimates should go up
+ while (blocknum < 265) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ txHashes[j].push_back(hash);
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ }
+
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+ // Mine all those transactions
+ // Estimates should still not be below original
+ for (int j = 0; j < 10; j++) {
+ while(txHashes[j].size()) {
+ CTransaction btx;
+ if (mpool.lookup(txHashes[j].back(), btx))
+ block.push_back(btx);
+ txHashes[j].pop_back();
+ }
+ }
+ mpool.removeForBlock(block, 265, dummyConflicted);
+ block.clear();
+ for (int i = 1; i < 10;i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
+ }
+
+ // Mine 100 more blocks where everything is mined every block
+ // Estimates should be below original estimates (not possible for last estimate)
+ while (blocknum < 365) {
+ for (int j = 0; j < 10; j++) { // For each fee/pri multiple
+ for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
+ tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
+ uint256 hash = tx.GetHash();
+ mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
+ CTransaction btx;
+ if (mpool.lookup(hash, btx))
+ block.push_back(btx);
+ }
+ }
+ mpool.removeForBlock(block, ++blocknum, dummyConflicted);
+ block.clear();
+ }
+ for (int i = 1; i < 9; i++) {
+ BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
+ BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/pow_tests.cpp b/src/test/pow_tests.cpp
index a436749287..b6eb39bc38 100644
--- a/src/test/pow_tests.cpp
+++ b/src/test/pow_tests.cpp
@@ -2,8 +2,10 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "chain.h"
+#include "chainparams.h"
#include "pow.h"
+#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/reverselock_tests.cpp b/src/test/reverselock_tests.cpp
new file mode 100644
index 0000000000..e7e627ae0f
--- /dev/null
+++ b/src/test/reverselock_tests.cpp
@@ -0,0 +1,64 @@
+// 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.
+
+#include "reverselock.h"
+#include "test/test_bitcoin.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_FIXTURE_TEST_SUITE(reverselock_tests, BasicTestingSetup)
+
+BOOST_AUTO_TEST_CASE(reverselock_basics)
+{
+ boost::mutex mutex;
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ BOOST_CHECK(lock.owns_lock());
+ {
+ reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
+ BOOST_CHECK(!lock.owns_lock());
+ }
+ BOOST_CHECK(lock.owns_lock());
+}
+
+BOOST_AUTO_TEST_CASE(reverselock_errors)
+{
+ boost::mutex mutex;
+ boost::unique_lock<boost::mutex> lock(mutex);
+
+ // Make sure trying to reverse lock an unlocked lock fails
+ lock.unlock();
+
+ BOOST_CHECK(!lock.owns_lock());
+
+ bool failed = false;
+ try {
+ reverse_lock<boost::unique_lock<boost::mutex> > rlock(lock);
+ } catch(...) {
+ failed = true;
+ }
+
+ 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;
+
+ 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(locked && failed);
+ BOOST_CHECK(lock.owns_lock());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp
index 45cb551d04..1bd59497ff 100644
--- a/src/test/rpc_tests.cpp
+++ b/src/test/rpc_tests.cpp
@@ -13,35 +13,36 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-Array
+UniValue
createArgs(int nRequired, const char* address1=NULL, const char* address2=NULL)
{
- Array result;
+ UniValue result(UniValue::VARR);
result.push_back(nRequired);
- Array addresses;
+ UniValue addresses(UniValue::VARR);
if (address1) addresses.push_back(address1);
if (address2) addresses.push_back(address2);
result.push_back(addresses);
return result;
}
-Value CallRPC(string args)
+UniValue CallRPC(string args)
{
vector<string> vArgs;
boost::split(vArgs, args, boost::is_any_of(" \t"));
string strMethod = vArgs[0];
vArgs.erase(vArgs.begin());
- Array params = RPCConvertValues(strMethod, vArgs);
+ UniValue params = RPCConvertValues(strMethod, vArgs);
rpcfn_type method = tableRPC[strMethod]->actor;
try {
- Value result = (*method)(params, false);
+ UniValue result = (*method)(params, false);
return result;
}
- catch (const Object& objError) {
+ catch (const UniValue& objError) {
throw runtime_error(find_value(objError, "message").get_str());
}
}
@@ -52,7 +53,7 @@ BOOST_FIXTURE_TEST_SUITE(rpc_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_rawparams)
{
// Test raw transaction API argument handling
- Value r;
+ UniValue r;
BOOST_CHECK_THROW(CallRPC("getrawtransaction"), runtime_error);
BOOST_CHECK_THROW(CallRPC("getrawtransaction not_hex"), runtime_error);
@@ -92,7 +93,7 @@ BOOST_AUTO_TEST_CASE(rpc_rawparams)
BOOST_AUTO_TEST_CASE(rpc_rawsign)
{
- Value r;
+ UniValue r;
// input is a 1-of-2 multisig (so is output):
string prevout =
"[{\"txid\":\"b4cc287e58f87cdae59417329f710f3ecd75a4ee1d2872b7248f50977c8493f3\","
@@ -109,27 +110,71 @@ BOOST_AUTO_TEST_CASE(rpc_rawsign)
BOOST_CHECK(find_value(r.get_obj(), "complete").get_bool() == true);
}
+BOOST_AUTO_TEST_CASE(rpc_createraw_op_return)
+{
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\"}"));
+
+ // Allow more than one data transaction output
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"68656c6c6f776f726c64\",\"data\":\"68656c6c6f776f726c64\"}"));
+
+ // Key not "data" (bad address)
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"somedata\":\"68656c6c6f776f726c64\"}"), runtime_error);
+
+ // Bad hex encoding of data output
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345\"}"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"12345g\"}"), runtime_error);
+
+ // Data 81 bytes long
+ BOOST_CHECK_NO_THROW(CallRPC("createrawtransaction [{\"txid\":\"a3b807410df0b60fcb9736768df5823938b2f838694939ba45f3c0a1bff150ed\",\"vout\":0}] {\"data\":\"010203040506070809101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081\"}"));
+}
+
BOOST_AUTO_TEST_CASE(rpc_format_monetary_values)
{
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(0LL), false), "0.00000000");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(1LL), false), "0.00000001");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(17622195LL), false), "0.17622195");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(50000000LL), false), "0.50000000");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(89898989LL), false), "0.89898989");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(100000000LL), false), "1.00000000");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999990LL), false), "20999999.99999990");
- BOOST_CHECK_EQUAL(write_string(ValueFromAmount(2099999999999999LL), false), "20999999.99999999");
+ BOOST_CHECK(ValueFromAmount(0LL).write() == "0.00000000");
+ BOOST_CHECK(ValueFromAmount(1LL).write() == "0.00000001");
+ BOOST_CHECK(ValueFromAmount(17622195LL).write() == "0.17622195");
+ BOOST_CHECK(ValueFromAmount(50000000LL).write() == "0.50000000");
+ BOOST_CHECK(ValueFromAmount(89898989LL).write() == "0.89898989");
+ BOOST_CHECK(ValueFromAmount(100000000LL).write() == "1.00000000");
+ BOOST_CHECK(ValueFromAmount(2099999999999990LL).write() == "20999999.99999990");
+ BOOST_CHECK(ValueFromAmount(2099999999999999LL).write() == "20999999.99999999");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(0).write(), "0.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount((COIN/10000)*123456789).write(), "12345.67890000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN).write(), "-1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(-COIN/10).write(), "-0.10000000");
+
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000000).write(), "100000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000000).write(), "10000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000000).write(), "1000000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100000).write(), "100000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10000).write(), "10000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*1000).write(), "1000.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*100).write(), "100.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN*10).write(), "10.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN).write(), "1.00000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10).write(), "0.10000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100).write(), "0.01000000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000).write(), "0.00100000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000).write(), "0.00010000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000).write(), "0.00001000");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/1000000).write(), "0.00000100");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/10000000).write(), "0.00000010");
+ BOOST_CHECK_EQUAL(ValueFromAmount(COIN/100000000).write(), "0.00000001");
}
-static Value ValueFromString(const std::string &str)
+static UniValue ValueFromString(const std::string &str)
{
- Value value;
- BOOST_CHECK(read_string(str, value));
+ UniValue value;
+ BOOST_CHECK(value.setNumStr(str));
return value;
}
BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
{
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("-0.00000001")), UniValue);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0")), 0LL);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000000")), 0LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001")), 1LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.17622195")), 17622195LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.5")), 50000000LL);
@@ -138,21 +183,128 @@ BOOST_AUTO_TEST_CASE(rpc_parse_monetary_values)
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1.00000000")), 100000000LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.9999999")), 2099999999999990LL);
BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("20999999.99999999")), 2099999999999999LL);
+
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("1e-8")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.1e-7")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.01e-6")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.0000000000000000000000000000000000000000000000000000000000000000000000000001e+68")), COIN/100000000);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("10000000000000000000000000000000000000000000000000000000000000000e-64")), COIN);
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000e64")), COIN);
+
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e-9")), UniValue); //should fail
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("0.000000019")), UniValue); //should fail
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.00000001000000")), 1LL); //should pass, cut trailing 0
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("19e-9")), UniValue); //should fail
+ BOOST_CHECK_EQUAL(AmountFromValue(ValueFromString("0.19e-6")), 19); //should pass, leading 0 is present
+
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("92233720368.54775808")), UniValue); //overflow error
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e+11")), UniValue); //overflow error
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("1e11")), UniValue); //overflow error signless
+ BOOST_CHECK_THROW(AmountFromValue(ValueFromString("93e+9")), UniValue); //overflow error
}
-BOOST_AUTO_TEST_CASE(rpc_boostasiotocnetaddr)
+BOOST_AUTO_TEST_CASE(json_parse_errors)
{
- // Check IPv4 addresses
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("1.2.3.4")).ToString(), "1.2.3.4");
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("127.0.0.1")).ToString(), "127.0.0.1");
- // Check IPv6 addresses
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::1")).ToString(), "::1");
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("123:4567:89ab:cdef:123:4567:89ab:cdef")).ToString(),
- "123:4567:89ab:cdef:123:4567:89ab:cdef");
- // v4 compatible must be interpreted as IPv4
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::0:127.0.0.1")).ToString(), "127.0.0.1");
- // v4 mapped must be interpreted as IPv4
- BOOST_CHECK_EQUAL(BoostAsioToCNetAddr(boost::asio::ip::address::from_string("::ffff:127.0.0.1")).ToString(), "127.0.0.1");
+ // Valid
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
+ // Valid, with leading or trailing whitespace
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
+ BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
+
+ BOOST_CHECK_THROW(AmountFromValue(ParseNonRFCJSONValue(".19e-6")), std::runtime_error); //should fail, missing leading 0, therefore invalid JSON
+ BOOST_CHECK_EQUAL(AmountFromValue(ParseNonRFCJSONValue("0.00000000000000000000000000000000000001e+30 ")), 1);
+ // Invalid, initial garbage
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("[1.0"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("a1.0"), std::runtime_error);
+ // Invalid, trailing garbage
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
+ // BTC addresses should fail parsing
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
+ BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(rpc_ban)
+{
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+
+ UniValue r;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.0:8334")), runtime_error); //portnumber for setban not allowed
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ UniValue ar = r.get_array();
+ UniValue o1 = ar[0].get_obj();
+ UniValue adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/32");
+ BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0 remove")));;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 1607731200 true")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ UniValue banned_until = find_value(o1, "banned_until");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
+ BOOST_CHECK_EQUAL(banned_until.get_int64(), 1607731200); // absolute time check
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/24 add 200")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ banned_until = find_value(o1, "banned_until");
+ BOOST_CHECK_EQUAL(adr.get_str(), "127.0.0.0/24");
+ int64_t now = GetTime();
+ BOOST_CHECK(banned_until.get_int64() > now);
+ BOOST_CHECK(banned_until.get_int64()-now <= 200);
+
+ // must throw an exception because 127.0.0.1 is in already banned suubnet range
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.0.1 add")), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("setban 127.0.0.0/24 remove")));;
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 127.0.0.0/255.255.0.0 add")));
+ BOOST_CHECK_THROW(r = CallRPC(string("setban 127.0.1.1 add")), runtime_error);
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ BOOST_CHECK_EQUAL(ar.size(), 0);
+
+
+ BOOST_CHECK_THROW(r = CallRPC(string("setban test add")), runtime_error); //invalid IP
+
+ //IPv6 tests
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban FE80:0000:0000:0000:0202:B3FF:FE1E:8329 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "fe80::202:b3ff:fe1e:8329/128");
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:db8::/ffff:fffc:0:0:0:0:0:0 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "2001:db8::/30");
+
+ BOOST_CHECK_NO_THROW(CallRPC(string("clearbanned")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("setban 2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128 add")));
+ BOOST_CHECK_NO_THROW(r = CallRPC(string("listbanned")));
+ ar = r.get_array();
+ o1 = ar[0].get_obj();
+ adr = find_value(o1, "address");
+ BOOST_CHECK_EQUAL(adr.get_str(), "2001:4d48:ac57:400:cacf:e9ff:fe1d:9c63/128");
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp
index 4d5e92cbd4..52f41be8ae 100644
--- a/src/test/rpc_wallet_tests.cpp
+++ b/src/test/rpc_wallet_tests.cpp
@@ -14,11 +14,12 @@
#include <boost/algorithm/string.hpp>
#include <boost/test/unit_test.hpp>
+#include "univalue/univalue.h"
+
using namespace std;
-using namespace json_spirit;
-extern Array createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
-extern Value CallRPC(string args);
+extern UniValue createArgs(int nRequired, const char* address1 = NULL, const char* address2 = NULL);
+extern UniValue CallRPC(string args);
extern CWallet* pwalletMain;
@@ -26,8 +27,6 @@ BOOST_FIXTURE_TEST_SUITE(rpc_wallet_tests, TestingSetup)
BOOST_AUTO_TEST_CASE(rpc_addmultisig)
{
- LOCK(pwalletMain->cs_wallet);
-
rpcfn_type addmultisig = tableRPC["addmultisigaddress"]->actor;
// old, 65-byte-long:
@@ -35,7 +34,7 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
// new, compressed:
const char address2Hex[] = "0388c2037017c62240b6b72ac1a2a5f94da790596ebd06177c8572752922165cb4";
- Value v;
+ UniValue v;
CBitcoinAddress address;
BOOST_CHECK_NO_THROW(v = addmultisig(createArgs(1, address1Hex), false));
address.SetString(v.get_str());
@@ -66,26 +65,29 @@ BOOST_AUTO_TEST_CASE(rpc_addmultisig)
BOOST_AUTO_TEST_CASE(rpc_wallet)
{
// Test RPC calls for various wallet statistics
- Value r;
-
- LOCK2(cs_main, pwalletMain->cs_wallet);
-
- CPubKey demoPubkey = pwalletMain->GenerateNewKey();
- CBitcoinAddress demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
- Value retValue;
+ UniValue r;
+ CPubKey demoPubkey;
+ CBitcoinAddress demoAddress;
+ UniValue retValue;
string strAccount = "walletDemoAccount";
- string strPurpose = "receive";
- BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
- CWalletDB walletdb(pwalletMain->strWalletFile);
- CAccount account;
- account.vchPubKey = demoPubkey;
- pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
- walletdb.WriteAccount(strAccount, account);
- });
-
- CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
- CBitcoinAddress setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
-
+ CBitcoinAddress setaccountDemoAddress;
+ {
+ LOCK(pwalletMain->cs_wallet);
+
+ demoPubkey = pwalletMain->GenerateNewKey();
+ demoAddress = CBitcoinAddress(CTxDestination(demoPubkey.GetID()));
+ string strPurpose = "receive";
+ BOOST_CHECK_NO_THROW({ /*Initialize Wallet with an account */
+ CWalletDB walletdb(pwalletMain->strWalletFile);
+ CAccount account;
+ account.vchPubKey = demoPubkey;
+ pwalletMain->SetAddressBook(account.vchPubKey.GetID(), strAccount, strPurpose);
+ walletdb.WriteAccount(strAccount, account);
+ });
+
+ CPubKey setaccountDemoPubkey = pwalletMain->GenerateNewKey();
+ setaccountDemoAddress = CBitcoinAddress(CTxDestination(setaccountDemoPubkey.GetID()));
+ }
/*********************************
* setaccount
*********************************/
@@ -213,9 +215,15 @@ BOOST_AUTO_TEST_CASE(rpc_wallet)
*********************************/
BOOST_CHECK_THROW(CallRPC("getaddressesbyaccount"), runtime_error);
BOOST_CHECK_NO_THROW(retValue = CallRPC("getaddressesbyaccount " + strAccount));
- Array arr = retValue.get_array();
+ UniValue arr = retValue.get_array();
BOOST_CHECK(arr.size() > 0);
BOOST_CHECK(CBitcoinAddress(arr[0].get_str()).Get() == demoAddress.Get());
+
+ /*********************************
+ * fundrawtransaction
+ *********************************/
+ BOOST_CHECK_THROW(CallRPC("fundrawtransaction 28z"), runtime_error);
+ BOOST_CHECK_THROW(CallRPC("fundrawtransaction 01000000000180969800000000001976a91450ce0a4b0ee0ddeb633da85199728b940ac3fe9488ac00000000"), runtime_error);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/scheduler_tests.cpp b/src/test/scheduler_tests.cpp
new file mode 100644
index 0000000000..cb1a427db0
--- /dev/null
+++ b/src/test/scheduler_tests.cpp
@@ -0,0 +1,119 @@
+// Copyright (c) 2012-2013 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "random.h"
+#include "scheduler.h"
+
+#include "test/test_bitcoin.h"
+
+#include <boost/bind.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include <boost/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(scheduler_tests)
+
+static void microTask(CScheduler& s, boost::mutex& mutex, int& counter, int delta, boost::chrono::system_clock::time_point rescheduleTime)
+{
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ counter += delta;
+ }
+ boost::chrono::system_clock::time_point noTime = boost::chrono::system_clock::time_point::min();
+ if (rescheduleTime != noTime) {
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(s), boost::ref(mutex), boost::ref(counter), -delta + 1, noTime);
+ s.schedule(f, rescheduleTime);
+ }
+}
+
+static void MicroSleep(uint64_t n)
+{
+#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
+ boost::this_thread::sleep_for(boost::chrono::microseconds(n));
+#elif defined(HAVE_WORKING_BOOST_SLEEP)
+ boost::this_thread::sleep(boost::posix_time::microseconds(n));
+#else
+ //should never get here
+ #error missing boost sleep implementation
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(manythreads)
+{
+ seed_insecure_rand(false);
+
+ // Stress test: hundreds of microsecond-scheduled tasks,
+ // serviced by 10 threads.
+ //
+ // So... ten shared counters, which if all the tasks execute
+ // properly will sum to the number of tasks done.
+ // Each task adds or subtracts from one of the counters a
+ // random amount, and then schedules another task 0-1000
+ // microseconds in the future to subtract or add from
+ // the counter -random_amount+1, so in the end the shared
+ // counters should sum to the number of initial tasks performed.
+ CScheduler microTasks;
+
+ boost::mutex counterMutex[10];
+ int counter[10] = { 0 };
+ boost::random::mt19937 rng(insecure_rand());
+ boost::random::uniform_int_distribution<> zeroToNine(0, 9);
+ boost::random::uniform_int_distribution<> randomMsec(-11, 1000);
+ boost::random::uniform_int_distribution<> randomDelta(-1000, 1000);
+
+ boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();
+ boost::chrono::system_clock::time_point now = start;
+ boost::chrono::system_clock::time_point first, last;
+ size_t nTasks = microTasks.getQueueInfo(first, last);
+ BOOST_CHECK(nTasks == 0);
+
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+ nTasks = microTasks.getQueueInfo(first, last);
+ BOOST_CHECK(nTasks == 100);
+ BOOST_CHECK(first < last);
+ BOOST_CHECK(last > now);
+
+ // As soon as these are created they will start running and servicing the queue
+ boost::thread_group microThreads;
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+
+ MicroSleep(600);
+ now = boost::chrono::system_clock::now();
+
+ // More threads and more tasks:
+ for (int i = 0; i < 5; i++)
+ microThreads.create_thread(boost::bind(&CScheduler::serviceQueue, &microTasks));
+ for (int i = 0; i < 100; i++) {
+ boost::chrono::system_clock::time_point t = now + boost::chrono::microseconds(randomMsec(rng));
+ boost::chrono::system_clock::time_point tReschedule = now + boost::chrono::microseconds(500 + randomMsec(rng));
+ int whichCounter = zeroToNine(rng);
+ CScheduler::Function f = boost::bind(&microTask, boost::ref(microTasks),
+ boost::ref(counterMutex[whichCounter]), boost::ref(counter[whichCounter]),
+ randomDelta(rng), tReschedule);
+ microTasks.schedule(f, t);
+ }
+
+ // Drain the task queue then exit threads
+ microTasks.stop(true);
+ microThreads.join_all(); // ... wait until all the threads are done
+
+ int counterSum = 0;
+ for (int i = 0; i < 10; i++) {
+ BOOST_CHECK(counter[i] != 0);
+ counterSum += counter[i];
+ }
+ BOOST_CHECK_EQUAL(counterSum, 200);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp
index c8cfe28729..16c9a4a868 100644
--- a/src/test/script_P2SH_tests.cpp
+++ b/src/test/script_P2SH_tests.cpp
@@ -5,6 +5,7 @@
#include "key.h"
#include "keystore.h"
#include "main.h"
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index c0614cca43..37c046935f 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -8,11 +8,11 @@
#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
#include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "test/test_bitcoin.h"
#if defined(HAVE_CONSENSUS_LIB)
@@ -26,12 +26,10 @@
#include <boost/foreach.hpp>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// Uncomment if you want to output updated JSON tests.
// #define UPDATE_JSON_TESTS
@@ -41,15 +39,15 @@ static const unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
unsigned int ParseScriptFlags(string strFlags);
string FormatScriptFlags(unsigned int flags);
-Array
+UniValue
read_json(const std::string& jsondata)
{
- Value v;
+ UniValue v;
- if (!read_string(jsondata, v) || v.type() != array_type)
+ if (!v.read(jsondata) || !v.isArray())
{
BOOST_ERROR("Parse error.");
- return Array();
+ return UniValue(UniValue::VARR);
}
return v.get_array();
}
@@ -295,10 +293,10 @@ public:
return *this;
}
- Array GetJSON()
+ UniValue GetJSON()
{
DoPush();
- Array array;
+ UniValue array(UniValue::VARR);
array.push_back(FormatScript(spendTx.vin[0].scriptSig));
array.push_back(FormatScript(creditTx.vout[0].scriptPubKey));
array.push_back(FormatScriptFlags(flags));
@@ -582,14 +580,16 @@ BOOST_AUTO_TEST_CASE(script_build)
std::set<std::string> tests_bad;
{
- Array json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- Array json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue json_good = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue json_bad = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, json_good) {
- tests_good.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_good.size(); idx++) {
+ const UniValue& tv = json_good[idx];
+ tests_good.insert(tv.get_array().write());
}
- BOOST_FOREACH(Value& tv, json_bad) {
- tests_bad.insert(write_string(Value(tv.get_array()), true));
+ for (unsigned int idx = 0; idx < json_bad.size(); idx++) {
+ const UniValue& tv = json_bad[idx];
+ tests_bad.insert(tv.get_array().write());
}
}
@@ -598,7 +598,7 @@ BOOST_AUTO_TEST_CASE(script_build)
BOOST_FOREACH(TestBuilder& test, good) {
test.Test(true);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_good.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_valid test: " + test.GetComment());
@@ -608,7 +608,7 @@ BOOST_AUTO_TEST_CASE(script_build)
}
BOOST_FOREACH(TestBuilder& test, bad) {
test.Test(false);
- std::string str = write_string(Value(test.GetJSON()), true);
+ std::string str = test.GetJSON().write();
#ifndef UPDATE_JSON_TESTS
if (tests_bad.count(str) == 0) {
BOOST_CHECK_MESSAGE(false, "Missing auto script_invalid test: " + test.GetComment());
@@ -634,12 +634,11 @@ BOOST_AUTO_TEST_CASE(script_valid)
// Inner arrays are [ "scriptSig", "scriptPubKey", "flags" ]
// ... where scriptSig and scriptPubKey are stringified
// scripts.
- Array tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
+ UniValue tests = read_json(std::string(json_tests::script_valid, json_tests::script_valid + sizeof(json_tests::script_valid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
@@ -660,13 +659,12 @@ BOOST_AUTO_TEST_CASE(script_valid)
BOOST_AUTO_TEST_CASE(script_invalid)
{
// Scripts that should evaluate as invalid
- Array tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
+ UniValue tests = read_json(std::string(json_tests::script_invalid, json_tests::script_invalid + sizeof(json_tests::script_invalid)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test.size() < 3) // Allow size > 3; extra stuff ignored (useful for comments)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test.size() < 3) // Allow size > 2; extra stuff ignored (useful for comments)
{
if (test.size() != 1) {
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/scriptnum_tests.cpp b/src/test/scriptnum_tests.cpp
index 24c7dd3d5a..d95724dbe1 100644
--- a/src/test/scriptnum_tests.cpp
+++ b/src/test/scriptnum_tests.cpp
@@ -145,7 +145,7 @@ static void RunCreate(const int64_t& num)
{
CheckCreateInt(num);
CScriptNum scriptnum(num);
- if (scriptnum.getvch().size() <= CScriptNum::nMaxNumSize)
+ if (scriptnum.getvch().size() <= CScriptNum::nDefaultMaxNumSize)
CheckCreateVch(num);
else
{
diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp
index afb7a41bbd..4b96461562 100644
--- a/src/test/sighash_tests.cpp
+++ b/src/test/sighash_tests.cpp
@@ -2,25 +2,27 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#include "consensus/validation.h"
#include "data/sighash.json.h"
-#include "main.h"
+#include "hash.h"
+#include "main.h" // For CheckTransaction
#include "random.h"
-#include "serialize.h"
-#include "script/script.h"
#include "script/interpreter.h"
+#include "script/script.h"
+#include "serialize.h"
+#include "streams.h"
+#include "test/test_bitcoin.h"
#include "util.h"
+#include "utilstrencodings.h"
#include "version.h"
-#include "test/test_bitcoin.h"
#include <iostream>
#include <boost/test/unit_test.hpp>
-#include "json/json_spirit_reader_template.h"
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_writer_template.h"
-using namespace json_spirit;
-extern Array read_json(const std::string& jsondata);
+#include "univalue/univalue.h"
+
+extern UniValue read_json(const std::string& jsondata);
// Old script.cpp SignatureHash function
uint256 static SignatureHashOld(CScript scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
@@ -167,12 +169,11 @@ BOOST_AUTO_TEST_CASE(sighash_test)
// Goal: check that SignatureHash generates correct hash
BOOST_AUTO_TEST_CASE(sighash_from_data)
{
- Array tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
+ UniValue tests = read_json(std::string(json_tests::sighash, json_tests::sighash + sizeof(json_tests::sighash)));
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- std::string strTest = write_string(tv, false);
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ std::string strTest = test.write();
if (test.size() < 1) // Allow for extra stuff (useful for comments)
{
BOOST_ERROR("Bad test: " << strTest);
diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp
index 86a4bc6727..a904e3862f 100644
--- a/src/test/skiplist_tests.cpp
+++ b/src/test/skiplist_tests.cpp
@@ -2,7 +2,7 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#include "main.h"
+#include "chain.h"
#include "random.h"
#include "util.h"
#include "test/test_bitcoin.h"
diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp
index c727303ea1..8d81275a6f 100644
--- a/src/test/test_bitcoin.cpp
+++ b/src/test/test_bitcoin.cpp
@@ -6,8 +6,13 @@
#include "test_bitcoin.h"
+#include "chainparams.h"
+#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "key.h"
#include "main.h"
+#include "miner.h"
+#include "pubkey.h"
#include "random.h"
#include "txdb.h"
#include "ui_interface.h"
@@ -27,20 +32,22 @@ CWallet* pwalletMain;
extern bool fPrintToConsole;
extern void noui_connect();
-BasicTestingSetup::BasicTestingSetup()
+BasicTestingSetup::BasicTestingSetup(CBaseChainParams::Network network)
{
ECC_Start();
SetupEnvironment();
fPrintToDebugLog = false; // don't want to write to debug.log file
fCheckBlockIndex = true;
- SelectParams(CBaseChainParams::MAIN);
+ SelectParams(network);
+ noui_connect();
}
+
BasicTestingSetup::~BasicTestingSetup()
{
ECC_Stop();
}
-TestingSetup::TestingSetup()
+TestingSetup::TestingSetup(CBaseChainParams::Network network) : BasicTestingSetup(network)
{
#ifdef ENABLE_WALLET
bitdb.MakeMock();
@@ -86,6 +93,51 @@ TestingSetup::~TestingSetup()
boost::filesystem::remove_all(pathTemp);
}
+TestChain100Setup::TestChain100Setup() : TestingSetup(CBaseChainParams::REGTEST)
+{
+ // Generate a 100-block chain:
+ coinbaseKey.MakeNewKey(true);
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+ for (int i = 0; i < COINBASE_MATURITY; i++)
+ {
+ std::vector<CMutableTransaction> noTxns;
+ CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey);
+ coinbaseTxns.push_back(b.vtx[0]);
+ }
+}
+
+//
+// Create a new block with just given transactions, coinbase paying to
+// scriptPubKey, and try to add it to the current chain.
+//
+CBlock
+TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey)
+{
+ CBlockTemplate *pblocktemplate = CreateNewBlock(scriptPubKey);
+ CBlock& block = pblocktemplate->block;
+
+ // Replace mempool-selected txns with just coinbase plus passed-in txns:
+ block.vtx.resize(1);
+ BOOST_FOREACH(const CMutableTransaction& tx, txns)
+ block.vtx.push_back(tx);
+ // IncrementExtraNonce creates a valid coinbase and merkleRoot
+ unsigned int extraNonce = 0;
+ IncrementExtraNonce(&block, chainActive.Tip(), extraNonce);
+
+ while (!CheckProofOfWork(block.GetHash(), block.nBits, Params(CBaseChainParams::REGTEST).GetConsensus())) ++block.nNonce;
+
+ CValidationState state;
+ ProcessNewBlock(state, NULL, &block, true, NULL);
+
+ CBlock result = block;
+ delete pblocktemplate;
+ return result;
+}
+
+TestChain100Setup::~TestChain100Setup()
+{
+}
+
void Shutdown(void* parg)
{
exit(0);
diff --git a/src/test/test_bitcoin.h b/src/test/test_bitcoin.h
index 2f75332d40..b9314d0611 100644
--- a/src/test/test_bitcoin.h
+++ b/src/test/test_bitcoin.h
@@ -1,6 +1,8 @@
#ifndef BITCOIN_TEST_TEST_BITCOIN_H
#define BITCOIN_TEST_TEST_BITCOIN_H
+#include "chainparamsbase.h"
+#include "key.h"
#include "txdb.h"
#include <boost/filesystem.hpp>
@@ -10,7 +12,7 @@
* This just configures logging and chain parameters.
*/
struct BasicTestingSetup {
- BasicTestingSetup();
+ BasicTestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
~BasicTestingSetup();
};
@@ -23,8 +25,30 @@ struct TestingSetup: public BasicTestingSetup {
boost::filesystem::path pathTemp;
boost::thread_group threadGroup;
- TestingSetup();
+ TestingSetup(CBaseChainParams::Network network = CBaseChainParams::MAIN);
~TestingSetup();
};
+class CBlock;
+struct CMutableTransaction;
+class CScript;
+
+//
+// Testing fixture that pre-creates a
+// 100-block REGTEST-mode block chain
+//
+struct TestChain100Setup : public TestingSetup {
+ TestChain100Setup();
+
+ // Create a new block with just given transactions, coinbase paying to
+ // scriptPubKey, and try to add it to the current chain.
+ CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns,
+ const CScript& scriptPubKey);
+
+ ~TestChain100Setup();
+
+ std::vector<CTransaction> coinbaseTxns; // For convenience, coinbase transactions
+ CKey coinbaseKey; // private/public key needed to spend coinbase transactions
+};
+
#endif
diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp
index 2a3083316e..e70ebddc2f 100644
--- a/src/test/transaction_tests.cpp
+++ b/src/test/transaction_tests.cpp
@@ -7,27 +7,31 @@
#include "test/test_bitcoin.h"
#include "clientversion.h"
+#include "consensus/validation.h"
+#include "core_io.h"
#include "key.h"
#include "keystore.h"
-#include "main.h"
+#include "main.h" // For CheckTransaction
+#include "policy/policy.h"
#include "script/script.h"
#include "script/script_error.h"
-#include "core_io.h"
+#include "utilstrencodings.h"
#include <map>
#include <string>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
+#include <boost/assign/list_of.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
// In script_tests.cpp
-extern Array read_json(const std::string& jsondata);
+extern UniValue read_json(const std::string& jsondata);
static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("NONE"), (unsigned int)SCRIPT_VERIFY_NONE)
@@ -39,7 +43,8 @@ static std::map<string, unsigned int> mapFlagNames = boost::assign::map_list_of
(string("MINIMALDATA"), (unsigned int)SCRIPT_VERIFY_MINIMALDATA)
(string("NULLDUMMY"), (unsigned int)SCRIPT_VERIFY_NULLDUMMY)
(string("DISCOURAGE_UPGRADABLE_NOPS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
- (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK);
+ (string("CLEANSTACK"), (unsigned int)SCRIPT_VERIFY_CLEANSTACK)
+ (string("CHECKLOCKTIMEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY);
unsigned int ParseScriptFlags(string strFlags)
{
@@ -87,32 +92,31 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
+ UniValue tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
@@ -163,32 +167,31 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// ... where all scripts are stringified scripts.
//
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
- Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
+ UniValue tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
ScriptError err;
- BOOST_FOREACH(Value& tv, tests)
- {
- Array test = tv.get_array();
- string strTest = write_string(tv, false);
- if (test[0].type() == array_type)
+ for (unsigned int idx = 0; idx < tests.size(); idx++) {
+ UniValue test = tests[idx];
+ string strTest = test.write();
+ if (test[0].isArray())
{
- if (test.size() != 3 || test[1].type() != str_type || test[2].type() != str_type)
+ if (test.size() != 3 || !test[1].isStr() || !test[2].isStr())
{
BOOST_ERROR("Bad test: " << strTest);
continue;
}
map<COutPoint, CScript> mapprevOutScriptPubKeys;
- Array inputs = test[0].get_array();
+ UniValue inputs = test[0].get_array();
bool fValid = true;
- BOOST_FOREACH(Value& input, inputs)
- {
- if (input.type() != array_type)
+ for (unsigned int inpIdx = 0; inpIdx < inputs.size(); inpIdx++) {
+ const UniValue& input = inputs[inpIdx];
+ if (!input.isArray())
{
fValid = false;
break;
}
- Array vinput = input.get_array();
+ UniValue vinput = input.get_array();
if (vinput.size() != 3)
{
fValid = false;
diff --git a/src/test/txvalidationcache_tests.cpp b/src/test/txvalidationcache_tests.cpp
new file mode 100644
index 0000000000..edad18644e
--- /dev/null
+++ b/src/test/txvalidationcache_tests.cpp
@@ -0,0 +1,86 @@
+// Copyright (c) 2011-2014 The Bitcoin Core developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "consensus/validation.h"
+#include "key.h"
+#include "main.h"
+#include "miner.h"
+#include "pubkey.h"
+#include "txmempool.h"
+#include "random.h"
+#include "script/standard.h"
+#include "test/test_bitcoin.h"
+#include "utiltime.h"
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(tx_validationcache_tests)
+
+static bool
+ToMemPool(CMutableTransaction& tx)
+{
+ LOCK(cs_main);
+
+ CValidationState state;
+ return AcceptToMemoryPool(mempool, state, tx, false, NULL, false);
+}
+
+BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup)
+{
+ // Make sure skipping validation of transctions that were
+ // validated going into the memory pool does not allow
+ // double-spends in blocks to pass validation when they should not.
+
+ CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
+
+ // Create a double-spend of mature coinbase txn:
+ std::vector<CMutableTransaction> spends;
+ spends.resize(2);
+ for (int i = 0; i < 2; i++)
+ {
+ spends[i].vin.resize(1);
+ spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash();
+ spends[i].vin[0].prevout.n = 0;
+ spends[i].vout.resize(1);
+ spends[i].vout[0].nValue = 11*CENT;
+ spends[i].vout[0].scriptPubKey = scriptPubKey;
+
+ // Sign:
+ std::vector<unsigned char> vchSig;
+ uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL);
+ BOOST_CHECK(coinbaseKey.Sign(hash, vchSig));
+ vchSig.push_back((unsigned char)SIGHASH_ALL);
+ spends[i].vin[0].scriptSig << vchSig;
+ }
+
+ CBlock block;
+
+ // Test 1: block with both of those transactions should be rejected.
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+
+ // Test 2: ... and should be rejected if spend1 is in the memory pool
+ BOOST_CHECK(ToMemPool(spends[0]));
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ mempool.clear();
+
+ // Test 3: ... and should be rejected if spend2 is in the memory pool
+ BOOST_CHECK(ToMemPool(spends[1]));
+ block = CreateAndProcessBlock(spends, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash());
+ mempool.clear();
+
+ // Final sanity test: first spend in mempool, second in block, that's OK:
+ std::vector<CMutableTransaction> oneSpend;
+ oneSpend.push_back(spends[0]);
+ BOOST_CHECK(ToMemPool(spends[1]));
+ block = CreateAndProcessBlock(oneSpend, scriptPubKey);
+ BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash());
+ // spends[1] should have been removed from the mempool when the
+ // block with spends[0] is accepted:
+ BOOST_CHECK_EQUAL(mempool.size(), 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp
index 8cecfbf651..ee31c0955b 100644
--- a/src/test/univalue_tests.cpp
+++ b/src/test/univalue_tests.cpp
@@ -63,6 +63,48 @@ BOOST_AUTO_TEST_CASE(univalue_constructor)
BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}
+BOOST_AUTO_TEST_CASE(univalue_typecheck)
+{
+ UniValue v1;
+ BOOST_CHECK(v1.setNumStr("1"));
+ BOOST_CHECK(v1.isNum());
+ BOOST_CHECK_THROW(v1.get_bool(), runtime_error);
+
+ UniValue v2;
+ BOOST_CHECK(v2.setBool(true));
+ BOOST_CHECK_EQUAL(v2.get_bool(), true);
+ BOOST_CHECK_THROW(v2.get_int(), runtime_error);
+
+ UniValue v3;
+ BOOST_CHECK(v3.setNumStr("32482348723847471234"));
+ BOOST_CHECK_THROW(v3.get_int64(), runtime_error);
+ BOOST_CHECK(v3.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v3.get_int64(), 1000);
+
+ UniValue v4;
+ BOOST_CHECK(v4.setNumStr("2147483648"));
+ BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
+ BOOST_CHECK_THROW(v4.get_int(), runtime_error);
+ BOOST_CHECK(v4.setNumStr("1000"));
+ BOOST_CHECK_EQUAL(v4.get_int(), 1000);
+ BOOST_CHECK_THROW(v4.get_str(), runtime_error);
+ BOOST_CHECK_EQUAL(v4.get_real(), 1000);
+ BOOST_CHECK_THROW(v4.get_array(), runtime_error);
+ BOOST_CHECK_THROW(v4.getKeys(), runtime_error);
+ BOOST_CHECK_THROW(v4.getValues(), runtime_error);
+ BOOST_CHECK_THROW(v4.get_obj(), runtime_error);
+
+ UniValue v5;
+ BOOST_CHECK(v5.read("[true, 10]"));
+ BOOST_CHECK_NO_THROW(v5.get_array());
+ std::vector<UniValue> vals = v5.getValues();
+ BOOST_CHECK_THROW(vals[0].get_int(), runtime_error);
+ BOOST_CHECK_EQUAL(vals[0].get_bool(), true);
+
+ BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
+ BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error);
+}
+
BOOST_AUTO_TEST_CASE(univalue_set)
{
UniValue v(UniValue::VSTR, "foo");
@@ -72,13 +114,13 @@ BOOST_AUTO_TEST_CASE(univalue_set)
BOOST_CHECK(v.setObject());
BOOST_CHECK(v.isObject());
- BOOST_CHECK_EQUAL(v.count(), 0);
+ BOOST_CHECK_EQUAL(v.size(), 0);
BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
BOOST_CHECK(v.empty());
BOOST_CHECK(v.setArray());
BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.count(), 0);
+ BOOST_CHECK_EQUAL(v.size(), 0);
BOOST_CHECK(v.setStr("zum"));
BOOST_CHECK(v.isStr());
@@ -145,7 +187,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
BOOST_CHECK(arr.push_backV(vec));
BOOST_CHECK_EQUAL(arr.empty(), false);
- BOOST_CHECK_EQUAL(arr.count(), 5);
+ BOOST_CHECK_EQUAL(arr.size(), 5);
BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
@@ -157,7 +199,7 @@ BOOST_AUTO_TEST_CASE(univalue_array)
arr.clear();
BOOST_CHECK(arr.empty());
- BOOST_CHECK_EQUAL(arr.count(), 0);
+ BOOST_CHECK_EQUAL(arr.size(), 0);
}
BOOST_AUTO_TEST_CASE(univalue_object)
@@ -197,7 +239,7 @@ BOOST_AUTO_TEST_CASE(univalue_object)
BOOST_CHECK(obj.pushKVs(obj2));
BOOST_CHECK_EQUAL(obj.empty(), false);
- BOOST_CHECK_EQUAL(obj.count(), 9);
+ BOOST_CHECK_EQUAL(obj.size(), 9);
BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
@@ -240,11 +282,11 @@ BOOST_AUTO_TEST_CASE(univalue_object)
obj.clear();
BOOST_CHECK(obj.empty());
- BOOST_CHECK_EQUAL(obj.count(), 0);
+ BOOST_CHECK_EQUAL(obj.size(), 0);
}
static const char *json1 =
-"[1.1,{\"key1\":\"str\",\"key2\":800,\"key3\":{\"name\":\"martian\"}}]";
+"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";
BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
@@ -255,21 +297,38 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite)
BOOST_CHECK(v.read(strJson1));
BOOST_CHECK(v.isArray());
- BOOST_CHECK_EQUAL(v.count(), 2);
+ BOOST_CHECK_EQUAL(v.size(), 2);
- BOOST_CHECK_EQUAL(v[0].getValStr(), "1.1");
+ BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");
UniValue obj = v[1];
BOOST_CHECK(obj.isObject());
- BOOST_CHECK_EQUAL(obj.count(), 3);
+ BOOST_CHECK_EQUAL(obj.size(), 3);
BOOST_CHECK(obj["key1"].isStr());
- BOOST_CHECK_EQUAL(obj["key1"].getValStr(), "str");
+ std::string correctValue("str");
+ correctValue.push_back('\0');
+ BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
BOOST_CHECK(obj["key2"].isNum());
BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
BOOST_CHECK(obj["key3"].isObject());
BOOST_CHECK_EQUAL(strJson1, v.write());
+
+ /* Check for (correctly reporting) a parsing error if the initial
+ JSON construct is followed by more stuff. Note that whitespace
+ is, of course, exempt. */
+
+ BOOST_CHECK(v.read(" {}\n "));
+ BOOST_CHECK(v.isObject());
+ BOOST_CHECK(v.read(" []\n "));
+ BOOST_CHECK(v.isArray());
+
+ BOOST_CHECK(!v.read("@{}"));
+ BOOST_CHECK(!v.read("{} garbage"));
+ BOOST_CHECK(!v.read("[]{}"));
+ BOOST_CHECK(!v.read("{}[]"));
+ BOOST_CHECK(!v.read("{} 42"));
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp
index 3309e2e387..bde16a517f 100644
--- a/src/test/util_tests.cpp
+++ b/src/test/util_tests.cpp
@@ -146,29 +146,27 @@ BOOST_AUTO_TEST_CASE(util_GetArg)
BOOST_AUTO_TEST_CASE(util_FormatMoney)
{
- BOOST_CHECK_EQUAL(FormatMoney(0, false), "0.00");
- BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789, false), "12345.6789");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, true), "+1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, false), "-1.00");
- BOOST_CHECK_EQUAL(FormatMoney(-COIN, true), "-1.00");
-
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000, false), "100000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000, false), "10000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000, false), "1000000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100000, false), "100000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10000, false), "10000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*1000, false), "1000.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*100, false), "100.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN*10, false), "10.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN, false), "1.00");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10, false), "0.10");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100, false), "0.01");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000, false), "0.001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000, false), "0.0001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000, false), "0.00001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000, false), "0.000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000, false), "0.0000001");
- BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000, false), "0.00000001");
+ BOOST_CHECK_EQUAL(FormatMoney(0), "0.00");
+ BOOST_CHECK_EQUAL(FormatMoney((COIN/10000)*123456789), "12345.6789");
+ BOOST_CHECK_EQUAL(FormatMoney(-COIN), "-1.00");
+
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000000), "100000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000000), "10000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000000), "1000000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100000), "100000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10000), "10000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*1000), "1000.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*100), "100.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN*10), "10.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN), "1.00");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10), "0.10");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100), "0.01");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000), "0.001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000), "0.0001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000), "0.00001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/1000000), "0.000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/10000000), "0.0000001");
+ BOOST_CHECK_EQUAL(FormatMoney(COIN/100000000), "0.00000001");
}
BOOST_AUTO_TEST_CASE(util_ParseMoney)
@@ -322,9 +320,16 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(ParseInt32("-2147483648", &n) && n == -2147483648);
BOOST_CHECK(ParseInt32("-1234", &n) && n == -1234);
// Invalid values
+ BOOST_CHECK(!ParseInt32("", &n));
+ BOOST_CHECK(!ParseInt32(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt32("1 ", &n));
BOOST_CHECK(!ParseInt32("1a", &n));
BOOST_CHECK(!ParseInt32("aap", &n));
BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ BOOST_CHECK(!ParseInt32("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt32(teststr, &n)); // no embedded NULs
// Overflow and underflow
BOOST_CHECK(!ParseInt32("-2147483649", NULL));
BOOST_CHECK(!ParseInt32("2147483648", NULL));
@@ -332,6 +337,64 @@ BOOST_AUTO_TEST_CASE(test_ParseInt32)
BOOST_CHECK(!ParseInt32("32482348723847471234", NULL));
}
+BOOST_AUTO_TEST_CASE(test_ParseInt64)
+{
+ int64_t n;
+ // Valid values
+ BOOST_CHECK(ParseInt64("1234", NULL));
+ BOOST_CHECK(ParseInt64("0", &n) && n == 0LL);
+ BOOST_CHECK(ParseInt64("1234", &n) && n == 1234LL);
+ BOOST_CHECK(ParseInt64("01234", &n) && n == 1234LL); // no octal
+ BOOST_CHECK(ParseInt64("2147483647", &n) && n == 2147483647LL);
+ BOOST_CHECK(ParseInt64("-2147483648", &n) && n == -2147483648LL);
+ BOOST_CHECK(ParseInt64("9223372036854775807", &n) && n == (int64_t)9223372036854775807);
+ BOOST_CHECK(ParseInt64("-9223372036854775808", &n) && n == (int64_t)-9223372036854775807-1);
+ BOOST_CHECK(ParseInt64("-1234", &n) && n == -1234LL);
+ // Invalid values
+ BOOST_CHECK(!ParseInt64("", &n));
+ BOOST_CHECK(!ParseInt64(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseInt64("1 ", &n));
+ BOOST_CHECK(!ParseInt64("1a", &n));
+ BOOST_CHECK(!ParseInt64("aap", &n));
+ BOOST_CHECK(!ParseInt64("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseInt64(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseInt64("-9223372036854775809", NULL));
+ BOOST_CHECK(!ParseInt64("9223372036854775808", NULL));
+ BOOST_CHECK(!ParseInt64("-32482348723847471234", NULL));
+ BOOST_CHECK(!ParseInt64("32482348723847471234", NULL));
+}
+
+BOOST_AUTO_TEST_CASE(test_ParseDouble)
+{
+ double n;
+ // Valid values
+ BOOST_CHECK(ParseDouble("1234", NULL));
+ BOOST_CHECK(ParseDouble("0", &n) && n == 0.0);
+ BOOST_CHECK(ParseDouble("1234", &n) && n == 1234.0);
+ BOOST_CHECK(ParseDouble("01234", &n) && n == 1234.0); // no octal
+ BOOST_CHECK(ParseDouble("2147483647", &n) && n == 2147483647.0);
+ BOOST_CHECK(ParseDouble("-2147483648", &n) && n == -2147483648.0);
+ BOOST_CHECK(ParseDouble("-1234", &n) && n == -1234.0);
+ BOOST_CHECK(ParseDouble("1e6", &n) && n == 1e6);
+ BOOST_CHECK(ParseDouble("-1e6", &n) && n == -1e6);
+ // Invalid values
+ BOOST_CHECK(!ParseDouble("", &n));
+ BOOST_CHECK(!ParseDouble(" 1", &n)); // no padding inside
+ BOOST_CHECK(!ParseDouble("1 ", &n));
+ BOOST_CHECK(!ParseDouble("1a", &n));
+ BOOST_CHECK(!ParseDouble("aap", &n));
+ BOOST_CHECK(!ParseDouble("0x1", &n)); // no hex
+ const char test_bytes[] = {'1', 0, '1'};
+ std::string teststr(test_bytes, sizeof(test_bytes));
+ BOOST_CHECK(!ParseDouble(teststr, &n)); // no embedded NULs
+ // Overflow and underflow
+ BOOST_CHECK(!ParseDouble("-1e10000", NULL));
+ BOOST_CHECK(!ParseDouble("1e10000", NULL));
+}
+
BOOST_AUTO_TEST_CASE(test_FormatParagraph)
{
BOOST_CHECK_EQUAL(FormatParagraph("", 79, 0), "");
@@ -350,9 +413,75 @@ BOOST_AUTO_TEST_CASE(test_FormatSubVersion)
comments.push_back(std::string("comment1"));
std::vector<std::string> comments2;
comments2.push_back(std::string("comment1"));
- comments2.push_back(std::string("comment2"));
+ comments2.push_back(SanitizeString(std::string("Comment2; .,_?@; !\"#$%&'()*+-/<=>[]\\^`{|}~"), SAFE_CHARS_UA_COMMENT)); // Semicolon is discouraged but not forbidden by BIP-0014
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, std::vector<std::string>()),std::string("/Test:0.9.99/"));
BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments),std::string("/Test:0.9.99(comment1)/"));
- BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; comment2)/"));
+ BOOST_CHECK_EQUAL(FormatSubVersion("Test", 99900, comments2),std::string("/Test:0.9.99(comment1; Comment2; .,_?@; )/"));
}
+
+BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
+{
+ int64_t amount = 0;
+ BOOST_CHECK(ParseFixedPoint("0", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 0LL);
+ BOOST_CHECK(ParseFixedPoint("1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000LL);
+ BOOST_CHECK(ParseFixedPoint("0.0", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 0LL);
+ BOOST_CHECK(ParseFixedPoint("-0.1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -10000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 110000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.10000000000000000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 110000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1e1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1100000000LL);
+ BOOST_CHECK(ParseFixedPoint("1.1e-1", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 11000000LL);
+ BOOST_CHECK(ParseFixedPoint("1000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000000LL);
+ BOOST_CHECK(ParseFixedPoint("-1000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -100000000000LL);
+ BOOST_CHECK(ParseFixedPoint("0.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1LL);
+ BOOST_CHECK(ParseFixedPoint("0.0000000100000000", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 1LL);
+ BOOST_CHECK(ParseFixedPoint("-0.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -1LL);
+ BOOST_CHECK(ParseFixedPoint("1000000000.00000001", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 100000000000000001LL);
+ BOOST_CHECK(ParseFixedPoint("9999999999.99999999", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, 999999999999999999LL);
+ BOOST_CHECK(ParseFixedPoint("-9999999999.99999999", 8, &amount));
+ BOOST_CHECK_EQUAL(amount, -999999999999999999LL);
+
+ BOOST_CHECK(!ParseFixedPoint("", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("a-1000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-a1000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-1000a", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-01000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("00.1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint(".1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("--0.1", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("0.000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-0.000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("0.00000001000000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000000", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000001", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-10000000000.00000009", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("10000000000.00000009", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-99999999999.99999999", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("99999909999.09999999", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("92233720368.54775807", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("92233720368.54775808", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-92233720368.54775808", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("-92233720368.54775809", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.1e", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.1e-", 8, &amount));
+ BOOST_CHECK(!ParseFixedPoint("1.", 8, &amount));
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/timedata.cpp b/src/timedata.cpp
index c3e9c75f6e..a14d69c116 100644
--- a/src/timedata.cpp
+++ b/src/timedata.cpp
@@ -40,16 +40,20 @@ static int64_t abs64(int64_t n)
return (n >= 0 ? n : -n);
}
+#define BITCOIN_TIMEDATA_MAX_SAMPLES 200
+
void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample)
{
LOCK(cs_nTimeOffset);
// Ignore duplicates
static set<CNetAddr> setKnown;
+ if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES)
+ return;
if (!setKnown.insert(ip).second)
return;
// Add data
- static CMedianFilter<int64_t> vTimeOffsets(200,0);
+ static CMedianFilter<int64_t> vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0);
vTimeOffsets.input(nOffsetSample);
LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60);
diff --git a/src/txdb.cpp b/src/txdb.cpp
index df9ff8d8c9..21ecd65238 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -5,6 +5,7 @@
#include "txdb.h"
+#include "chain.h"
#include "chainparams.h"
#include "hash.h"
#include "main.h"
@@ -147,7 +148,10 @@ bool CCoinsViewDB::GetStats(CCoinsStats &stats) const {
return error("%s: Deserialize or I/O error - %s", __func__, e.what());
}
}
- stats.nHeight = mapBlockIndex.find(GetBestBlock())->second->nHeight;
+ {
+ LOCK(cs_main);
+ stats.nHeight = mapBlockIndex.find(stats.hashBlock)->second->nHeight;
+ }
stats.hashSerialized = ss.GetHash();
stats.nTotalAmount = nTotalAmount;
return true;
diff --git a/src/txdb.h b/src/txdb.h
index 86e1c5d831..bef5dc9fd1 100644
--- a/src/txdb.h
+++ b/src/txdb.h
@@ -22,7 +22,7 @@ class uint256;
//! -dbcache default (MiB)
static const int64_t nDefaultDbCache = 100;
//! max. -dbcache in (MiB)
-static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 4096 : 1024;
+static const int64_t nMaxDbCache = sizeof(void*) > 4 ? 16384 : 1024;
//! min. -dbcache in (MiB)
static const int64_t nMinDbCache = 4;
diff --git a/src/txmempool.cpp b/src/txmempool.cpp
index d05e3c6eec..2f603e3c9f 100644
--- a/src/txmempool.cpp
+++ b/src/txmempool.cpp
@@ -7,30 +7,29 @@
#include "clientversion.h"
#include "consensus/consensus.h"
+#include "consensus/validation.h"
#include "main.h"
+#include "policy/fees.h"
#include "streams.h"
#include "util.h"
#include "utilmoneystr.h"
#include "version.h"
-#include <boost/circular_buffer.hpp>
-
using namespace std;
-CTxMemPoolEntry::CTxMemPoolEntry():
- nFee(0), nTxSize(0), nModSize(0), nTime(0), dPriority(0.0)
-{
- nHeight = MEMPOOL_HEIGHT;
-}
-
CTxMemPoolEntry::CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
int64_t _nTime, double _dPriority,
- unsigned int _nHeight):
- tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight)
+ unsigned int _nHeight, bool poolHasNoInputsOf):
+ tx(_tx), nFee(_nFee), nTime(_nTime), dPriority(_dPriority), nHeight(_nHeight),
+ hadNoDependencies(poolHasNoInputsOf)
{
nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
-
nModSize = tx.CalculateModifiedSize(nTxSize);
+ nUsageSize = RecursiveDynamicUsage(tx);
+
+ nCountWithDescendants = 1;
+ nSizeWithDescendants = nTxSize;
+ nFeesWithDescendants = nFee;
}
CTxMemPoolEntry::CTxMemPoolEntry(const CTxMemPoolEntry& other)
@@ -47,346 +46,253 @@ CTxMemPoolEntry::GetPriority(unsigned int currentHeight) const
return dResult;
}
-/**
- * Keep track of fee/priority for transactions confirmed within N blocks
- */
-class CBlockAverage
+// Update the given tx for any in-mempool descendants.
+// Assumes that setMemPoolChildren is correct for the given tx and all
+// descendants.
+bool CTxMemPool::UpdateForDescendants(txiter updateIt, int maxDescendantsToVisit, cacheMap &cachedDescendants, const std::set<uint256> &setExclude)
{
-private:
- boost::circular_buffer<CFeeRate> feeSamples;
- boost::circular_buffer<double> prioritySamples;
+ // Track the number of entries (outside setExclude) that we'd need to visit
+ // (will bail out if it exceeds maxDescendantsToVisit)
+ int nChildrenToVisit = 0;
- template<typename T> std::vector<T> buf2vec(boost::circular_buffer<T> buf) const
- {
- std::vector<T> vec(buf.begin(), buf.end());
- return vec;
- }
+ setEntries stageEntries, setAllDescendants;
+ stageEntries = GetMemPoolChildren(updateIt);
-public:
- CBlockAverage() : feeSamples(100), prioritySamples(100) { }
-
- void RecordFee(const CFeeRate& feeRate) {
- feeSamples.push_back(feeRate);
- }
-
- void RecordPriority(double priority) {
- prioritySamples.push_back(priority);
- }
-
- size_t FeeSamples() const { return feeSamples.size(); }
- size_t GetFeeSamples(std::vector<CFeeRate>& insertInto) const
- {
- BOOST_FOREACH(const CFeeRate& f, feeSamples)
- insertInto.push_back(f);
- return feeSamples.size();
- }
- size_t PrioritySamples() const { return prioritySamples.size(); }
- size_t GetPrioritySamples(std::vector<double>& insertInto) const
- {
- BOOST_FOREACH(double d, prioritySamples)
- insertInto.push_back(d);
- return prioritySamples.size();
- }
-
- /**
- * Used as belt-and-suspenders check when reading to detect
- * file corruption
- */
- static bool AreSane(const CFeeRate fee, const CFeeRate& minRelayFee)
- {
- if (fee < CFeeRate(0))
- return false;
- if (fee.GetFeePerK() > minRelayFee.GetFeePerK() * 10000)
+ while (!stageEntries.empty()) {
+ const txiter cit = *stageEntries.begin();
+ if (cit->IsDirty()) {
+ // Don't consider any more children if any descendant is dirty
return false;
- return true;
- }
- static bool AreSane(const std::vector<CFeeRate>& vecFee, const CFeeRate& minRelayFee)
- {
- BOOST_FOREACH(CFeeRate fee, vecFee)
- {
- if (!AreSane(fee, minRelayFee))
- return false;
}
- return true;
- }
- static bool AreSane(const double priority)
- {
- return priority >= 0;
- }
- static bool AreSane(const std::vector<double> vecPriority)
- {
- BOOST_FOREACH(double priority, vecPriority)
- {
- if (!AreSane(priority))
+ setAllDescendants.insert(cit);
+ stageEntries.erase(cit);
+ const setEntries &setChildren = GetMemPoolChildren(cit);
+ BOOST_FOREACH(const txiter childEntry, setChildren) {
+ cacheMap::iterator cacheIt = cachedDescendants.find(childEntry);
+ if (cacheIt != cachedDescendants.end()) {
+ // We've already calculated this one, just add the entries for this set
+ // but don't traverse again.
+ BOOST_FOREACH(const txiter cacheEntry, cacheIt->second) {
+ // update visit count only for new child transactions
+ // (outside of setExclude and stageEntries)
+ if (setAllDescendants.insert(cacheEntry).second &&
+ !setExclude.count(cacheEntry->GetTx().GetHash()) &&
+ !stageEntries.count(cacheEntry)) {
+ nChildrenToVisit++;
+ }
+ }
+ } else if (!setAllDescendants.count(childEntry)) {
+ // Schedule for later processing and update our visit count
+ if (stageEntries.insert(childEntry).second && !setExclude.count(childEntry->GetTx().GetHash())) {
+ nChildrenToVisit++;
+ }
+ }
+ if (nChildrenToVisit > maxDescendantsToVisit) {
return false;
+ }
}
- return true;
}
-
- void Write(CAutoFile& fileout) const
- {
- std::vector<CFeeRate> vecFee = buf2vec(feeSamples);
- fileout << vecFee;
- std::vector<double> vecPriority = buf2vec(prioritySamples);
- fileout << vecPriority;
- }
-
- void Read(CAutoFile& filein, const CFeeRate& minRelayFee) {
- std::vector<CFeeRate> vecFee;
- filein >> vecFee;
- if (AreSane(vecFee, minRelayFee))
- feeSamples.insert(feeSamples.end(), vecFee.begin(), vecFee.end());
- else
- throw runtime_error("Corrupt fee value in estimates file.");
- std::vector<double> vecPriority;
- filein >> vecPriority;
- if (AreSane(vecPriority))
- prioritySamples.insert(prioritySamples.end(), vecPriority.begin(), vecPriority.end());
- else
- throw runtime_error("Corrupt priority value in estimates file.");
- if (feeSamples.size() + prioritySamples.size() > 0)
- LogPrint("estimatefee", "Read %d fee samples and %d priority samples\n",
- feeSamples.size(), prioritySamples.size());
- }
-};
-
-class CMinerPolicyEstimator
-{
-private:
- /**
- * Records observed averages transactions that confirmed within one block, two blocks,
- * three blocks etc.
- */
- std::vector<CBlockAverage> history;
- std::vector<CFeeRate> sortedFeeSamples;
- std::vector<double> sortedPrioritySamples;
-
- int nBestSeenHeight;
-
- /**
- * nBlocksAgo is 0 based, i.e. transactions that confirmed in the highest seen block are
- * nBlocksAgo == 0, transactions in the block before that are nBlocksAgo == 1 etc.
- */
- void seenTxConfirm(const CFeeRate& feeRate, const CFeeRate& minRelayFee, double dPriority, int nBlocksAgo)
- {
- // Last entry records "everything else".
- int nBlocksTruncated = min(nBlocksAgo, (int) history.size() - 1);
- assert(nBlocksTruncated >= 0);
-
- // We need to guess why the transaction was included in a block-- either
- // because it is high-priority or because it has sufficient fees.
- bool sufficientFee = (feeRate > minRelayFee);
- bool sufficientPriority = AllowFree(dPriority);
- const char* assignedTo = "unassigned";
- if (sufficientFee && !sufficientPriority && CBlockAverage::AreSane(feeRate, minRelayFee))
- {
- history[nBlocksTruncated].RecordFee(feeRate);
- assignedTo = "fee";
- }
- else if (sufficientPriority && !sufficientFee && CBlockAverage::AreSane(dPriority))
- {
- history[nBlocksTruncated].RecordPriority(dPriority);
- assignedTo = "priority";
+ // setAllDescendants now contains all in-mempool descendants of updateIt.
+ // Update and add to cached descendant map
+ int64_t modifySize = 0;
+ CAmount modifyFee = 0;
+ int64_t modifyCount = 0;
+ BOOST_FOREACH(txiter cit, setAllDescendants) {
+ if (!setExclude.count(cit->GetTx().GetHash())) {
+ modifySize += cit->GetTxSize();
+ modifyFee += cit->GetFee();
+ modifyCount++;
+ cachedDescendants[updateIt].insert(cit);
}
- else
- {
- // Neither or both fee and priority sufficient to get confirmed:
- // don't know why they got confirmed.
- }
- LogPrint("estimatefee", "Seen TX confirm: %s: %s fee/%g priority, took %d blocks\n",
- assignedTo, feeRate.ToString(), dPriority, nBlocksAgo);
- }
-
-public:
- CMinerPolicyEstimator(int nEntries) : nBestSeenHeight(0)
- {
- history.resize(nEntries);
}
+ mapTx.modify(updateIt, update_descendant_state(modifySize, modifyFee, modifyCount));
+ return true;
+}
- void seenBlock(const std::vector<CTxMemPoolEntry>& entries, int nBlockHeight, const CFeeRate minRelayFee)
- {
- if (nBlockHeight <= nBestSeenHeight)
- {
- // Ignore side chains and re-orgs; assuming they are random
- // they don't affect the estimate.
- // And if an attacker can re-org the chain at will, then
- // you've got much bigger problems than "attacker can influence
- // transaction fees."
- return;
+// vHashesToUpdate is the set of transaction hashes from a disconnected block
+// which has been re-added to the mempool.
+// for each entry, look for descendants that are outside hashesToUpdate, and
+// add fee/size information for such descendants to the parent.
+void CTxMemPool::UpdateTransactionsFromBlock(const std::vector<uint256> &vHashesToUpdate)
+{
+ LOCK(cs);
+ // For each entry in vHashesToUpdate, store the set of in-mempool, but not
+ // in-vHashesToUpdate transactions, so that we don't have to recalculate
+ // descendants when we come across a previously seen entry.
+ cacheMap mapMemPoolDescendantsToUpdate;
+
+ // Use a set for lookups into vHashesToUpdate (these entries are already
+ // accounted for in the state of their ancestors)
+ std::set<uint256> setAlreadyIncluded(vHashesToUpdate.begin(), vHashesToUpdate.end());
+
+ // Iterate in reverse, so that whenever we are looking at at a transaction
+ // we are sure that all in-mempool descendants have already been processed.
+ // This maximizes the benefit of the descendant cache and guarantees that
+ // setMemPoolChildren will be updated, an assumption made in
+ // UpdateForDescendants.
+ BOOST_REVERSE_FOREACH(const uint256 &hash, vHashesToUpdate) {
+ // we cache the in-mempool children to avoid duplicate updates
+ setEntries setChildren;
+ // calculate children from mapNextTx
+ txiter it = mapTx.find(hash);
+ if (it == mapTx.end()) {
+ continue;
}
- nBestSeenHeight = nBlockHeight;
-
- // Fill up the history buckets based on how long transactions took
- // to confirm.
- std::vector<std::vector<const CTxMemPoolEntry*> > entriesByConfirmations;
- entriesByConfirmations.resize(history.size());
- BOOST_FOREACH(const CTxMemPoolEntry& entry, entries)
- {
- // How many blocks did it take for miners to include this transaction?
- int delta = nBlockHeight - entry.GetHeight();
- if (delta <= 0)
- {
- // Re-org made us lose height, this should only happen if we happen
- // to re-org on a difficulty transition point: very rare!
- continue;
+ std::map<COutPoint, CInPoint>::iterator iter = mapNextTx.lower_bound(COutPoint(hash, 0));
+ // First calculate the children, and update setMemPoolChildren to
+ // include them, and update their setMemPoolParents to include this tx.
+ for (; iter != mapNextTx.end() && iter->first.hash == hash; ++iter) {
+ const uint256 &childHash = iter->second.ptx->GetHash();
+ txiter childIter = mapTx.find(childHash);
+ assert(childIter != mapTx.end());
+ // We can skip updating entries we've encountered before or that
+ // are in the block (which are already accounted for).
+ if (setChildren.insert(childIter).second && !setAlreadyIncluded.count(childHash)) {
+ UpdateChild(it, childIter, true);
+ UpdateParent(childIter, it, true);
}
- if ((delta-1) >= (int)history.size())
- delta = history.size(); // Last bucket is catch-all
- entriesByConfirmations.at(delta-1).push_back(&entry);
}
- for (size_t i = 0; i < entriesByConfirmations.size(); i++)
- {
- std::vector<const CTxMemPoolEntry*> &e = entriesByConfirmations.at(i);
- // Insert at most 10 random entries per bucket, otherwise a single block
- // can dominate an estimate:
- if (e.size() > 10) {
- std::random_shuffle(e.begin(), e.end());
- e.resize(10);
- }
- BOOST_FOREACH(const CTxMemPoolEntry* entry, e)
- {
- // Fees are stored and reported as BTC-per-kb:
- CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
- double dPriority = entry->GetPriority(entry->GetHeight()); // Want priority when it went IN
- seenTxConfirm(feeRate, minRelayFee, dPriority, i);
- }
+ if (!UpdateForDescendants(it, 100, mapMemPoolDescendantsToUpdate, setAlreadyIncluded)) {
+ // Mark as dirty if we can't do the calculation.
+ mapTx.modify(it, set_dirty());
}
+ }
+}
- // After new samples are added, we have to clear the sorted lists,
- // so they'll be resorted the next time someone asks for an estimate
- sortedFeeSamples.clear();
- sortedPrioritySamples.clear();
-
- for (size_t i = 0; i < history.size(); i++) {
- if (history[i].FeeSamples() + history[i].PrioritySamples() > 0)
- LogPrint("estimatefee", "estimates: for confirming within %d blocks based on %d/%d samples, fee=%s, prio=%g\n",
- i,
- history[i].FeeSamples(), history[i].PrioritySamples(),
- estimateFee(i+1).ToString(), estimatePriority(i+1));
+bool CTxMemPool::CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString)
+{
+ setEntries parentHashes;
+ const CTransaction &tx = entry.GetTx();
+
+ // Get parents of this transaction that are in the mempool
+ // Entry may or may not already be in the mempool, and GetMemPoolParents()
+ // is only valid for entries in the mempool, so we iterate mapTx to find
+ // parents.
+ // TODO: optimize this so that we only check limits and walk
+ // tx.vin when called on entries not already in the mempool.
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ txiter piter = mapTx.find(tx.vin[i].prevout.hash);
+ if (piter != mapTx.end()) {
+ parentHashes.insert(piter);
+ if (parentHashes.size() + 1 > limitAncestorCount) {
+ errString = strprintf("too many unconfirmed parents [limit: %u]", limitAncestorCount);
+ return false;
+ }
}
}
- /**
- * Can return CFeeRate(0) if we don't have any data for that many blocks back. nBlocksToConfirm is 1 based.
- */
- CFeeRate estimateFee(int nBlocksToConfirm)
- {
- nBlocksToConfirm--;
+ size_t totalSizeWithAncestors = entry.GetTxSize();
- if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size())
- return CFeeRate(0);
+ while (!parentHashes.empty()) {
+ txiter stageit = *parentHashes.begin();
- if (sortedFeeSamples.size() == 0)
- {
- for (size_t i = 0; i < history.size(); i++)
- history.at(i).GetFeeSamples(sortedFeeSamples);
- std::sort(sortedFeeSamples.begin(), sortedFeeSamples.end(),
- std::greater<CFeeRate>());
- }
- if (sortedFeeSamples.size() < 11)
- {
- // Eleven is Gavin's Favorite Number
- // ... but we also take a maximum of 10 samples per block so eleven means
- // we're getting samples from at least two different blocks
- return CFeeRate(0);
- }
+ setAncestors.insert(stageit);
+ parentHashes.erase(stageit);
+ totalSizeWithAncestors += stageit->GetTxSize();
- int nBucketSize = history.at(nBlocksToConfirm).FeeSamples();
+ if (stageit->GetSizeWithDescendants() + entry.GetTxSize() > limitDescendantSize) {
+ errString = strprintf("exceeds descendant size limit for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantSize);
+ return false;
+ } else if (stageit->GetCountWithDescendants() + 1 > limitDescendantCount) {
+ errString = strprintf("too many descendants for tx %s [limit: %u]", stageit->GetTx().GetHash().ToString(), limitDescendantCount);
+ return false;
+ } else if (totalSizeWithAncestors > limitAncestorSize) {
+ errString = strprintf("exceeds ancestor size limit [limit: %u]", limitAncestorSize);
+ return false;
+ }
- // Estimates should not increase as number of confirmations goes up,
- // but the estimates are noisy because confirmations happen discretely
- // in blocks. To smooth out the estimates, use all samples in the history
- // and use the nth highest where n is (number of samples in previous bucket +
- // half the samples in nBlocksToConfirm bucket):
- size_t nPrevSize = 0;
- for (int i = 0; i < nBlocksToConfirm; i++)
- nPrevSize += history.at(i).FeeSamples();
- size_t index = min(nPrevSize + nBucketSize/2, sortedFeeSamples.size()-1);
- return sortedFeeSamples[index];
+ const setEntries & setMemPoolParents = GetMemPoolParents(stageit);
+ BOOST_FOREACH(const txiter &phash, setMemPoolParents) {
+ // If this is a new ancestor, add it.
+ if (setAncestors.count(phash) == 0) {
+ parentHashes.insert(phash);
+ }
+ if (parentHashes.size() + setAncestors.size() + 1 > limitAncestorCount) {
+ errString = strprintf("too many unconfirmed ancestors [limit: %u]", limitAncestorCount);
+ return false;
+ }
+ }
}
- double estimatePriority(int nBlocksToConfirm)
- {
- nBlocksToConfirm--;
- if (nBlocksToConfirm < 0 || nBlocksToConfirm >= (int)history.size())
- return -1;
-
- if (sortedPrioritySamples.size() == 0)
- {
- for (size_t i = 0; i < history.size(); i++)
- history.at(i).GetPrioritySamples(sortedPrioritySamples);
- std::sort(sortedPrioritySamples.begin(), sortedPrioritySamples.end(),
- std::greater<double>());
- }
- if (sortedPrioritySamples.size() < 11)
- return -1.0;
+ return true;
+}
- int nBucketSize = history.at(nBlocksToConfirm).PrioritySamples();
+void CTxMemPool::UpdateAncestorsOf(bool add, txiter it, setEntries &setAncestors)
+{
+ setEntries parentIters = GetMemPoolParents(it);
+ // add or remove this tx as a child of each parent
+ BOOST_FOREACH(txiter piter, parentIters) {
+ UpdateChild(piter, it, add);
+ }
+ const int64_t updateCount = (add ? 1 : -1);
+ const int64_t updateSize = updateCount * it->GetTxSize();
+ const CAmount updateFee = updateCount * it->GetFee();
+ BOOST_FOREACH(txiter ancestorIt, setAncestors) {
+ mapTx.modify(ancestorIt, update_descendant_state(updateSize, updateFee, updateCount));
+ }
+}
- // Estimates should not increase as number of confirmations needed goes up,
- // but the estimates are noisy because confirmations happen discretely
- // in blocks. To smooth out the estimates, use all samples in the history
- // and use the nth highest where n is (number of samples in previous buckets +
- // half the samples in nBlocksToConfirm bucket).
- size_t nPrevSize = 0;
- for (int i = 0; i < nBlocksToConfirm; i++)
- nPrevSize += history.at(i).PrioritySamples();
- size_t index = min(nPrevSize + nBucketSize/2, sortedPrioritySamples.size()-1);
- return sortedPrioritySamples[index];
+void CTxMemPool::UpdateChildrenForRemoval(txiter it)
+{
+ const setEntries &setMemPoolChildren = GetMemPoolChildren(it);
+ BOOST_FOREACH(txiter updateIt, setMemPoolChildren) {
+ UpdateParent(updateIt, it, false);
}
+}
- void Write(CAutoFile& fileout) const
- {
- fileout << nBestSeenHeight;
- fileout << (uint32_t)history.size();
- BOOST_FOREACH(const CBlockAverage& entry, history)
- {
- entry.Write(fileout);
- }
+void CTxMemPool::UpdateForRemoveFromMempool(const setEntries &entriesToRemove)
+{
+ // For each entry, walk back all ancestors and decrement size associated with this
+ // transaction
+ const uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ BOOST_FOREACH(txiter removeIt, entriesToRemove) {
+ setEntries setAncestors;
+ const CTxMemPoolEntry &entry = *removeIt;
+ std::string dummy;
+ CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
+ // Note that UpdateAncestorsOf severs the child links that point to
+ // removeIt in the entries for the parents of removeIt. This is
+ // fine since we don't need to use the mempool children of any entries
+ // to walk back over our ancestors (but we do need the mempool
+ // parents!)
+ UpdateAncestorsOf(false, removeIt, setAncestors);
+ }
+ // After updating all the ancestor sizes, we can now sever the link between each
+ // transaction being removed and any mempool children (ie, update setMemPoolParents
+ // for each direct child of a transaction being removed).
+ BOOST_FOREACH(txiter removeIt, entriesToRemove) {
+ UpdateChildrenForRemoval(removeIt);
}
+}
- void Read(CAutoFile& filein, const CFeeRate& minRelayFee)
- {
- int nFileBestSeenHeight;
- filein >> nFileBestSeenHeight;
- uint32_t numEntries;
- filein >> numEntries;
- if (numEntries <= 0 || numEntries > 10000)
- throw runtime_error("Corrupt estimates file. Must have between 1 and 10k entries.");
-
- std::vector<CBlockAverage> fileHistory;
-
- for (size_t i = 0; i < numEntries; i++)
- {
- CBlockAverage entry;
- entry.Read(filein, minRelayFee);
- fileHistory.push_back(entry);
- }
+void CTxMemPoolEntry::SetDirty()
+{
+ nCountWithDescendants = 0;
+ nSizeWithDescendants = nTxSize;
+ nFeesWithDescendants = nFee;
+}
- // Now that we've processed the entire fee estimate data file and not
- // thrown any errors, we can copy it to our history
- nBestSeenHeight = nFileBestSeenHeight;
- history = fileHistory;
- assert(history.size() > 0);
+void CTxMemPoolEntry::UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount)
+{
+ if (!IsDirty()) {
+ nSizeWithDescendants += modifySize;
+ assert(int64_t(nSizeWithDescendants) > 0);
+ nFeesWithDescendants += modifyFee;
+ assert(nFeesWithDescendants >= 0);
+ nCountWithDescendants += modifyCount;
+ assert(int64_t(nCountWithDescendants) > 0);
}
-};
-
+}
CTxMemPool::CTxMemPool(const CFeeRate& _minRelayFee) :
- nTransactionsUpdated(0),
- minRelayFee(_minRelayFee)
+ nTransactionsUpdated(0)
{
// Sanity checks off by default for performance, because otherwise
// accepting transactions becomes O(N^2) where N is the number
// of transactions in the pool
fSanityCheck = false;
- // 25 blocks is a compromise between using a lot of disk/memory and
- // trying to give accurate estimates to people who might be willing
- // to wait a day or two to save a fraction of a penny in fees.
- // Confirmation times for very-low-fee transactions that take more
- // than an hour or three to confirm are highly variable.
- minerPolicyEstimator = new CMinerPolicyEstimator(25);
+ minerPolicyEstimator = new CBlockPolicyEstimator(_minRelayFee);
}
CTxMemPool::~CTxMemPool()
@@ -419,33 +325,103 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
nTransactionsUpdated += n;
}
-
-bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry)
+bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate)
{
// Add to memory pool without checking anything.
// Used by main.cpp AcceptToMemoryPool(), which DOES do
// all the appropriate checks.
LOCK(cs);
- {
- mapTx[hash] = entry;
- const CTransaction& tx = mapTx[hash].GetTx();
- for (unsigned int i = 0; i < tx.vin.size(); i++)
- mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
- nTransactionsUpdated++;
- totalTxSize += entry.GetTxSize();
+ indexed_transaction_set::iterator newit = mapTx.insert(entry).first;
+ mapLinks.insert(make_pair(newit, TxLinks()));
+
+ // Update cachedInnerUsage to include contained transaction's usage.
+ // (When we update the entry for in-mempool parents, memory usage will be
+ // further updated.)
+ cachedInnerUsage += entry.DynamicMemoryUsage();
+
+ const CTransaction& tx = newit->GetTx();
+ std::set<uint256> setParentTransactions;
+ for (unsigned int i = 0; i < tx.vin.size(); i++) {
+ mapNextTx[tx.vin[i].prevout] = CInPoint(&tx, i);
+ setParentTransactions.insert(tx.vin[i].prevout.hash);
+ }
+ // Don't bother worrying about child transactions of this one.
+ // Normal case of a new transaction arriving is that there can't be any
+ // children, because such children would be orphans.
+ // An exception to that is if a transaction enters that used to be in a block.
+ // In that case, our disconnect block logic will call UpdateTransactionsFromBlock
+ // to clean up the mess we're leaving here.
+
+ // Update ancestors with information about this tx
+ BOOST_FOREACH (const uint256 &phash, setParentTransactions) {
+ txiter pit = mapTx.find(phash);
+ if (pit != mapTx.end()) {
+ UpdateParent(newit, pit, true);
+ }
}
+ UpdateAncestorsOf(true, newit, setAncestors);
+
+ nTransactionsUpdated++;
+ totalTxSize += entry.GetTxSize();
+ minerPolicyEstimator->processTransaction(entry, fCurrentEstimate);
+
return true;
}
+void CTxMemPool::removeUnchecked(txiter it)
+{
+ const uint256 hash = it->GetTx().GetHash();
+ BOOST_FOREACH(const CTxIn& txin, it->GetTx().vin)
+ mapNextTx.erase(txin.prevout);
+
+ totalTxSize -= it->GetTxSize();
+ cachedInnerUsage -= it->DynamicMemoryUsage();
+ cachedInnerUsage -= memusage::DynamicUsage(mapLinks[it].parents) + memusage::DynamicUsage(mapLinks[it].children);
+ mapLinks.erase(it);
+ mapTx.erase(it);
+ nTransactionsUpdated++;
+ minerPolicyEstimator->removeTx(hash);
+}
+
+// Calculates descendants of entry that are not already in setDescendants, and adds to
+// setDescendants. Assumes entryit is already a tx in the mempool and setMemPoolChildren
+// is correct for tx and all descendants.
+// Also assumes that if an entry is in setDescendants already, then all
+// in-mempool descendants of it are already in setDescendants as well, so that we
+// can save time by not iterating over those entries.
+void CTxMemPool::CalculateDescendants(txiter entryit, setEntries &setDescendants)
+{
+ setEntries stage;
+ if (setDescendants.count(entryit) == 0) {
+ stage.insert(entryit);
+ }
+ // Traverse down the children of entry, only adding children that are not
+ // accounted for in setDescendants already (because those children have either
+ // already been walked, or will be walked in this iteration).
+ while (!stage.empty()) {
+ txiter it = *stage.begin();
+ setDescendants.insert(it);
+ stage.erase(it);
+
+ const setEntries &setChildren = GetMemPoolChildren(it);
+ BOOST_FOREACH(const txiter &childiter, setChildren) {
+ if (!setDescendants.count(childiter)) {
+ stage.insert(childiter);
+ }
+ }
+ }
+}
void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& removed, bool fRecursive)
{
// Remove transaction from memory pool
{
LOCK(cs);
- std::deque<uint256> txToRemove;
- txToRemove.push_back(origTx.GetHash());
- if (fRecursive && !mapTx.count(origTx.GetHash())) {
+ setEntries txToRemove;
+ txiter origit = mapTx.find(origTx.GetHash());
+ if (origit != mapTx.end()) {
+ txToRemove.insert(origit);
+ } else if (fRecursive) {
// If recursively removing but origTx isn't in the mempool
// be sure to remove any children that are in the pool. This can
// happen during chain re-orgs if origTx isn't re-accepted into
@@ -454,32 +430,23 @@ void CTxMemPool::remove(const CTransaction &origTx, std::list<CTransaction>& rem
std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(origTx.GetHash(), i));
if (it == mapNextTx.end())
continue;
- txToRemove.push_back(it->second.ptx->GetHash());
+ txiter nextit = mapTx.find(it->second.ptx->GetHash());
+ assert(nextit != mapTx.end());
+ txToRemove.insert(nextit);
}
}
- while (!txToRemove.empty())
- {
- uint256 hash = txToRemove.front();
- txToRemove.pop_front();
- if (!mapTx.count(hash))
- continue;
- const CTransaction& tx = mapTx[hash].GetTx();
- if (fRecursive) {
- for (unsigned int i = 0; i < tx.vout.size(); i++) {
- std::map<COutPoint, CInPoint>::iterator it = mapNextTx.find(COutPoint(hash, i));
- if (it == mapNextTx.end())
- continue;
- txToRemove.push_back(it->second.ptx->GetHash());
- }
+ setEntries setAllRemoves;
+ if (fRecursive) {
+ BOOST_FOREACH(txiter it, txToRemove) {
+ CalculateDescendants(it, setAllRemoves);
}
- BOOST_FOREACH(const CTxIn& txin, tx.vin)
- mapNextTx.erase(txin.prevout);
-
- removed.push_back(tx);
- totalTxSize -= mapTx[hash].GetTxSize();
- mapTx.erase(hash);
- nTransactionsUpdated++;
+ } else {
+ setAllRemoves.swap(txToRemove);
}
+ BOOST_FOREACH(txiter it, setAllRemoves) {
+ removed.push_back(it->GetTx());
+ }
+ RemoveStaged(setAllRemoves);
}
}
@@ -488,15 +455,15 @@ void CTxMemPool::removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned in
// Remove transactions spending a coinbase which are now immature
LOCK(cs);
list<CTransaction> transactionsToRemove;
- for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
- const CTransaction& tx = it->second.GetTx();
+ for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
+ const CTransaction& tx = it->GetTx();
BOOST_FOREACH(const CTxIn& txin, tx.vin) {
- std::map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(txin.prevout.hash);
+ indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
if (it2 != mapTx.end())
continue;
const CCoins *coins = pcoins->AccessCoins(txin.prevout.hash);
if (fSanityCheck) assert(coins);
- if (!coins || (coins->IsCoinBase() && nMemPoolHeight - coins->nHeight < COINBASE_MATURITY)) {
+ if (!coins || (coins->IsCoinBase() && ((signed long)nMemPoolHeight) - coins->nHeight < COINBASE_MATURITY)) {
transactionsToRemove.push_back(tx);
break;
}
@@ -529,17 +496,18 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list<CTransaction>
* Called when a block is connected. Removes from mempool and updates the miner fee estimator.
*/
void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
- std::list<CTransaction>& conflicts)
+ std::list<CTransaction>& conflicts, bool fCurrentEstimate)
{
LOCK(cs);
std::vector<CTxMemPoolEntry> entries;
BOOST_FOREACH(const CTransaction& tx, vtx)
{
uint256 hash = tx.GetHash();
- if (mapTx.count(hash))
- entries.push_back(mapTx[hash]);
+
+ indexed_transaction_set::iterator i = mapTx.find(hash);
+ if (i != mapTx.end())
+ entries.push_back(*i);
}
- minerPolicyEstimator->seenBlock(entries, nBlockHeight, minRelayFee);
BOOST_FOREACH(const CTransaction& tx, vtx)
{
std::list<CTransaction> dummy;
@@ -547,15 +515,18 @@ void CTxMemPool::removeForBlock(const std::vector<CTransaction>& vtx, unsigned i
removeConflicts(tx, conflicts);
ClearPrioritisation(tx.GetHash());
}
+ // After the txs in the new block have been removed from the mempool, update policy estimates
+ minerPolicyEstimator->processBlock(nBlockHeight, entries, fCurrentEstimate);
}
-
void CTxMemPool::clear()
{
LOCK(cs);
+ mapLinks.clear();
mapTx.clear();
mapNextTx.clear();
totalTxSize = 0;
+ cachedInnerUsage = 0;
++nTransactionsUpdated;
}
@@ -567,23 +538,31 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
LogPrint("mempool", "Checking mempool with %u transactions and %u inputs\n", (unsigned int)mapTx.size(), (unsigned int)mapNextTx.size());
uint64_t checkTotal = 0;
+ uint64_t innerUsage = 0;
CCoinsViewCache mempoolDuplicate(const_cast<CCoinsViewCache*>(pcoins));
LOCK(cs);
list<const CTxMemPoolEntry*> waitingOnDependants;
- for (std::map<uint256, CTxMemPoolEntry>::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
+ for (indexed_transaction_set::const_iterator it = mapTx.begin(); it != mapTx.end(); it++) {
unsigned int i = 0;
- checkTotal += it->second.GetTxSize();
- const CTransaction& tx = it->second.GetTx();
+ checkTotal += it->GetTxSize();
+ innerUsage += it->DynamicMemoryUsage();
+ const CTransaction& tx = it->GetTx();
+ txlinksMap::const_iterator linksiter = mapLinks.find(it);
+ assert(linksiter != mapLinks.end());
+ const TxLinks &links = linksiter->second;
+ innerUsage += memusage::DynamicUsage(links.parents) + memusage::DynamicUsage(links.children);
bool fDependsWait = false;
+ setEntries setParentCheck;
BOOST_FOREACH(const CTxIn &txin, tx.vin) {
// Check that every mempool transaction's inputs refer to available coins, or other mempool tx's.
- std::map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(txin.prevout.hash);
+ indexed_transaction_set::const_iterator it2 = mapTx.find(txin.prevout.hash);
if (it2 != mapTx.end()) {
- const CTransaction& tx2 = it2->second.GetTx();
+ const CTransaction& tx2 = it2->GetTx();
assert(tx2.vout.size() > txin.prevout.n && !tx2.vout[txin.prevout.n].IsNull());
fDependsWait = true;
+ setParentCheck.insert(it2);
} else {
const CCoins* coins = pcoins->AccessCoins(txin.prevout.hash);
assert(coins && coins->IsAvailable(txin.prevout.n));
@@ -595,8 +574,35 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
assert(it3->second.n == i);
i++;
}
+ assert(setParentCheck == GetMemPoolParents(it));
+ // Check children against mapNextTx
+ CTxMemPool::setEntries setChildrenCheck;
+ std::map<COutPoint, CInPoint>::const_iterator iter = mapNextTx.lower_bound(COutPoint(it->GetTx().GetHash(), 0));
+ int64_t childSizes = 0;
+ CAmount childFees = 0;
+ for (; iter != mapNextTx.end() && iter->first.hash == it->GetTx().GetHash(); ++iter) {
+ txiter childit = mapTx.find(iter->second.ptx->GetHash());
+ assert(childit != mapTx.end()); // mapNextTx points to in-mempool transactions
+ if (setChildrenCheck.insert(childit).second) {
+ childSizes += childit->GetTxSize();
+ childFees += childit->GetFee();
+ }
+ }
+ assert(setChildrenCheck == GetMemPoolChildren(it));
+ // Also check to make sure size/fees is greater than sum with immediate children.
+ // just a sanity check, not definitive that this calc is correct...
+ // also check that the size is less than the size of the entire mempool.
+ if (!it->IsDirty()) {
+ assert(it->GetSizeWithDescendants() >= childSizes + it->GetTxSize());
+ assert(it->GetFeesWithDescendants() >= childFees + it->GetFee());
+ } else {
+ assert(it->GetSizeWithDescendants() == it->GetTxSize());
+ assert(it->GetFeesWithDescendants() == it->GetFee());
+ }
+ assert(it->GetFeesWithDescendants() >= 0);
+
if (fDependsWait)
- waitingOnDependants.push_back(&it->second);
+ waitingOnDependants.push_back(&(*it));
else {
CValidationState state;
assert(CheckInputs(tx, state, mempoolDuplicate, false, 0, false, NULL));
@@ -620,8 +626,8 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
}
for (std::map<COutPoint, CInPoint>::const_iterator it = mapNextTx.begin(); it != mapNextTx.end(); it++) {
uint256 hash = it->second.ptx->GetHash();
- map<uint256, CTxMemPoolEntry>::const_iterator it2 = mapTx.find(hash);
- const CTransaction& tx = it2->second.GetTx();
+ indexed_transaction_set::const_iterator it2 = mapTx.find(hash);
+ const CTransaction& tx = it2->GetTx();
assert(it2 != mapTx.end());
assert(&tx == it->second.ptx);
assert(tx.vin.size() > it->second.n);
@@ -629,6 +635,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const
}
assert(totalTxSize == checkTotal);
+ assert(innerUsage == cachedInnerUsage);
}
void CTxMemPool::queryHashes(vector<uint256>& vtxid)
@@ -637,16 +644,16 @@ void CTxMemPool::queryHashes(vector<uint256>& vtxid)
LOCK(cs);
vtxid.reserve(mapTx.size());
- for (map<uint256, CTxMemPoolEntry>::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
- vtxid.push_back((*mi).first);
+ for (indexed_transaction_set::iterator mi = mapTx.begin(); mi != mapTx.end(); ++mi)
+ vtxid.push_back(mi->GetTx().GetHash());
}
bool CTxMemPool::lookup(uint256 hash, CTransaction& result) const
{
LOCK(cs);
- map<uint256, CTxMemPoolEntry>::const_iterator i = mapTx.find(hash);
+ indexed_transaction_set::const_iterator i = mapTx.find(hash);
if (i == mapTx.end()) return false;
- result = i->second.GetTx();
+ result = i->GetTx();
return true;
}
@@ -666,12 +673,12 @@ CTxMemPool::WriteFeeEstimates(CAutoFile& fileout) const
{
try {
LOCK(cs);
- fileout << 99900; // version required to read: 0.9.99 or later
+ fileout << 109900; // version required to read: 0.10.99 or later
fileout << CLIENT_VERSION; // version that wrote the file
minerPolicyEstimator->Write(fileout);
}
catch (const std::exception&) {
- LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)");
+ LogPrintf("CTxMemPool::WriteFeeEstimates(): unable to write policy estimator data (non-fatal)\n");
return false;
}
return true;
@@ -687,10 +694,10 @@ CTxMemPool::ReadFeeEstimates(CAutoFile& filein)
return error("CTxMemPool::ReadFeeEstimates(): up-version (%d) fee estimate file", nVersionRequired);
LOCK(cs);
- minerPolicyEstimator->Read(filein, minRelayFee);
+ minerPolicyEstimator->Read(filein);
}
catch (const std::exception&) {
- LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)");
+ LogPrintf("CTxMemPool::ReadFeeEstimates(): unable to read policy estimator data (non-fatal)\n");
return false;
}
return true;
@@ -724,6 +731,13 @@ void CTxMemPool::ClearPrioritisation(const uint256 hash)
mapDeltas.erase(hash);
}
+bool CTxMemPool::HasNoInputsOf(const CTransaction &tx) const
+{
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
+ if (exists(tx.vin[i].prevout.hash))
+ return false;
+ return true;
+}
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView *baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { }
@@ -742,3 +756,63 @@ bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) const {
bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) const {
return mempool.exists(txid) || base->HaveCoins(txid);
}
+
+size_t CTxMemPool::DynamicMemoryUsage() const {
+ LOCK(cs);
+ // Estimate the overhead of mapTx to be 9 pointers + an allocation, as no exact formula for boost::multi_index_contained is implemented.
+ return memusage::MallocUsage(sizeof(CTxMemPoolEntry) + 9 * sizeof(void*)) * mapTx.size() + memusage::DynamicUsage(mapNextTx) + memusage::DynamicUsage(mapDeltas) + memusage::DynamicUsage(mapLinks) + cachedInnerUsage;
+}
+
+void CTxMemPool::RemoveStaged(setEntries &stage) {
+ AssertLockHeld(cs);
+ UpdateForRemoveFromMempool(stage);
+ BOOST_FOREACH(const txiter& it, stage) {
+ removeUnchecked(it);
+ }
+}
+
+bool CTxMemPool::addUnchecked(const uint256&hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate)
+{
+ LOCK(cs);
+ setEntries setAncestors;
+ uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
+ std::string dummy;
+ CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
+ return addUnchecked(hash, entry, setAncestors, fCurrentEstimate);
+}
+
+void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
+{
+ setEntries s;
+ if (add && mapLinks[entry].children.insert(child).second) {
+ cachedInnerUsage += memusage::IncrementalDynamicUsage(s);
+ } else if (!add && mapLinks[entry].children.erase(child)) {
+ cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);
+ }
+}
+
+void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add)
+{
+ setEntries s;
+ if (add && mapLinks[entry].parents.insert(parent).second) {
+ cachedInnerUsage += memusage::IncrementalDynamicUsage(s);
+ } else if (!add && mapLinks[entry].parents.erase(parent)) {
+ cachedInnerUsage -= memusage::IncrementalDynamicUsage(s);
+ }
+}
+
+const CTxMemPool::setEntries & CTxMemPool::GetMemPoolParents(txiter entry) const
+{
+ assert (entry != mapTx.end());
+ txlinksMap::const_iterator it = mapLinks.find(entry);
+ assert(it != mapLinks.end());
+ return it->second.parents;
+}
+
+const CTxMemPool::setEntries & CTxMemPool::GetMemPoolChildren(txiter entry) const
+{
+ assert (entry != mapTx.end());
+ txlinksMap::const_iterator it = mapLinks.find(entry);
+ assert(it != mapLinks.end());
+ return it->second.children;
+}
diff --git a/src/txmempool.h b/src/txmempool.h
index 0732af67e6..f0c3f7e0f1 100644
--- a/src/txmempool.h
+++ b/src/txmempool.h
@@ -7,12 +7,17 @@
#define BITCOIN_TXMEMPOOL_H
#include <list>
+#include <set>
#include "amount.h"
#include "coins.h"
#include "primitives/transaction.h"
#include "sync.h"
+#undef foreach
+#include "boost/multi_index_container.hpp"
+#include "boost/multi_index/ordered_index.hpp"
+
class CAutoFile;
inline double AllowFreeThreshold()
@@ -30,9 +35,25 @@ inline bool AllowFree(double dPriority)
/** Fake height value used in CCoins to signify they are only in the memory pool (since 0.8) */
static const unsigned int MEMPOOL_HEIGHT = 0x7FFFFFFF;
-/**
- * CTxMemPool stores these:
+class CTxMemPool;
+
+/** \class CTxMemPoolEntry
+ *
+ * CTxMemPoolEntry stores data about the correponding transaction, as well
+ * as data about all in-mempool transactions that depend on the transaction
+ * ("descendant" transactions).
+ *
+ * When a new entry is added to the mempool, we update the descendant state
+ * (nCountWithDescendants, nSizeWithDescendants, and nFeesWithDescendants) for
+ * all ancestors of the newly added transaction.
+ *
+ * If updating the descendant state is skipped, we can mark the entry as
+ * "dirty", and set nSizeWithDescendants/nFeesWithDescendants to equal nTxSize/
+ * nTxFee. (This can potentially happen during a reorg, where we limit the
+ * amount of work we're willing to do to avoid consuming too much CPU.)
+ *
*/
+
class CTxMemPoolEntry
{
private:
@@ -40,14 +61,24 @@ private:
CAmount nFee; //! Cached to avoid expensive parent-transaction lookups
size_t nTxSize; //! ... and avoid recomputing tx size
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
+ bool hadNoDependencies; //! Not dependent on any other txs when it entered the mempool
+
+ // Information about descendants of this transaction that are in the
+ // mempool; if we remove this transaction we must remove all of these
+ // descendants as well. if nCountWithDescendants is 0, treat this entry as
+ // dirty, and nSizeWithDescendants and nFeesWithDescendants will not be
+ // correct.
+ uint64_t nCountWithDescendants; //! number of descendant transactions
+ uint64_t nSizeWithDescendants; //! ... and size
+ CAmount nFeesWithDescendants; //! ... and total fees (all including us)
public:
CTxMemPoolEntry(const CTransaction& _tx, const CAmount& _nFee,
- int64_t _nTime, double _dPriority, unsigned int _nHeight);
- CTxMemPoolEntry();
+ int64_t _nTime, double _dPriority, unsigned int _nHeight, bool poolHasNoInputsOf = false);
CTxMemPoolEntry(const CTxMemPoolEntry& other);
const CTransaction& GetTx() const { return this->tx; }
@@ -56,9 +87,103 @@ public:
size_t GetTxSize() const { return nTxSize; }
int64_t GetTime() const { return nTime; }
unsigned int GetHeight() const { return nHeight; }
+ bool WasClearAtEntry() const { return hadNoDependencies; }
+ size_t DynamicMemoryUsage() const { return nUsageSize; }
+
+ // Adjusts the descendant state, if this entry is not dirty.
+ void UpdateState(int64_t modifySize, CAmount modifyFee, int64_t modifyCount);
+
+ /** We can set the entry to be dirty if doing the full calculation of in-
+ * mempool descendants will be too expensive, which can potentially happen
+ * when re-adding transactions from a block back to the mempool.
+ */
+ void SetDirty();
+ bool IsDirty() const { return nCountWithDescendants == 0; }
+
+ uint64_t GetCountWithDescendants() const { return nCountWithDescendants; }
+ uint64_t GetSizeWithDescendants() const { return nSizeWithDescendants; }
+ CAmount GetFeesWithDescendants() const { return nFeesWithDescendants; }
+};
+
+// Helpers for modifying CTxMemPool::mapTx, which is a boost multi_index.
+struct update_descendant_state
+{
+ update_descendant_state(int64_t _modifySize, CAmount _modifyFee, int64_t _modifyCount) :
+ modifySize(_modifySize), modifyFee(_modifyFee), modifyCount(_modifyCount)
+ {}
+
+ void operator() (CTxMemPoolEntry &e)
+ { e.UpdateState(modifySize, modifyFee, modifyCount); }
+
+ private:
+ int64_t modifySize;
+ CAmount modifyFee;
+ int64_t modifyCount;
+};
+
+struct set_dirty
+{
+ void operator() (CTxMemPoolEntry &e)
+ { e.SetDirty(); }
};
-class CMinerPolicyEstimator;
+// extracts a TxMemPoolEntry's transaction hash
+struct mempoolentry_txid
+{
+ typedef uint256 result_type;
+ result_type operator() (const CTxMemPoolEntry &entry) const
+ {
+ return entry.GetTx().GetHash();
+ }
+};
+
+/** \class CompareTxMemPoolEntryByFee
+ *
+ * Sort an entry by max(feerate of entry's tx, feerate with all descendants).
+ */
+class CompareTxMemPoolEntryByFee
+{
+public:
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ {
+ bool fUseADescendants = UseDescendantFeeRate(a);
+ bool fUseBDescendants = UseDescendantFeeRate(b);
+
+ double aFees = fUseADescendants ? a.GetFeesWithDescendants() : a.GetFee();
+ double aSize = fUseADescendants ? a.GetSizeWithDescendants() : a.GetTxSize();
+
+ double bFees = fUseBDescendants ? b.GetFeesWithDescendants() : b.GetFee();
+ double bSize = fUseBDescendants ? b.GetSizeWithDescendants() : b.GetTxSize();
+
+ // Avoid division by rewriting (a/b > c/d) as (a*d > c*b).
+ double f1 = aFees * bSize;
+ double f2 = aSize * bFees;
+
+ if (f1 == f2) {
+ return a.GetTime() < b.GetTime();
+ }
+ return f1 > f2;
+ }
+
+ // Calculate which feerate to use for an entry (avoiding division).
+ bool UseDescendantFeeRate(const CTxMemPoolEntry &a)
+ {
+ double f1 = (double)a.GetFee() * a.GetSizeWithDescendants();
+ double f2 = (double)a.GetFeesWithDescendants() * a.GetTxSize();
+ return f2 > f1;
+ }
+};
+
+class CompareTxMemPoolEntryByEntryTime
+{
+public:
+ bool operator()(const CTxMemPoolEntry& a, const CTxMemPoolEntry& b)
+ {
+ return a.GetTime() < b.GetTime();
+ }
+};
+
+class CBlockPolicyEstimator;
/** An inpoint - a combination of a transaction and an index n into its vin */
class CInPoint
@@ -71,6 +196,7 @@ public:
CInPoint(const CTransaction* ptxIn, uint32_t nIn) { ptx = ptxIn; n = nIn; }
void SetNull() { ptx = NULL; n = (uint32_t) -1; }
bool IsNull() const { return (ptx == NULL && n == (uint32_t) -1); }
+ size_t DynamicMemoryUsage() const { return 0; }
};
/**
@@ -82,20 +208,123 @@ public:
* are added to the pool: if a new transaction double-spends
* an input of a transaction in the pool, it is dropped,
* as are non-standard transactions.
+ *
+ * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
+ *
+ * mapTx is a boost::multi_index that sorts the mempool on 2 criteria:
+ * - transaction hash
+ * - feerate [we use max(feerate of tx, feerate of tx with all descendants)]
+ *
+ * Note: the term "descendant" refers to in-mempool transactions that depend on
+ * this one, while "ancestor" refers to in-mempool transactions that a given
+ * transaction depends on.
+ *
+ * In order for the feerate sort to remain correct, we must update transactions
+ * in the mempool when new descendants arrive. To facilitate this, we track
+ * the set of in-mempool direct parents and direct children in mapLinks. Within
+ * each CTxMemPoolEntry, we track the size and fees of all descendants.
+ *
+ * Usually when a new transaction is added to the mempool, it has no in-mempool
+ * children (because any such children would be an orphan). So in
+ * addUnchecked(), we:
+ * - update a new entry's setMemPoolParents to include all in-mempool parents
+ * - update the new entry's direct parents to include the new tx as a child
+ * - update all ancestors of the transaction to include the new tx's size/fee
+ *
+ * When a transaction is removed from the mempool, we must:
+ * - update all in-mempool parents to not track the tx in setMemPoolChildren
+ * - update all ancestors to not include the tx's size/fees in descendant state
+ * - update all in-mempool children to not include it as a parent
+ *
+ * These happen in UpdateForRemoveFromMempool(). (Note that when removing a
+ * transaction along with its descendants, we must calculate that set of
+ * transactions to be removed before doing the removal, or else the mempool can
+ * be in an inconsistent state where it's impossible to walk the ancestors of
+ * a transaction.)
+ *
+ * In the event of a reorg, the assumption that a newly added tx has no
+ * in-mempool children is false. In particular, the mempool is in an
+ * inconsistent state while new transactions are being added, because there may
+ * be descendant transactions of a tx coming from a disconnected block that are
+ * unreachable from just looking at transactions in the mempool (the linking
+ * transactions may also be in the disconnected block, waiting to be added).
+ * Because of this, there's not much benefit in trying to search for in-mempool
+ * children in addUnchecked(). Instead, in the special case of transactions
+ * being added from a disconnected block, we require the caller to clean up the
+ * state, to account for in-mempool, out-of-block descendants for all the
+ * in-block transactions by calling UpdateTransactionsFromBlock(). Note that
+ * until this is called, the mempool state is not consistent, and in particular
+ * mapLinks may not be correct (and therefore functions like
+ * CalculateMemPoolAncestors() and CalculateDescendants() that rely
+ * on them to walk the mempool are not generally safe to use).
+ *
+ * Computational limits:
+ *
+ * Updating all in-mempool ancestors of a newly added transaction can be slow,
+ * if no bound exists on how many in-mempool ancestors there may be.
+ * CalculateMemPoolAncestors() takes configurable limits that are designed to
+ * prevent these calculations from being too CPU intensive.
+ *
+ * Adding transactions from a disconnected block can be very time consuming,
+ * because we don't have a way to limit the number of in-mempool descendants.
+ * To bound CPU processing, we limit the amount of work we're willing to do
+ * to properly update the descendant information for a tx being added from
+ * a disconnected block. If we would exceed the limit, then we instead mark
+ * the entry as "dirty", and set the feerate for sorting purposes to be equal
+ * the feerate of the transaction without any descendants.
+ *
*/
class CTxMemPool
{
private:
bool fSanityCheck; //! Normally false, true if -checkmempool or -regtest
unsigned int nTransactionsUpdated;
- CMinerPolicyEstimator* minerPolicyEstimator;
+ CBlockPolicyEstimator* minerPolicyEstimator;
- CFeeRate minRelayFee; //! Passed to constructor to avoid dependency on main
uint64_t totalTxSize; //! sum of all mempool tx' byte sizes
+ uint64_t cachedInnerUsage; //! sum of dynamic memory usage of all the map elements (NOT the maps themselves)
public:
+ typedef boost::multi_index_container<
+ CTxMemPoolEntry,
+ boost::multi_index::indexed_by<
+ // sorted by txid
+ boost::multi_index::ordered_unique<mempoolentry_txid>,
+ // sorted by fee rate
+ boost::multi_index::ordered_non_unique<
+ boost::multi_index::identity<CTxMemPoolEntry>,
+ CompareTxMemPoolEntryByFee
+ >
+ >
+ > indexed_transaction_set;
+
mutable CCriticalSection cs;
- std::map<uint256, CTxMemPoolEntry> mapTx;
+ indexed_transaction_set mapTx;
+ typedef indexed_transaction_set::nth_index<0>::type::iterator txiter;
+ struct CompareIteratorByHash {
+ bool operator()(const txiter &a, const txiter &b) const {
+ return a->GetTx().GetHash() < b->GetTx().GetHash();
+ }
+ };
+ typedef std::set<txiter, CompareIteratorByHash> setEntries;
+
+private:
+ typedef std::map<txiter, setEntries, CompareIteratorByHash> cacheMap;
+
+ struct TxLinks {
+ setEntries parents;
+ setEntries children;
+ };
+
+ typedef std::map<txiter, TxLinks, CompareIteratorByHash> txlinksMap;
+ txlinksMap mapLinks;
+
+ const setEntries & GetMemPoolParents(txiter entry) const;
+ const setEntries & GetMemPoolChildren(txiter entry) const;
+ void UpdateParent(txiter entry, txiter parent, bool add);
+ void UpdateChild(txiter entry, txiter child, bool add);
+
+public:
std::map<COutPoint, CInPoint> mapNextTx;
std::map<uint256, std::pair<double, CAmount> > mapDeltas;
@@ -111,35 +340,74 @@ public:
void check(const CCoinsViewCache *pcoins) const;
void setSanityCheck(bool _fSanityCheck) { fSanityCheck = _fSanityCheck; }
- bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry);
+ // addUnchecked must updated state for all ancestors of a given transaction,
+ // to track size/count of descendant transactions. First version of
+ // addUnchecked can be used to have it call CalculateMemPoolAncestors(), and
+ // then invoke the second version.
+ bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, bool fCurrentEstimate = true);
+ bool addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, setEntries &setAncestors, bool fCurrentEstimate = true);
+
void remove(const CTransaction &tx, std::list<CTransaction>& removed, bool fRecursive = false);
void removeCoinbaseSpends(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight);
void removeConflicts(const CTransaction &tx, std::list<CTransaction>& removed);
void removeForBlock(const std::vector<CTransaction>& vtx, unsigned int nBlockHeight,
- std::list<CTransaction>& conflicts);
+ std::list<CTransaction>& conflicts, bool fCurrentEstimate = true);
void clear();
void queryHashes(std::vector<uint256>& vtxid);
void pruneSpent(const uint256& hash, CCoins &coins);
unsigned int GetTransactionsUpdated() const;
void AddTransactionsUpdated(unsigned int n);
+ /**
+ * Check that none of this transactions inputs are in the mempool, and thus
+ * the tx is not dependent on other mempool transactions to be included in a block.
+ */
+ bool HasNoInputsOf(const CTransaction& tx) const;
/** Affect CreateNewBlock prioritisation of transactions */
void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount& nFeeDelta);
void ApplyDeltas(const uint256 hash, double &dPriorityDelta, CAmount &nFeeDelta);
void ClearPrioritisation(const uint256 hash);
+public:
+ /** Remove a set of transactions from the mempool.
+ * If a transaction is in this set, then all in-mempool descendants must
+ * also be in the set.*/
+ void RemoveStaged(setEntries &stage);
+
+ /** When adding transactions from a disconnected block back to the mempool,
+ * new mempool entries may have children in the mempool (which is generally
+ * not the case when otherwise adding transactions).
+ * UpdateTransactionsFromBlock() will find child transactions and update the
+ * descendant state for each transaction in hashesToUpdate (excluding any
+ * child transactions present in hashesToUpdate, which are already accounted
+ * for). Note: hashesToUpdate should be the set of transactions from the
+ * disconnected block that have been accepted back into the mempool.
+ */
+ void UpdateTransactionsFromBlock(const std::vector<uint256> &hashesToUpdate);
+
+ /** Try to calculate all in-mempool ancestors of entry.
+ * (these are all calculated including the tx itself)
+ * limitAncestorCount = max number of ancestors
+ * limitAncestorSize = max size of ancestors
+ * limitDescendantCount = max number of descendants any ancestor can have
+ * limitDescendantSize = max size of descendants any ancestor can have
+ * errString = populated with error reason if any limits are hit
+ */
+ bool CalculateMemPoolAncestors(const CTxMemPoolEntry &entry, setEntries &setAncestors, uint64_t limitAncestorCount, uint64_t limitAncestorSize, uint64_t limitDescendantCount, uint64_t limitDescendantSize, std::string &errString);
+
unsigned long size()
{
LOCK(cs);
return mapTx.size();
}
+
uint64_t GetTotalTxSize()
{
LOCK(cs);
return totalTxSize;
}
- bool exists(uint256 hash)
+ bool exists(uint256 hash) const
{
LOCK(cs);
return (mapTx.count(hash) != 0);
@@ -156,6 +424,50 @@ public:
/** Write/Read estimates to disk */
bool WriteFeeEstimates(CAutoFile& fileout) const;
bool ReadFeeEstimates(CAutoFile& filein);
+
+ size_t DynamicMemoryUsage() const;
+
+private:
+ /** UpdateForDescendants is used by UpdateTransactionsFromBlock to update
+ * the descendants for a single transaction that has been added to the
+ * mempool but may have child transactions in the mempool, eg during a
+ * chain reorg. setExclude is the set of descendant transactions in the
+ * mempool that must not be accounted for (because any descendants in
+ * setExclude were added to the mempool after the transaction being
+ * updated and hence their state is already reflected in the parent
+ * state).
+ *
+ * If updating an entry requires looking at more than maxDescendantsToVisit
+ * transactions, outside of the ones in setExclude, then give up.
+ *
+ * cachedDescendants will be updated with the descendants of the transaction
+ * being updated, so that future invocations don't need to walk the
+ * same transaction again, if encountered in another transaction chain.
+ */
+ bool UpdateForDescendants(txiter updateIt,
+ int maxDescendantsToVisit,
+ cacheMap &cachedDescendants,
+ const std::set<uint256> &setExclude);
+ /** Update ancestors of hash to add/remove it as a descendant transaction. */
+ void UpdateAncestorsOf(bool add, txiter hash, setEntries &setAncestors);
+ /** For each transaction being removed, update ancestors and any direct children. */
+ void UpdateForRemoveFromMempool(const setEntries &entriesToRemove);
+ /** Sever link between specified transaction and direct children. */
+ void UpdateChildrenForRemoval(txiter entry);
+ /** Populate setDescendants with all in-mempool descendants of hash.
+ * Assumes that setDescendants includes all in-mempool descendants of anything
+ * already in it. */
+ void CalculateDescendants(txiter it, setEntries &setDescendants);
+
+ /** Before calling removeUnchecked for a given transaction,
+ * UpdateForRemoveFromMempool must be called on the entire (dependent) set
+ * of transactions being removed at the same time. We use each
+ * CTxMemPoolEntry's setMemPoolParents in order to walk ancestors of a
+ * given transaction that is removed, so we can't remove intermediate
+ * transactions in a chain before we've updated all the state for the
+ * removal.
+ */
+ void removeUnchecked(txiter entry);
};
/**
diff --git a/src/ui_interface.h b/src/ui_interface.h
index 32a92a4b81..e402479933 100644
--- a/src/ui_interface.h
+++ b/src/ui_interface.h
@@ -95,6 +95,9 @@ public:
/** New block has been accepted */
boost::signals2::signal<void (const uint256& hash)> NotifyBlockTip;
+
+ /** Banlist did change. */
+ boost::signals2::signal<void (void)> BannedListChanged;
};
extern CClientUIInterface uiInterface;
diff --git a/src/univalue/gen.cpp b/src/univalue/gen.cpp
index abebe88634..5e5a4d4aed 100644
--- a/src/univalue/gen.cpp
+++ b/src/univalue/gen.cpp
@@ -22,7 +22,6 @@ static void initJsonEscape()
{
escapes[(int)'"'] = "\\\"";
escapes[(int)'\\'] = "\\\\";
- escapes[(int)'/'] = "\\/";
escapes[(int)'\b'] = "\\b";
escapes[(int)'\f'] = "\\f";
escapes[(int)'\n'] = "\\n";
diff --git a/src/univalue/univalue.cpp b/src/univalue/univalue.cpp
index 4e445a542a..1d49a2cfc9 100644
--- a/src/univalue/univalue.cpp
+++ b/src/univalue/univalue.cpp
@@ -4,12 +4,17 @@
#include <stdint.h>
#include <ctype.h>
+#include <iomanip>
#include <sstream>
+#include <stdexcept> // std::runtime_error
+
#include "univalue.h"
+#include "utilstrencodings.h" // ParseXX
+
using namespace std;
-static const UniValue nullValue;
+const UniValue NullUniValue;
void UniValue::clear()
{
@@ -78,9 +83,11 @@ bool UniValue::setFloat(double val)
string s;
ostringstream oss;
- oss << val;
+ oss << std::setprecision(16) << val;
- return setNumStr(oss.str());
+ bool ret = setNumStr(oss.str());
+ typ = VNUM;
+ return ret;
}
bool UniValue::setStr(const string& val_)
@@ -175,11 +182,11 @@ bool UniValue::checkObject(const std::map<std::string,UniValue::VType>& t)
const UniValue& UniValue::operator[](const std::string& key) const
{
if (typ != VOBJ)
- return nullValue;
+ return NullUniValue;
int index = findKey(key);
if (index < 0)
- return nullValue;
+ return NullUniValue;
return values[index];
}
@@ -187,9 +194,9 @@ const UniValue& UniValue::operator[](const std::string& key) const
const UniValue& UniValue::operator[](unsigned int index) const
{
if (typ != VOBJ && typ != VARR)
- return nullValue;
+ return NullUniValue;
if (index >= values.size())
- return nullValue;
+ return NullUniValue;
return values[index];
}
@@ -209,3 +216,88 @@ const char *uvTypeName(UniValue::VType t)
return NULL;
}
+const UniValue& find_value( const UniValue& obj, const std::string& name)
+{
+ for (unsigned int i = 0; i < obj.keys.size(); i++)
+ {
+ if( obj.keys[i] == name )
+ {
+ return obj.values[i];
+ }
+ }
+
+ return NullUniValue;
+}
+
+std::vector<std::string> UniValue::getKeys() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return keys;
+}
+
+std::vector<UniValue> UniValue::getValues() const
+{
+ if (typ != VOBJ && typ != VARR)
+ throw std::runtime_error("JSON value is not an object or array as expected");
+ return values;
+}
+
+bool UniValue::get_bool() const
+{
+ if (typ != VBOOL)
+ throw std::runtime_error("JSON value is not a boolean as expected");
+ return getBool();
+}
+
+std::string UniValue::get_str() const
+{
+ if (typ != VSTR)
+ throw std::runtime_error("JSON value is not a string as expected");
+ return getValStr();
+}
+
+int UniValue::get_int() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int32_t retval;
+ if (!ParseInt32(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+int64_t UniValue::get_int64() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not an integer as expected");
+ int64_t retval;
+ if (!ParseInt64(getValStr(), &retval))
+ throw std::runtime_error("JSON integer out of range");
+ return retval;
+}
+
+double UniValue::get_real() const
+{
+ if (typ != VNUM)
+ throw std::runtime_error("JSON value is not a number as expected");
+ double retval;
+ if (!ParseDouble(getValStr(), &retval))
+ throw std::runtime_error("JSON double out of range");
+ return retval;
+}
+
+const UniValue& UniValue::get_obj() const
+{
+ if (typ != VOBJ)
+ throw std::runtime_error("JSON value is not an object as expected");
+ return *this;
+}
+
+const UniValue& UniValue::get_array() const
+{
+ if (typ != VARR)
+ throw std::runtime_error("JSON value is not an array as expected");
+ return *this;
+}
+
diff --git a/src/univalue/univalue.h b/src/univalue/univalue.h
index 88d73b8c64..4742b56f3d 100644
--- a/src/univalue/univalue.h
+++ b/src/univalue/univalue.h
@@ -11,6 +11,9 @@
#include <map>
#include <cassert>
+#include <sstream> // .get_int64()
+#include <utility> // std::pair
+
class UniValue {
public:
enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
@@ -26,6 +29,9 @@ public:
UniValue(int64_t val_) {
setInt(val_);
}
+ UniValue(bool val_) {
+ setBool(val_);
+ }
UniValue(int val_) {
setInt(val_);
}
@@ -55,10 +61,10 @@ public:
bool setObject();
enum VType getType() const { return typ; }
- std::string getValStr() const { return val; }
+ const std::string& getValStr() const { return val; }
bool empty() const { return (values.size() == 0); }
- size_t count() const { return values.size(); }
+ size_t size() const { return values.size(); }
bool getBool() const { return isTrue(); }
bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes);
@@ -68,7 +74,7 @@ public:
bool isNull() const { return (typ == VNULL); }
bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
- bool isFalse() const { return (!isTrue()); }
+ bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
bool isBool() const { return (typ == VBOOL); }
bool isStr() const { return (typ == VSTR); }
bool isNum() const { return (typ == VNUM); }
@@ -130,8 +136,91 @@ private:
int findKey(const std::string& key) const;
void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
+
+public:
+ // Strict type-specific getters, these throw std::runtime_error if the
+ // value is of unexpected type
+ std::vector<std::string> getKeys() const;
+ std::vector<UniValue> getValues() const;
+ bool get_bool() const;
+ std::string get_str() const;
+ int get_int() const;
+ int64_t get_int64() const;
+ double get_real() const;
+ const UniValue& get_obj() const;
+ const UniValue& get_array() const;
+
+ enum VType type() const { return getType(); }
+ bool push_back(std::pair<std::string,UniValue> pear) {
+ return pushKV(pear.first, pear.second);
+ }
+ friend const UniValue& find_value( const UniValue& obj, const std::string& name);
};
+//
+// The following were added for compatibility with json_spirit.
+// Most duplicate other methods, and should be removed.
+//
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, const char *cVal)
+{
+ std::string key(cKey);
+ UniValue uVal(cVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, std::string strVal)
+{
+ std::string key(cKey);
+ UniValue uVal(strVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, uint64_t u64Val)
+{
+ std::string key(cKey);
+ UniValue uVal(u64Val);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, int64_t i64Val)
+{
+ std::string key(cKey);
+ UniValue uVal(i64Val);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, bool iVal)
+{
+ std::string key(cKey);
+ UniValue uVal(iVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, int iVal)
+{
+ std::string key(cKey);
+ UniValue uVal(iVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, double dVal)
+{
+ std::string key(cKey);
+ UniValue uVal(dVal);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(const char *cKey, const UniValue& uVal)
+{
+ std::string key(cKey);
+ return std::make_pair(key, uVal);
+}
+
+static inline std::pair<std::string,UniValue> Pair(std::string key, const UniValue& uVal)
+{
+ return std::make_pair(key, uVal);
+}
+
enum jtokentype {
JTOK_ERR = -1,
JTOK_NONE = 0, // eof
@@ -152,4 +241,8 @@ extern enum jtokentype getJsonToken(std::string& tokenVal,
unsigned int& consumed, const char *raw);
extern const char *uvTypeName(UniValue::VType t);
+extern const UniValue NullUniValue;
+
+const UniValue& find_value( const UniValue& obj, const std::string& name);
+
#endif // BITCOIN_UNIVALUE_UNIVALUE_H
diff --git a/src/univalue/univalue_escapes.h b/src/univalue/univalue_escapes.h
index 0514118285..4133b24ca1 100644
--- a/src/univalue/univalue_escapes.h
+++ b/src/univalue/univalue_escapes.h
@@ -49,7 +49,7 @@ static const char *escapes[256] = {
NULL,
NULL,
NULL,
- "\\/",
+ NULL,
NULL,
NULL,
NULL,
diff --git a/src/univalue/univalue_read.cpp b/src/univalue/univalue_read.cpp
index 5cea778996..64591234cb 100644
--- a/src/univalue/univalue_read.cpp
+++ b/src/univalue/univalue_read.cpp
@@ -188,25 +188,22 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
case 't': valStr += "\t"; break;
case 'u': {
- char buf[4] = {0,0,0,0};
- char *last = &buf[0];
unsigned int codepoint;
if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
raw + 1 + 4)
return JTOK_ERR;
if (codepoint <= 0x7f)
- *last = (char)codepoint;
+ valStr.push_back((char)codepoint);
else if (codepoint <= 0x7FF) {
- *last++ = (char)(0xC0 | (codepoint >> 6));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xC0 | (codepoint >> 6)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
} else if (codepoint <= 0xFFFF) {
- *last++ = (char)(0xE0 | (codepoint >> 12));
- *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F));
- *last = (char)(0x80 | (codepoint & 0x3F));
+ valStr.push_back((char)(0xE0 | (codepoint >> 12)));
+ valStr.push_back((char)(0x80 | ((codepoint >> 6) & 0x3F)));
+ valStr.push_back((char)(0x80 | (codepoint & 0x3F)));
}
- valStr += buf;
raw += 4;
break;
}
@@ -247,16 +244,16 @@ bool UniValue::read(const char *raw)
bool expectColon = false;
vector<UniValue*> stack;
+ string tokenVal;
+ unsigned int consumed;
enum jtokentype tok = JTOK_NONE;
enum jtokentype last_tok = JTOK_NONE;
- while (1) {
+ do {
last_tok = tok;
- string tokenVal;
- unsigned int consumed;
tok = getJsonToken(tokenVal, consumed, raw);
if (tok == JTOK_NONE || tok == JTOK_ERR)
- break;
+ return false;
raw += consumed;
switch (tok) {
@@ -380,9 +377,11 @@ bool UniValue::read(const char *raw)
default:
return false;
}
- }
+ } while (!stack.empty ());
- if (stack.size() != 0)
+ /* Check that nothing follows the initial construct (parsed above). */
+ tok = getJsonToken(tokenVal, consumed, raw);
+ if (tok != JTOK_NONE)
return false;
return true;
diff --git a/src/univalue/univalue_write.cpp b/src/univalue/univalue_write.cpp
index 9a1d364c95..bce3997af7 100644
--- a/src/univalue/univalue_write.cpp
+++ b/src/univalue/univalue_write.cpp
@@ -3,6 +3,8 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <ctype.h>
+#include <iomanip>
+#include <sstream>
#include <stdio.h>
#include "univalue.h"
#include "univalue_escapes.h"
diff --git a/src/util.cpp b/src/util.cpp
index da5b259aee..f50d25e17a 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -7,11 +7,6 @@
#include "config/bitcoin-config.h"
#endif
-#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
-#include <pthread.h>
-#include <pthread_np.h>
-#endif
-
#include "util.h"
#include "chainparamsbase.h"
@@ -23,6 +18,11 @@
#include <stdarg.h>
+#if (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
+#include <pthread.h>
+#include <pthread_np.h>
+#endif
+
#ifndef WIN32
// for posix_fallocate
#ifdef __linux__
@@ -83,6 +83,7 @@
#include <boost/thread.hpp>
#include <openssl/crypto.h>
#include <openssl/rand.h>
+#include <openssl/conf.h>
// Work around clang compilation problem in Boost 1.46:
// /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
@@ -113,7 +114,7 @@ CTranslationInterface translationInterface;
/** Init OpenSSL library multithreading support */
static CCriticalSection** ppmutexOpenSSL;
-void locking_callback(int mode, int i, const char* file, int line)
+void locking_callback(int mode, int i, const char* file, int line) NO_THREAD_SAFETY_ANALYSIS
{
if (mode & CRYPTO_LOCK) {
ENTER_CRITICAL_SECTION(*ppmutexOpenSSL[i]);
@@ -134,6 +135,13 @@ public:
ppmutexOpenSSL[i] = new CCriticalSection();
CRYPTO_set_locking_callback(locking_callback);
+ // OpenSSL can optionally load a config file which lists optional loadable modules and engines.
+ // We don't use them so we don't require the config. However some of our libs may call functions
+ // which attempt to load the config file, possibly resulting in an exit() or crash if it is missing
+ // or corrupt. Explicitly tell OpenSSL not to try to load the file. The result for our libs will be
+ // that the config appears to have been loaded and there are no modules/engines available.
+ OPENSSL_no_config();
+
#ifdef WIN32
// Seed OpenSSL PRNG with current contents of the screen
RAND_screen();
@@ -167,23 +175,51 @@ instance_of_cinit;
*/
static boost::once_flag debugPrintInitFlag = BOOST_ONCE_INIT;
+
/**
- * We use boost::call_once() to make sure these are initialized
- * in a thread-safe manner the first time called:
+ * We use boost::call_once() to make sure mutexDebugLog and
+ * vMsgsBeforeOpenLog are initialized in a thread-safe manner.
+ *
+ * NOTE: fileout, mutexDebugLog and sometimes vMsgsBeforeOpenLog
+ * are leaked on exit. This is ugly, but will be cleaned up by
+ * the OS/libc. When the shutdown sequence is fully audited and
+ * tested, explicit destruction of these objects can be implemented.
*/
static FILE* fileout = NULL;
static boost::mutex* mutexDebugLog = NULL;
+static list<string> *vMsgsBeforeOpenLog;
+
+static int FileWriteStr(const std::string &str, FILE *fp)
+{
+ return fwrite(str.data(), 1, str.size(), fp);
+}
static void DebugPrintInit()
{
- assert(fileout == NULL);
assert(mutexDebugLog == NULL);
+ mutexDebugLog = new boost::mutex();
+ vMsgsBeforeOpenLog = new list<string>;
+}
+
+void OpenDebugLog()
+{
+ boost::call_once(&DebugPrintInit, debugPrintInitFlag);
+ boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
+ assert(fileout == NULL);
+ assert(vMsgsBeforeOpenLog);
boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
fileout = fopen(pathDebug.string().c_str(), "a");
if (fileout) setbuf(fileout, NULL); // unbuffered
- mutexDebugLog = new boost::mutex();
+ // dump buffered messages from before we opened the log
+ while (!vMsgsBeforeOpenLog->empty()) {
+ FileWriteStr(vMsgsBeforeOpenLog->front(), fileout);
+ vMsgsBeforeOpenLog->pop_front();
+ }
+
+ delete vMsgsBeforeOpenLog;
+ vMsgsBeforeOpenLog = NULL;
}
bool LogAcceptCategory(const char* category)
@@ -208,65 +244,92 @@ bool LogAcceptCategory(const char* category)
// if not debugging everything and not debugging specific category, LogPrint does nothing.
if (setCategories.count(string("")) == 0 &&
+ setCategories.count(string("1")) == 0 &&
setCategories.count(string(category)) == 0)
return false;
}
return true;
}
+/**
+ * fStartedNewLine is a state variable held by the calling context that will
+ * suppress printing of the timestamp when multiple calls are made that don't
+ * end in a newline. Initialize it to true, and hold it, in the calling context.
+ */
+static std::string LogTimestampStr(const std::string &str, bool *fStartedNewLine)
+{
+ string strStamped;
+
+ if (!fLogTimestamps)
+ return str;
+
+ if (*fStartedNewLine)
+ strStamped = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()) + ' ' + str;
+ else
+ strStamped = str;
+
+ if (!str.empty() && str[str.size()-1] == '\n')
+ *fStartedNewLine = true;
+ else
+ *fStartedNewLine = false;
+
+ return strStamped;
+}
+
int LogPrintStr(const std::string &str)
{
int ret = 0; // Returns total number of characters written
+ static bool fStartedNewLine = true;
if (fPrintToConsole)
{
// print to console
ret = fwrite(str.data(), 1, str.size(), stdout);
fflush(stdout);
}
- else if (fPrintToDebugLog && AreBaseParamsConfigured())
+ else if (fPrintToDebugLog)
{
- static bool fStartedNewLine = true;
boost::call_once(&DebugPrintInit, debugPrintInitFlag);
-
- if (fileout == NULL)
- return ret;
-
boost::mutex::scoped_lock scoped_lock(*mutexDebugLog);
- // reopen the log file, if requested
- if (fReopenDebugLog) {
- fReopenDebugLog = false;
- boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
- if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
- setbuf(fileout, NULL); // unbuffered
- }
+ string strTimestamped = LogTimestampStr(str, &fStartedNewLine);
- // Debug print useful for profiling
- if (fLogTimestamps && fStartedNewLine)
- ret += fprintf(fileout, "%s ", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime()).c_str());
- if (!str.empty() && str[str.size()-1] == '\n')
- fStartedNewLine = true;
+ // buffer if we haven't opened the log yet
+ if (fileout == NULL) {
+ assert(vMsgsBeforeOpenLog);
+ ret = strTimestamped.length();
+ vMsgsBeforeOpenLog->push_back(strTimestamped);
+ }
else
- fStartedNewLine = false;
-
- ret = fwrite(str.data(), 1, str.size(), fileout);
+ {
+ // reopen the log file, if requested
+ if (fReopenDebugLog) {
+ fReopenDebugLog = false;
+ boost::filesystem::path pathDebug = GetDataDir() / "debug.log";
+ if (freopen(pathDebug.string().c_str(),"a",fileout) != NULL)
+ setbuf(fileout, NULL); // unbuffered
+ }
+
+ ret = FileWriteStr(strTimestamped, fileout);
+ }
}
-
return ret;
}
-static void InterpretNegativeSetting(string name, map<string, string>& mapSettingsRet)
+/** Interpret string as boolean, for argument parsing */
+static bool InterpretBool(const std::string& strValue)
{
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- if (name.find("-no") == 0)
+ if (strValue.empty())
+ return true;
+ return (atoi(strValue) != 0);
+}
+
+/** Turn -noX into -X=0 */
+static void InterpretNegativeSetting(std::string& strKey, std::string& strValue)
+{
+ if (strKey.length()>3 && strKey[0]=='-' && strKey[1]=='n' && strKey[2]=='o')
{
- std::string positive("-");
- positive.append(name.begin()+3, name.end());
- if (mapSettingsRet.count(positive) == 0)
- {
- bool value = !GetBoolArg(name, false);
- mapSettingsRet[positive] = (value ? "1" : "0");
- }
+ strKey = "-" + strKey.substr(3);
+ strValue = InterpretBool(strValue) ? "0" : "1";
}
}
@@ -298,17 +361,11 @@ void ParseParameters(int argc, const char* const argv[])
// If both --foo and -foo are set, the last takes effect.
if (str.length() > 1 && str[1] == '-')
str = str.substr(1);
+ InterpretNegativeSetting(str, strValue);
mapArgs[str] = strValue;
mapMultiArgs[str].push_back(strValue);
}
-
- // New 0.6 features:
- BOOST_FOREACH(const PAIRTYPE(string,string)& entry, mapArgs)
- {
- // interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
- InterpretNegativeSetting(entry.first, mapArgs);
- }
}
std::string GetArg(const std::string& strArg, const std::string& strDefault)
@@ -328,11 +385,7 @@ int64_t GetArg(const std::string& strArg, int64_t nDefault)
bool GetBoolArg(const std::string& strArg, bool fDefault)
{
if (mapArgs.count(strArg))
- {
- if (mapArgs[strArg].empty())
- return true;
- return (atoi(mapArgs[strArg]) != 0);
- }
+ return InterpretBool(mapArgs[strArg]);
return fDefault;
}
@@ -483,13 +536,11 @@ void ReadConfigFile(map<string, string>& mapSettingsRet,
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
string strKey = string("-") + it->string_key;
+ string strValue = it->value[0];
+ InterpretNegativeSetting(strKey, strValue);
if (mapSettingsRet.count(strKey) == 0)
- {
- mapSettingsRet[strKey] = it->value[0];
- // interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
- InterpretNegativeSetting(strKey, mapSettingsRet);
- }
- mapMultiSettingsRet[strKey].push_back(it->value[0]);
+ mapSettingsRet[strKey] = strValue;
+ mapMultiSettingsRet[strKey].push_back(strValue);
}
// If datadir is changed in .conf file:
ClearDatadirCache();
@@ -701,7 +752,7 @@ boost::filesystem::path GetTempPath() {
#endif
}
-void runCommand(std::string strCommand)
+void runCommand(const std::string& strCommand)
{
int nErr = ::system(strCommand.c_str());
if (nErr)
@@ -743,6 +794,18 @@ void SetupEnvironment()
boost::filesystem::path::imbue(loc);
}
+bool SetupNetworking()
+{
+#ifdef WIN32
+ // Initialize Windows Sockets
+ WSADATA wsadata;
+ int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
+ if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
+ return false;
+#endif
+ return true;
+}
+
void SetThreadPriority(int nPriority)
{
#ifdef WIN32
@@ -755,3 +818,13 @@ void SetThreadPriority(int nPriority)
#endif // PRIO_THREAD
#endif // WIN32
}
+
+int GetNumCores()
+{
+#if BOOST_VERSION >= 105600
+ return boost::thread::physical_concurrency();
+#else // Must fall back to hardware_concurrency, which unfortunately counts virtual cores
+ return boost::thread::hardware_concurrency();
+#endif
+}
+
diff --git a/src/util.h b/src/util.h
index 483d9d7858..0b2dc01ac6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -59,6 +59,7 @@ inline std::string _(const char* psz)
}
void SetupEnvironment();
+bool SetupNetworking();
/** Return true if log accepts specified category */
bool LogAcceptCategory(const char* category);
@@ -125,8 +126,9 @@ void ReadConfigFile(std::map<std::string, std::string>& mapSettingsRet, std::map
boost::filesystem::path GetSpecialFolderPath(int nFolder, bool fCreate = true);
#endif
boost::filesystem::path GetTempPath();
+void OpenDebugLog();
void ShrinkDebugFile();
-void runCommand(std::string strCommand);
+void runCommand(const std::string& strCommand);
inline bool IsSwitchChar(char c)
{
@@ -199,45 +201,15 @@ std::string HelpMessageGroup(const std::string& message);
*/
std::string HelpMessageOpt(const std::string& option, const std::string& message);
-void SetThreadPriority(int nPriority);
-void RenameThread(const char* name);
-
/**
- * Standard wrapper for do-something-forever thread functions.
- * "Forever" really means until the thread is interrupted.
- * Use it like:
- * new boost::thread(boost::bind(&LoopForever<void (*)()>, "dumpaddr", &DumpAddresses, 900000));
- * or maybe:
- * boost::function<void()> f = boost::bind(&FunctionWithArg, argument);
- * threadGroup.create_thread(boost::bind(&LoopForever<boost::function<void()> >, "nothing", f, milliseconds));
+ * Return the number of physical cores available on the current system.
+ * @note This does not count virtual cores, such as those provided by HyperThreading
+ * when boost is newer than 1.56.
*/
-template <typename Callable> void LoopForever(const char* name, Callable func, int64_t msecs)
-{
- std::string s = strprintf("bitcoin-%s", name);
- RenameThread(s.c_str());
- LogPrintf("%s thread start\n", name);
- try
- {
- while (1)
- {
- MilliSleep(msecs);
- func();
- }
- }
- catch (const boost::thread_interrupted&)
- {
- LogPrintf("%s thread stop\n", name);
- throw;
- }
- catch (const std::exception& e) {
- PrintExceptionContinue(&e, name);
- throw;
- }
- catch (...) {
- PrintExceptionContinue(NULL, name);
- throw;
- }
-}
+int GetNumCores();
+
+void SetThreadPriority(int nPriority);
+void RenameThread(const char* name);
/**
* .. and a wrapper that just calls func once
diff --git a/src/utilmoneystr.cpp b/src/utilmoneystr.cpp
index 2fbc048878..0f3203432f 100644
--- a/src/utilmoneystr.cpp
+++ b/src/utilmoneystr.cpp
@@ -11,7 +11,7 @@
using namespace std;
-string FormatMoney(const CAmount& n, bool fPlus)
+std::string FormatMoney(const CAmount& n)
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
@@ -29,8 +29,6 @@ string FormatMoney(const CAmount& n, bool fPlus)
if (n < 0)
str.insert((unsigned int)0, 1, '-');
- else if (fPlus && n > 0)
- str.insert((unsigned int)0, 1, '+');
return str;
}
diff --git a/src/utilmoneystr.h b/src/utilmoneystr.h
index cd9b04810d..99c3ba8306 100644
--- a/src/utilmoneystr.h
+++ b/src/utilmoneystr.h
@@ -14,7 +14,7 @@
#include "amount.h"
-std::string FormatMoney(const CAmount& n, bool fPlus=false);
+std::string FormatMoney(const CAmount& n);
bool ParseMoney(const std::string& str, CAmount& nRet);
bool ParseMoney(const char* pszIn, CAmount& nRet);
diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp
index c15bddc6fb..76c22f7353 100644
--- a/src/utilstrencodings.cpp
+++ b/src/utilstrencodings.cpp
@@ -14,17 +14,20 @@
using namespace std;
-string SanitizeString(const string& str)
+static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+static const string SAFE_CHARS[] =
+{
+ CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT
+ CHARS_ALPHA_NUM + " .,;_?@" // SAFE_CHARS_UA_COMMENT
+};
+
+string SanitizeString(const string& str, int rule)
{
- /**
- * safeChars chosen to allow simple messages/URLs/email addresses, but avoid anything
- * even possibly remotely dangerous like & or >
- */
- static string safeChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890 .,;_/:?@()");
string strResult;
for (std::string::size_type i = 0; i < str.size(); i++)
{
- if (safeChars.find(str[i]) != std::string::npos)
+ if (SAFE_CHARS[rule].find(str[i]) != std::string::npos)
strResult.push_back(str[i]);
}
return strResult;
@@ -416,12 +419,25 @@ string DecodeBase32(const string& str)
return (vchRet.size() == 0) ? string() : string((const char*)&vchRet[0], vchRet.size());
}
+static bool ParsePrechecks(const std::string& str)
+{
+ if (str.empty()) // No empty string allowed
+ return false;
+ if (str.size() >= 1 && (isspace(str[0]) || isspace(str[str.size()-1]))) // No padding allowed
+ return false;
+ if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
+ return false;
+ return true;
+}
+
bool ParseInt32(const std::string& str, int32_t *out)
{
+ if (!ParsePrechecks(str))
+ return false;
char *endp = NULL;
errno = 0; // strtol will not set errno if valid
long int n = strtol(str.c_str(), &endp, 10);
- if(out) *out = (int)n;
+ if(out) *out = (int32_t)n;
// Note that strtol returns a *long int*, so even if strtol doesn't report a over/underflow
// we still have to check that the returned value is within the range of an *int32_t*. On 64-bit
// platforms the size of these types may be different.
@@ -430,7 +446,36 @@ bool ParseInt32(const std::string& str, int32_t *out)
n <= std::numeric_limits<int32_t>::max();
}
-std::string FormatParagraph(const std::string in, size_t width, size_t indent)
+bool ParseInt64(const std::string& str, int64_t *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ char *endp = NULL;
+ errno = 0; // strtoll will not set errno if valid
+ long long int n = strtoll(str.c_str(), &endp, 10);
+ if(out) *out = (int64_t)n;
+ // Note that strtoll returns a *long long int*, so even if strtol doesn't report a over/underflow
+ // we still have to check that the returned value is within the range of an *int64_t*.
+ return endp && *endp == 0 && !errno &&
+ n >= std::numeric_limits<int64_t>::min() &&
+ n <= std::numeric_limits<int64_t>::max();
+}
+
+bool ParseDouble(const std::string& str, double *out)
+{
+ if (!ParsePrechecks(str))
+ return false;
+ if (str.size() >= 2 && str[0] == '0' && str[1] == 'x') // No hexadecimal floats allowed
+ return false;
+ std::istringstream text(str);
+ text.imbue(std::locale::classic());
+ double result;
+ text >> result;
+ if(out) *out = result;
+ return text.eof() && !text.fail();
+}
+
+std::string FormatParagraph(const std::string& in, size_t width, size_t indent)
{
std::stringstream out;
size_t col = 0;
@@ -497,3 +542,123 @@ int atoi(const std::string& str)
{
return atoi(str.c_str());
}
+
+/** Upper bound for mantissa.
+ * 10^18-1 is the largest arbitrary decimal that will fit in a signed 64-bit integer.
+ * Larger integers cannot consist of arbitrary combinations of 0-9:
+ *
+ * 999999999999999999 1^18-1
+ * 9223372036854775807 (1<<63)-1 (max int64_t)
+ * 9999999999999999999 1^19-1 (would overflow)
+ */
+static const int64_t UPPER_BOUND = 1000000000000000000LL - 1LL;
+
+/** Helper function for ParseFixedPoint */
+static inline bool ProcessMantissaDigit(char ch, int64_t &mantissa, int &mantissa_tzeros)
+{
+ if(ch == '0')
+ ++mantissa_tzeros;
+ else {
+ for (int i=0; i<=mantissa_tzeros; ++i) {
+ if (mantissa > (UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ mantissa *= 10;
+ }
+ mantissa += ch - '0';
+ mantissa_tzeros = 0;
+ }
+ return true;
+}
+
+bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
+{
+ int64_t mantissa = 0;
+ int64_t exponent = 0;
+ int mantissa_tzeros = 0;
+ bool mantissa_sign = false;
+ bool exponent_sign = false;
+ int ptr = 0;
+ int end = val.size();
+ int point_ofs = 0;
+
+ if (ptr < end && val[ptr] == '-') {
+ mantissa_sign = true;
+ ++ptr;
+ }
+ if (ptr < end)
+ {
+ if (val[ptr] == '0') {
+ /* pass single 0 */
+ ++ptr;
+ } else if (val[ptr] >= '1' && val[ptr] <= '9') {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
+ return false; /* overflow */
+ ++ptr;
+ }
+ } else return false; /* missing expected digit */
+ } else return false; /* empty string or loose '-' */
+ if (ptr < end && val[ptr] == '.')
+ {
+ ++ptr;
+ if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9')
+ {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
+ return false; /* overflow */
+ ++ptr;
+ ++point_ofs;
+ }
+ } else return false; /* missing expected digit */
+ }
+ if (ptr < end && (val[ptr] == 'e' || val[ptr] == 'E'))
+ {
+ ++ptr;
+ if (ptr < end && val[ptr] == '+')
+ ++ptr;
+ else if (ptr < end && val[ptr] == '-') {
+ exponent_sign = true;
+ ++ptr;
+ }
+ if (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ while (ptr < end && val[ptr] >= '0' && val[ptr] <= '9') {
+ if (exponent > (UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ exponent = exponent * 10 + val[ptr] - '0';
+ ++ptr;
+ }
+ } else return false; /* missing expected digit */
+ }
+ if (ptr != end)
+ return false; /* trailing garbage */
+
+ /* finalize exponent */
+ if (exponent_sign)
+ exponent = -exponent;
+ exponent = exponent - point_ofs + mantissa_tzeros;
+
+ /* finalize mantissa */
+ if (mantissa_sign)
+ mantissa = -mantissa;
+
+ /* convert to one 64-bit fixed-point value */
+ exponent += decimals;
+ if (exponent < 0)
+ return false; /* cannot represent values smaller than 10^-decimals */
+ if (exponent >= 18)
+ return false; /* cannot represent values larger than or equal to 10^(18-decimals) */
+
+ for (int i=0; i < exponent; ++i) {
+ if (mantissa > (UPPER_BOUND / 10LL) || mantissa < -(UPPER_BOUND / 10LL))
+ return false; /* overflow */
+ mantissa *= 10;
+ }
+ if (mantissa > UPPER_BOUND || mantissa < -UPPER_BOUND)
+ return false; /* overflow */
+
+ if (amount_out)
+ *amount_out = mantissa;
+
+ return true;
+}
+
diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h
index b0edd8b542..ce93e83497 100644
--- a/src/utilstrencodings.h
+++ b/src/utilstrencodings.h
@@ -22,7 +22,21 @@
/** This is needed because the foreach macro can't get over the comma in pair<t1, t2> */
#define PAIRTYPE(t1, t2) std::pair<t1, t2>
-std::string SanitizeString(const std::string& str);
+/** Used by SanitizeString() */
+enum SafeChars
+{
+ SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
+ SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset
+};
+
+/**
+* Remove unsafe chars. Safe chars chosen to allow simple messages/URLs/email
+* addresses, but avoid anything even possibly remotely dangerous like & or >
+* @param[in] str The string to sanitize
+* @param[in] rule The set of safe chars to choose (default: least restrictive)
+* @return A new string without unsafe chars
+*/
+std::string SanitizeString(const std::string& str, int rule = SAFE_CHARS_DEFAULT);
std::vector<unsigned char> ParseHex(const char* psz);
std::vector<unsigned char> ParseHex(const std::string& str);
signed char HexDigit(char c);
@@ -49,6 +63,20 @@ int atoi(const std::string& str);
*/
bool ParseInt32(const std::string& str, int32_t *out);
+/**
+ * Convert string to signed 64-bit integer with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid integer,
+ * false if not the entire string could be parsed or when overflow or underflow occurred.
+ */
+bool ParseInt64(const std::string& str, int64_t *out);
+
+/**
+ * Convert string to double with strict parse error feedback.
+ * @returns true if the entire string could be parsed as valid double,
+ * false if not the entire string could be parsed or when overflow or underflow occurred.
+ */
+bool ParseDouble(const std::string& str, double *out);
+
template<typename T>
std::string HexStr(const T itbegin, const T itend, bool fSpaces=false)
{
@@ -74,11 +102,11 @@ inline std::string HexStr(const T& vch, bool fSpaces=false)
return HexStr(vch.begin(), vch.end(), fSpaces);
}
-/**
+/**
* Format a paragraph of text to a fixed width, adding spaces for
* indentation to any added line.
*/
-std::string FormatParagraph(const std::string in, size_t width=79, size_t indent=0);
+std::string FormatParagraph(const std::string& in, size_t width = 79, size_t indent = 0);
/**
* Timing-attack-resistant comparison.
@@ -95,4 +123,11 @@ bool TimingResistantEqual(const T& a, const T& b)
return accumulator == 0;
}
+/** Parse number as fixed point according to JSON number syntax.
+ * See http://json.org/number.gif
+ * @returns true on success, false on error.
+ * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger.
+ */
+bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out);
+
#endif // BITCOIN_UTILSTRENCODINGS_H
diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp
index aa9aefb0de..81f3b775f4 100644
--- a/src/validationinterface.cpp
+++ b/src/validationinterface.cpp
@@ -13,33 +13,39 @@ CMainSignals& GetMainSignals()
}
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
+ g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
- g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
+ g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
+ g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
}
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
+ g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
+ g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1));
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
- g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
+ g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
}
void UnregisterAllValidationInterfaces() {
+ g_signals.BlockFound.disconnect_all_slots();
+ g_signals.ScriptForMining.disconnect_all_slots();
g_signals.BlockChecked.disconnect_all_slots();
g_signals.Broadcast.disconnect_all_slots();
g_signals.Inventory.disconnect_all_slots();
g_signals.SetBestChain.disconnect_all_slots();
g_signals.UpdatedTransaction.disconnect_all_slots();
- g_signals.EraseTransaction.disconnect_all_slots();
g_signals.SyncTransaction.disconnect_all_slots();
+ g_signals.UpdatedBlockTip.disconnect_all_slots();
}
void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
diff --git a/src/validationinterface.h b/src/validationinterface.h
index b4c93d72ca..6f95ad74eb 100644
--- a/src/validationinterface.h
+++ b/src/validationinterface.h
@@ -7,9 +7,11 @@
#define BITCOIN_VALIDATIONINTERFACE_H
#include <boost/signals2/signal.hpp>
+#include <boost/shared_ptr.hpp>
class CBlock;
struct CBlockLocator;
+class CReserveScript;
class CTransaction;
class CValidationInterface;
class CValidationState;
@@ -28,23 +30,25 @@ void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
class CValidationInterface {
protected:
- virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {};
- virtual void EraseFromWallet(const uint256 &hash) {};
- virtual void SetBestChain(const CBlockLocator &locator) {};
- virtual void UpdatedTransaction(const uint256 &hash) {};
- virtual void Inventory(const uint256 &hash) {};
- virtual void ResendWalletTransactions(int64_t nBestBlockTime) {};
- virtual void BlockChecked(const CBlock&, const CValidationState&) {};
+ virtual void UpdatedBlockTip(const uint256 &newHashTip) {}
+ virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
+ virtual void SetBestChain(const CBlockLocator &locator) {}
+ virtual void UpdatedTransaction(const uint256 &hash) {}
+ virtual void Inventory(const uint256 &hash) {}
+ virtual void ResendWalletTransactions(int64_t nBestBlockTime) {}
+ virtual void BlockChecked(const CBlock&, const CValidationState&) {}
+ virtual void GetScriptForMining(boost::shared_ptr<CReserveScript>&) {};
+ virtual void ResetRequestCount(const uint256 &hash) {};
friend void ::RegisterValidationInterface(CValidationInterface*);
friend void ::UnregisterValidationInterface(CValidationInterface*);
friend void ::UnregisterAllValidationInterfaces();
};
struct CMainSignals {
+ /** Notifies listeners of updated block chain tip */
+ boost::signals2::signal<void (const uint256 &)> UpdatedBlockTip;
/** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
- /** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */
- boost::signals2::signal<void (const uint256 &)> EraseTransaction;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a new active block chain. */
@@ -55,6 +59,10 @@ struct CMainSignals {
boost::signals2::signal<void (int64_t nBestBlockTime)> Broadcast;
/** Notifies listeners of a block validation result */
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
+ /** Notifies listeners that a key for mining is required (coinbase) */
+ boost::signals2::signal<void (boost::shared_ptr<CReserveScript>&)> ScriptForMining;
+ /** Notifies listeners that a block has been successfully mined */
+ boost::signals2::signal<void (const uint256 &)> BlockFound;
};
CMainSignals& GetMainSignals();
diff --git a/src/version.h b/src/version.h
index 38b3d2e734..6cdddf9255 100644
--- a/src/version.h
+++ b/src/version.h
@@ -9,7 +9,7 @@
* network protocol versioning
*/
-static const int PROTOCOL_VERSION = 70002;
+static const int PROTOCOL_VERSION = 70011;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@@ -34,4 +34,7 @@ static const int BIP0031_VERSION = 60000;
//! "mempool" command, enhanced "getdata" behavior starts with this version
static const int MEMPOOL_GD_VERSION = 60002;
+//! "filter*" commands are disabled without NODE_BLOOM after and including this version
+static const int NO_BLOOM_VERSION = 70011;
+
#endif // BITCOIN_VERSION_H
diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp
index c7f7e21679..c86ad9758e 100644
--- a/src/wallet/crypter.cpp
+++ b/src/wallet/crypter.cpp
@@ -186,7 +186,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn)
}
if (keyPass && keyFail)
{
- LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.");
+ LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n");
assert(false);
}
if (keyFail || !keyPass)
@@ -255,7 +255,7 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
{
LOCK(cs_KeyStore);
if (!IsCrypted())
- return CKeyStore::GetPubKey(address, vchPubKeyOut);
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address);
if (mi != mapCryptedKeys.end())
@@ -263,6 +263,8 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co
vchPubKeyOut = (*mi).second.first;
return true;
}
+ // Check for watch-only pubkeys
+ return CBasicKeyStore::GetPubKey(address, vchPubKeyOut);
}
return false;
}
diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp
index 53cfcf0961..e5bc653c33 100644
--- a/src/wallet/db.cpp
+++ b/src/wallet/db.cpp
@@ -43,7 +43,7 @@ void CDBEnv::EnvShutdown()
if (ret != 0)
LogPrintf("CDBEnv::EnvShutdown: Error %d shutting down database environment: %s\n", ret, DbEnv::strerror(ret));
if (!fMockDb)
- DbEnv(0).remove(path.string().c_str(), 0);
+ DbEnv(0).remove(strPath.c_str(), 0);
}
void CDBEnv::Reset()
@@ -78,10 +78,10 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
boost::this_thread::interruption_point();
- path = pathIn;
- boost::filesystem::path pathLogDir = path / "database";
+ strPath = pathIn.string();
+ boost::filesystem::path pathLogDir = pathIn / "database";
TryCreateDirectory(pathLogDir);
- boost::filesystem::path pathErrorFile = path / "db.log";
+ boost::filesystem::path pathErrorFile = pathIn / "db.log";
LogPrintf("CDBEnv::Open: LogDir=%s ErrorFile=%s\n", pathLogDir.string(), pathErrorFile.string());
unsigned int nEnvFlags = 0;
@@ -98,7 +98,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn)
dbenv->set_flags(DB_AUTO_COMMIT, 1);
dbenv->set_flags(DB_TXN_WRITE_NOSYNC, 1);
dbenv->log_set_config(DB_LOG_AUTO_REMOVE, 1);
- int ret = dbenv->open(path.string().c_str(),
+ int ret = dbenv->open(strPath.c_str(),
DB_CREATE |
DB_INIT_LOCK |
DB_INIT_LOG |
@@ -455,7 +455,7 @@ void CDBEnv::Flush(bool fShutdown)
dbenv->log_archive(&listp, DB_ARCH_REMOVE);
Close();
if (!fMockDb)
- boost::filesystem::remove_all(path / "database");
+ boost::filesystem::remove_all(boost::filesystem::path(strPath) / "database");
}
}
}
diff --git a/src/wallet/db.h b/src/wallet/db.h
index 9596723b21..64071caa3a 100644
--- a/src/wallet/db.h
+++ b/src/wallet/db.h
@@ -20,9 +20,6 @@
#include <db_cxx.h>
-class CDiskBlockIndex;
-class COutPoint;
-
extern unsigned int nWalletDBUpdated;
class CDBEnv
@@ -30,7 +27,9 @@ class CDBEnv
private:
bool fDbEnvInit;
bool fMockDb;
- boost::filesystem::path path;
+ // Don't change into boost::filesystem::path, as that can result in
+ // shutdown problems/crashes caused by a static initialized internal pointer.
+ std::string strPath;
void EnvShutdown();
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index ab951d1d7d..8d557979c0 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
+#include "chain.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
@@ -19,9 +20,10 @@
#include <boost/algorithm/string.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
+
+#include <boost/foreach.hpp>
-using namespace json_spirit;
using namespace std;
void EnsureWalletIsUnlocked();
@@ -70,10 +72,10 @@ std::string DecodeDumpString(const std::string &str) {
return ret.str();
}
-Value importprivkey(const Array& params, bool fHelp)
+UniValue importprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 3)
throw runtime_error(
@@ -95,6 +97,9 @@ Value importprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing keys is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -126,7 +131,7 @@ Value importprivkey(const Array& params, bool fHelp)
// Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress))
- return Value::null;
+ return NullUniValue;
pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1;
@@ -141,46 +146,127 @@ Value importprivkey(const Array& params, bool fHelp)
}
}
- return Value::null;
+ return NullUniValue;
+}
+
+void ImportAddress(const CBitcoinAddress& address, const string& strLabel);
+void ImportScript(const CScript& script, const string& strLabel, bool isRedeemScript)
+{
+ if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
+ throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+
+ pwalletMain->MarkDirty();
+
+ if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script))
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+
+ if (isRedeemScript) {
+ if (!pwalletMain->HaveCScript(script) && !pwalletMain->AddCScript(script))
+ throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
+ ImportAddress(CBitcoinAddress(CScriptID(script)), strLabel);
+ }
+}
+
+void ImportAddress(const CBitcoinAddress& address, const string& strLabel)
+{
+ CScript script = GetScriptForDestination(address.Get());
+ ImportScript(script, strLabel, false);
+ // add to address book or update label
+ if (address.IsValid())
+ pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
}
-Value importaddress(const Array& params, bool fHelp)
+UniValue importaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
- if (fHelp || params.size() < 1 || params.size() > 3)
+ if (fHelp || params.size() < 1 || params.size() > 4)
throw runtime_error(
- "importaddress \"address\" ( \"label\" rescan )\n"
- "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "importaddress \"address\" ( \"label\" rescan p2sh )\n"
+ "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n"
"\nArguments:\n"
- "1. \"address\" (string, required) The address\n"
+ "1. \"script\" (string, required) The hex-encoded script (or address)\n"
"2. \"label\" (string, optional, default=\"\") An optional label\n"
"3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
+ "4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n"
"\nNote: This call can take minutes to complete if rescan is true.\n"
+ "If you have the full public key, you should call importpublickey instead of this.\n"
"\nExamples:\n"
- "\nImport an address with rescan\n"
- + HelpExampleCli("importaddress", "\"myaddress\"") +
+ "\nImport a script with rescan\n"
+ + HelpExampleCli("importaddress", "\"myscript\"") +
"\nImport using a label without rescan\n"
- + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
+ + HelpExampleCli("importaddress", "\"myscript\" \"testing\" false") +
"\nAs a JSON-RPC call\n"
- + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
+ + HelpExampleRpc("importaddress", "\"myscript\", \"testing\", false")
);
- LOCK2(cs_main, pwalletMain->cs_wallet);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing addresses is disabled in pruned mode");
+
+ string strLabel = "";
+ if (params.size() > 1)
+ strLabel = params[1].get_str();
+
+ // Whether to perform rescan after import
+ bool fRescan = true;
+ if (params.size() > 2)
+ fRescan = params[2].get_bool();
- CScript script;
+ // Whether to import a p2sh version, too
+ bool fP2SH = false;
+ if (params.size() > 3)
+ fP2SH = params[3].get_bool();
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
CBitcoinAddress address(params[0].get_str());
if (address.IsValid()) {
- script = GetScriptForDestination(address.Get());
+ if (fP2SH)
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
+ ImportAddress(address, strLabel);
} else if (IsHex(params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(params[0].get_str()));
- script = CScript(data.begin(), data.end());
+ ImportScript(CScript(data.begin(), data.end()), strLabel, fP2SH);
} else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
}
+ if (fRescan)
+ {
+ pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwalletMain->ReacceptWalletTransactions();
+ }
+
+ return NullUniValue;
+}
+
+UniValue importpubkey(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() < 1 || params.size() > 4)
+ throw runtime_error(
+ "importpubkey \"pubkey\" ( \"label\" rescan )\n"
+ "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n"
+ "\nArguments:\n"
+ "1. \"pubkey\" (string, required) The hex-encoded public key\n"
+ "2. \"label\" (string, optional, default=\"\") An optional label\n"
+ "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
+ "\nNote: This call can take minutes to complete if rescan is true.\n"
+ "\nExamples:\n"
+ "\nImport a public key with rescan\n"
+ + HelpExampleCli("importpubkey", "\"mypubkey\"") +
+ "\nImport using a label without rescan\n"
+ + HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
+ "\nAs a JSON-RPC call\n"
+ + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
+ );
+
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing public keys is disabled in pruned mode");
+
string strLabel = "";
if (params.size() > 1)
strLabel = params[1].get_str();
@@ -190,37 +276,32 @@ Value importaddress(const Array& params, bool fHelp)
if (params.size() > 2)
fRescan = params[2].get_bool();
- {
- if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE)
- throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
+ if (!IsHex(params[0].get_str()))
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
+ std::vector<unsigned char> data(ParseHex(params[0].get_str()));
+ CPubKey pubKey(data.begin(), data.end());
+ if (!pubKey.IsFullyValid())
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
- // add to address book or update label
- if (address.IsValid())
- pwalletMain->SetAddressBook(address.Get(), strLabel, "receive");
-
- // Don't throw error in case an address is already there
- if (pwalletMain->HaveWatchOnly(script))
- return Value::null;
-
- pwalletMain->MarkDirty();
+ LOCK2(cs_main, pwalletMain->cs_wallet);
- if (!pwalletMain->AddWatchOnly(script))
- throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
+ ImportAddress(CBitcoinAddress(pubKey.GetID()), strLabel);
+ ImportScript(GetScriptForRawPubKey(pubKey), strLabel, false);
- if (fRescan)
- {
- pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
- pwalletMain->ReacceptWalletTransactions();
- }
+ if (fRescan)
+ {
+ pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true);
+ pwalletMain->ReacceptWalletTransactions();
}
- return Value::null;
+ return NullUniValue;
}
-Value importwallet(const Array& params, bool fHelp)
+
+UniValue importwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -237,6 +318,9 @@ Value importwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ if (fPruneMode)
+ throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
+
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
@@ -318,13 +402,13 @@ Value importwallet(const Array& params, bool fHelp)
if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
- return Value::null;
+ return NullUniValue;
}
-Value dumpprivkey(const Array& params, bool fHelp)
+UniValue dumpprivkey(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -359,10 +443,10 @@ Value dumpprivkey(const Array& params, bool fHelp)
}
-Value dumpwallet(const Array& params, bool fHelp)
+UniValue dumpwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -421,5 +505,5 @@ Value dumpwallet(const Array& params, bool fHelp)
file << "\n";
file << "# End of dump\n";
file.close();
- return Value::null;
+ return NullUniValue;
}
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index dd5240e3c0..5d182f3d42 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -5,6 +5,7 @@
#include "amount.h"
#include "base58.h"
+#include "chain.h"
#include "core_io.h"
#include "init.h"
#include "main.h"
@@ -21,11 +22,9 @@
#include <boost/assign/list_of.hpp>
-#include "json/json_spirit_utils.h"
-#include "json/json_spirit_value.h"
+#include "univalue/univalue.h"
using namespace std;
-using namespace json_spirit;
int64_t nWalletUnlockTime;
static CCriticalSection cs_nWalletUnlockTime;
@@ -55,7 +54,7 @@ void EnsureWalletIsUnlocked()
throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
}
-void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
+void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
entry.push_back(Pair("confirmations", confirms));
@@ -69,7 +68,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
}
uint256 hash = wtx.GetHash();
entry.push_back(Pair("txid", hash.GetHex()));
- Array conflicts;
+ UniValue conflicts(UniValue::VARR);
BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts())
conflicts.push_back(conflict.GetHex());
entry.push_back(Pair("walletconflicts", conflicts));
@@ -79,7 +78,7 @@ void WalletTxToJSON(const CWalletTx& wtx, Object& entry)
entry.push_back(Pair(item.first, item.second));
}
-string AccountFromValue(const Value& value)
+string AccountFromValue(const UniValue& value)
{
string strAccount = value.get_str();
if (strAccount == "*")
@@ -87,10 +86,10 @@ string AccountFromValue(const Value& value)
return strAccount;
}
-Value getnewaddress(const Array& params, bool fHelp)
+UniValue getnewaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -166,10 +165,10 @@ CBitcoinAddress GetAccountAddress(string strAccount, bool bForceNew=false)
return CBitcoinAddress(account.vchPubKey.GetID());
}
-Value getaccountaddress(const Array& params, bool fHelp)
+UniValue getaccountaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -191,17 +190,17 @@ Value getaccountaddress(const Array& params, bool fHelp)
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
- Value ret;
+ UniValue ret(UniValue::VSTR);
ret = GetAccountAddress(strAccount).ToString();
return ret;
}
-Value getrawchangeaddress(const Array& params, bool fHelp)
+UniValue getrawchangeaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -233,10 +232,10 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
}
-Value setaccount(const Array& params, bool fHelp)
+UniValue setaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -275,14 +274,14 @@ Value setaccount(const Array& params, bool fHelp)
else
throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
- return Value::null;
+ return NullUniValue;
}
-Value getaccount(const Array& params, bool fHelp)
+UniValue getaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -311,10 +310,10 @@ Value getaccount(const Array& params, bool fHelp)
}
-Value getaddressesbyaccount(const Array& params, bool fHelp)
+UniValue getaddressesbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -337,7 +336,7 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
{
const CBitcoinAddress& address = item.first;
@@ -379,10 +378,10 @@ static void SendMoney(const CTxDestination &address, CAmount nValue, bool fSubtr
throw JSONRPCError(RPC_WALLET_ERROR, "Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
-Value sendtoaddress(const Array& params, bool fHelp)
+UniValue sendtoaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
@@ -391,7 +390,7 @@ Value sendtoaddress(const Array& params, bool fHelp)
+ HelpRequiringPassphrase() +
"\nArguments:\n"
"1. \"bitcoinaddress\" (string, required) The bitcoin address to send to.\n"
- "2. \"amount\" (numeric, required) The amount in btc to send. eg 0.1\n"
+ "2. \"amount\" (numeric, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n"
"3. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
"4. \"comment-to\" (string, optional) A comment to store the name of the person or organization \n"
@@ -416,12 +415,14 @@ Value sendtoaddress(const Array& params, bool fHelp)
// Amount
CAmount nAmount = AmountFromValue(params[1]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
CWalletTx wtx;
- if (params.size() > 2 && params[2].type() != null_type && !params[2].get_str().empty())
+ if (params.size() > 2 && !params[2].isNull() && !params[2].get_str().empty())
wtx.mapValue["comment"] = params[2].get_str();
- if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["to"] = params[3].get_str();
bool fSubtractFeeFromAmount = false;
@@ -435,10 +436,10 @@ Value sendtoaddress(const Array& params, bool fHelp)
return wtx.GetHash().GetHex();
}
-Value listaddressgroupings(const Array& params, bool fHelp)
+UniValue listaddressgroupings(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp)
throw runtime_error(
@@ -451,7 +452,7 @@ Value listaddressgroupings(const Array& params, bool fHelp)
" [\n"
" [\n"
" \"bitcoinaddress\", (string) The bitcoin address\n"
- " amount, (numeric) The amount in btc\n"
+ " amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"account\" (string, optional) The account (DEPRECATED)\n"
" ]\n"
" ,...\n"
@@ -465,18 +466,17 @@ Value listaddressgroupings(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- Array jsonGroupings;
+ UniValue jsonGroupings(UniValue::VARR);
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
{
- Array jsonGrouping;
+ UniValue jsonGrouping(UniValue::VARR);
BOOST_FOREACH(CTxDestination address, grouping)
{
- Array addressInfo;
+ UniValue addressInfo(UniValue::VARR);
addressInfo.push_back(CBitcoinAddress(address).ToString());
addressInfo.push_back(ValueFromAmount(balances[address]));
{
- LOCK(pwalletMain->cs_wallet);
if (pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get()) != pwalletMain->mapAddressBook.end())
addressInfo.push_back(pwalletMain->mapAddressBook.find(CBitcoinAddress(address).Get())->second.name);
}
@@ -487,10 +487,10 @@ Value listaddressgroupings(const Array& params, bool fHelp)
return jsonGroupings;
}
-Value signmessage(const Array& params, bool fHelp)
+UniValue signmessage(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 2)
throw runtime_error(
@@ -543,10 +543,10 @@ Value signmessage(const Array& params, bool fHelp)
return EncodeBase64(&vchSig[0], vchSig.size());
}
-Value getreceivedbyaddress(const Array& params, bool fHelp)
+UniValue getreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -556,7 +556,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
"1. \"bitcoinaddress\" (string, required) The bitcoin address for transactions.\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received at this address.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received at this address.\n"
"\nExamples:\n"
"\nThe amount from transactions with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"") +
@@ -588,7 +588,7 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !IsFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
@@ -601,10 +601,10 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
}
-Value getreceivedbyaccount(const Array& params, bool fHelp)
+UniValue getreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -614,7 +614,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
"1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
"\nAmount received by the default account with at least 1 confirmation\n"
+ HelpExampleCli("getreceivedbyaccount", "\"\"") +
@@ -642,7 +642,7 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !IsFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
continue;
BOOST_FOREACH(const CTxOut& txout, wtx.vout)
@@ -666,7 +666,7 @@ CAmount GetAccountBalance(CWalletDB& walletdb, const string& strAccount, int nMi
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!IsFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
continue;
CAmount nReceived, nSent, nFee;
@@ -690,10 +690,10 @@ CAmount GetAccountBalance(const string& strAccount, int nMinDepth, const isminef
}
-Value getbalance(const Array& params, bool fHelp)
+UniValue getbalance(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -707,7 +707,7 @@ Value getbalance(const Array& params, bool fHelp)
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"3. includeWatchonly (bool, optional, default=false) Also include balance in watchonly addresses (see 'importaddress')\n"
"\nResult:\n"
- "amount (numeric) The total amount in btc received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
"\nExamples:\n"
"\nThe total amount in the wallet\n"
+ HelpExampleCli("getbalance", "") +
@@ -733,12 +733,12 @@ Value getbalance(const Array& params, bool fHelp)
if (params[0].get_str() == "*") {
// Calculate total balance a different way from GetBalance()
// (GetBalance() sums up all unspent TxOuts)
- // getbalance and getbalance '*' 0 should return the same number
+ // getbalance and "getbalance * 1 true" should return the same number
CAmount nBalance = 0;
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it)
{
const CWalletTx& wtx = (*it).second;
- if (!wtx.IsTrusted() || wtx.GetBlocksToMaturity() > 0)
+ if (!CheckFinalTx(wtx) || wtx.GetBlocksToMaturity() > 0 || wtx.GetDepthInMainChain() < 0)
continue;
CAmount allFee;
@@ -765,10 +765,10 @@ Value getbalance(const Array& params, bool fHelp)
return ValueFromAmount(nBalance);
}
-Value getunconfirmedbalance(const Array &params, bool fHelp)
+UniValue getunconfirmedbalance(const UniValue &params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -781,10 +781,10 @@ Value getunconfirmedbalance(const Array &params, bool fHelp)
}
-Value movecmd(const Array& params, bool fHelp)
+UniValue movecmd(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 3 || params.size() > 5)
throw runtime_error(
@@ -793,14 +793,15 @@ Value movecmd(const Array& params, bool fHelp)
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to move funds from. May be the default account using \"\".\n"
"2. \"toaccount\" (string, required) The name of the account to move funds to. May be the default account using \"\".\n"
- "3. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
- "4. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
+ "3. amount (numeric) Quantity of " + CURRENCY_UNIT + " to move between accounts.\n"
+ "4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
+ "5. \"comment\" (string, optional) An optional comment, stored in the wallet only.\n"
"\nResult:\n"
- "true|false (boolean) true if successfull.\n"
+ "true|false (boolean) true if successful.\n"
"\nExamples:\n"
- "\nMove 0.01 btc from the default account to the account named tabby\n"
+ "\nMove 0.01 " + CURRENCY_UNIT + " from the default account to the account named tabby\n"
+ HelpExampleCli("move", "\"\" \"tabby\" 0.01") +
- "\nMove 0.01 btc timotei to akiko with a comment and funds have 6 confirmations\n"
+ "\nMove 0.01 " + CURRENCY_UNIT + " timotei to akiko with a comment and funds have 6 confirmations\n"
+ HelpExampleCli("move", "\"timotei\" \"akiko\" 0.01 6 \"happy birthday!\"") +
"\nAs a json rpc call\n"
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
@@ -811,6 +812,8 @@ Value movecmd(const Array& params, bool fHelp)
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
if (params.size() > 3)
// unused parameter, used to be nMinDepth, keep type-checking it though
(void)params[3].get_int();
@@ -851,10 +854,10 @@ Value movecmd(const Array& params, bool fHelp)
}
-Value sendfrom(const Array& params, bool fHelp)
+UniValue sendfrom(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 3 || params.size() > 6)
throw runtime_error(
@@ -865,7 +868,7 @@ Value sendfrom(const Array& params, bool fHelp)
"\nArguments:\n"
"1. \"fromaccount\" (string, required) The name of the account to send funds from. May be the default account using \"\".\n"
"2. \"tobitcoinaddress\" (string, required) The bitcoin address to send funds to.\n"
- "3. amount (numeric, required) The amount in btc. (transaction fee is added on top).\n"
+ "3. amount (numeric, required) The amount in " + CURRENCY_UNIT + " (transaction fee is added on top).\n"
"4. minconf (numeric, optional, default=1) Only use funds with at least this many confirmations.\n"
"5. \"comment\" (string, optional) A comment used to store what the transaction is for. \n"
" This is not part of the transaction, just kept in your wallet.\n"
@@ -875,7 +878,7 @@ Value sendfrom(const Array& params, bool fHelp)
"\nResult:\n"
"\"transactionid\" (string) The transaction id.\n"
"\nExamples:\n"
- "\nSend 0.01 btc from the default account to the address, must have at least 1 confirmation\n"
+ "\nSend 0.01 " + CURRENCY_UNIT + " from the default account to the address, must have at least 1 confirmation\n"
+ HelpExampleCli("sendfrom", "\"\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01") +
"\nSend 0.01 from the tabby account to the given address, funds must have at least 6 confirmations\n"
+ HelpExampleCli("sendfrom", "\"tabby\" \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.01 6 \"donation\" \"seans outpost\"") +
@@ -890,15 +893,17 @@ Value sendfrom(const Array& params, bool fHelp)
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
CAmount nAmount = AmountFromValue(params[2]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
int nMinDepth = 1;
if (params.size() > 3)
nMinDepth = params[3].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 4 && params[4].type() != null_type && !params[4].get_str().empty())
+ if (params.size() > 4 && !params[4].isNull() && !params[4].get_str().empty())
wtx.mapValue["comment"] = params[4].get_str();
- if (params.size() > 5 && params[5].type() != null_type && !params[5].get_str().empty())
+ if (params.size() > 5 && !params[5].isNull() && !params[5].get_str().empty())
wtx.mapValue["to"] = params[5].get_str();
EnsureWalletIsUnlocked();
@@ -914,10 +919,10 @@ Value sendfrom(const Array& params, bool fHelp)
}
-Value sendmany(const Array& params, bool fHelp)
+UniValue sendmany(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 5)
throw runtime_error(
@@ -928,7 +933,7 @@ Value sendmany(const Array& params, bool fHelp)
"1. \"fromaccount\" (string, required) DEPRECATED. The account to send the funds from. Should be \"\" for the default account\n"
"2. \"amounts\" (string, required) A json object with addresses and amounts\n"
" {\n"
- " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in btc is the value\n"
+ " \"address\":amount (numeric) The bitcoin address is the key, the numeric amount in " + CURRENCY_UNIT + " is the value\n"
" ,...\n"
" }\n"
"3. minconf (numeric, optional, default=1) Only use the balance confirmed at least this many times.\n"
@@ -958,17 +963,17 @@ Value sendmany(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
string strAccount = AccountFromValue(params[0]);
- Object sendTo = params[1].get_obj();
+ UniValue sendTo = params[1].get_obj();
int nMinDepth = 1;
if (params.size() > 2)
nMinDepth = params[2].get_int();
CWalletTx wtx;
wtx.strFromAccount = strAccount;
- if (params.size() > 3 && params[3].type() != null_type && !params[3].get_str().empty())
+ if (params.size() > 3 && !params[3].isNull() && !params[3].get_str().empty())
wtx.mapValue["comment"] = params[3].get_str();
- Array subtractFeeFromAmount;
+ UniValue subtractFeeFromAmount(UniValue::VARR);
if (params.size() > 4)
subtractFeeFromAmount = params[4].get_array();
@@ -976,24 +981,29 @@ Value sendmany(const Array& params, bool fHelp)
vector<CRecipient> vecSend;
CAmount totalAmount = 0;
- BOOST_FOREACH(const Pair& s, sendTo)
+ vector<string> keys = sendTo.getKeys();
+ BOOST_FOREACH(const string& name_, keys)
{
- CBitcoinAddress address(s.name_);
+ CBitcoinAddress address(name_);
if (!address.IsValid())
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_);
if (setAddress.count(address))
- throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+s.name_);
+ throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_);
setAddress.insert(address);
CScript scriptPubKey = GetScriptForDestination(address.Get());
- CAmount nAmount = AmountFromValue(s.value_);
+ CAmount nAmount = AmountFromValue(sendTo[name_]);
+ if (nAmount <= 0)
+ throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
totalAmount += nAmount;
bool fSubtractFeeFromAmount = false;
- BOOST_FOREACH(const Value& addr, subtractFeeFromAmount)
- if (addr.get_str() == s.name_)
+ for (unsigned int idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
+ const UniValue& addr = subtractFeeFromAmount[idx];
+ if (addr.get_str() == name_)
fSubtractFeeFromAmount = true;
+ }
CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
@@ -1021,12 +1031,12 @@ Value sendmany(const Array& params, bool fHelp)
}
// Defined in rpcmisc.cpp
-extern CScript _createmultisig_redeemScript(const Array& params);
+extern CScript _createmultisig_redeemScript(const UniValue& params);
-Value addmultisigaddress(const Array& params, bool fHelp)
+UniValue addmultisigaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 2 || params.size() > 3)
{
@@ -1086,7 +1096,7 @@ struct tallyitem
}
};
-Value ListReceived(const Array& params, bool fByAccounts)
+UniValue ListReceived(const UniValue& params, bool fByAccounts)
{
// Minimum confirmations
int nMinDepth = 1;
@@ -1109,7 +1119,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
{
const CWalletTx& wtx = (*it).second;
- if (wtx.IsCoinBase() || !IsFinalTx(wtx))
+ if (wtx.IsCoinBase() || !CheckFinalTx(wtx))
continue;
int nDepth = wtx.GetDepthInMainChain();
@@ -1136,7 +1146,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
}
// Reply
- Array ret;
+ UniValue ret(UniValue::VARR);
map<string, tallyitem> mapAccountTally;
BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress, CAddressBookData)& item, pwalletMain->mapAddressBook)
{
@@ -1165,14 +1175,14 @@ Value ListReceived(const Array& params, bool fByAccounts)
}
else
{
- Object obj;
+ UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("address", address.ToString()));
obj.push_back(Pair("account", strAccount));
obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
- Array transactions;
+ UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
BOOST_FOREACH(const uint256& item, (*it).second.txids)
@@ -1191,7 +1201,7 @@ Value ListReceived(const Array& params, bool fByAccounts)
{
CAmount nAmount = (*it).second.nAmount;
int nConf = (*it).second.nConf;
- Object obj;
+ UniValue obj(UniValue::VOBJ);
if((*it).second.fIsWatchonly)
obj.push_back(Pair("involvesWatchonly", true));
obj.push_back(Pair("account", (*it).first));
@@ -1204,10 +1214,10 @@ Value ListReceived(const Array& params, bool fByAccounts)
return ret;
}
-Value listreceivedbyaddress(const Array& params, bool fHelp)
+UniValue listreceivedbyaddress(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -1224,7 +1234,7 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
" \"address\" : \"receivingaddress\", (string) The receiving address\n"
" \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
- " \"amount\" : x.xxx, (numeric) The total amount in btc received by the address\n"
+ " \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
" \"confirmations\" : n (numeric) The number of confirmations of the most recent transaction included\n"
" }\n"
" ,...\n"
@@ -1241,10 +1251,10 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
return ListReceived(params, false);
}
-Value listreceivedbyaccount(const Array& params, bool fHelp)
+UniValue listreceivedbyaccount(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -1277,14 +1287,14 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
return ListReceived(params, true);
}
-static void MaybePushAddress(Object & entry, const CTxDestination &dest)
+static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
CBitcoinAddress addr;
if (addr.Set(dest))
entry.push_back(Pair("address", addr.ToString()));
}
-void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, Array& ret, const isminefilter& filter)
+void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
{
CAmount nFee;
string strSentAccount;
@@ -1301,7 +1311,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
{
BOOST_FOREACH(const COutputEntry& s, listSent)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if(involvesWatchonly || (::IsMine(*pwalletMain, s.destination) & ISMINE_WATCH_ONLY))
entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", strSentAccount));
@@ -1326,7 +1336,7 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
account = pwalletMain->mapAddressBook[r.destination].name;
if (fAllAccounts || (account == strAccount))
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if(involvesWatchonly || (::IsMine(*pwalletMain, r.destination) & ISMINE_WATCH_ONLY))
entry.push_back(Pair("involvesWatchonly", true));
entry.push_back(Pair("account", account));
@@ -1354,13 +1364,13 @@ void ListTransactions(const CWalletTx& wtx, const string& strAccount, int nMinDe
}
}
-void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Array& ret)
+void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, UniValue& ret)
{
bool fAllAccounts = (strAccount == string("*"));
if (fAllAccounts || acentry.strAccount == strAccount)
{
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("account", acentry.strAccount));
entry.push_back(Pair("category", "move"));
entry.push_back(Pair("time", acentry.nTime));
@@ -1371,10 +1381,10 @@ void AcentryToJSON(const CAccountingEntry& acentry, const string& strAccount, Ar
}
}
-Value listtransactions(const Array& params, bool fHelp)
+UniValue listtransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 4)
throw runtime_error(
@@ -1396,11 +1406,11 @@ Value listtransactions(const Array& params, bool fHelp)
" transaction between accounts, and not associated with an address,\n"
" transaction id or block. 'send' and 'receive' transactions are \n"
" associated with an address, transaction id and block details\n"
- " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the\n"
+ " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the\n"
" 'move' category for moves outbound. It is positive for the 'receive' category,\n"
" and for the 'move' category for inbound funds.\n"
" \"vout\" : n, (numeric) the vout value\n"
- " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the \n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
" 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and \n"
" 'receive' category of transactions.\n"
@@ -1449,7 +1459,7 @@ Value listtransactions(const Array& params, bool fHelp)
if (nFrom < 0)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
- Array ret;
+ UniValue ret(UniValue::VARR);
std::list<CAccountingEntry> acentries;
CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount);
@@ -1472,23 +1482,30 @@ Value listtransactions(const Array& params, bool fHelp)
nFrom = ret.size();
if ((nFrom + nCount) > (int)ret.size())
nCount = ret.size() - nFrom;
- Array::iterator first = ret.begin();
+
+ vector<UniValue> arrTmp = ret.getValues();
+
+ vector<UniValue>::iterator first = arrTmp.begin();
std::advance(first, nFrom);
- Array::iterator last = ret.begin();
+ vector<UniValue>::iterator last = arrTmp.begin();
std::advance(last, nFrom+nCount);
- if (last != ret.end()) ret.erase(last, ret.end());
- if (first != ret.begin()) ret.erase(ret.begin(), first);
+ if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end());
+ if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first);
- std::reverse(ret.begin(), ret.end()); // Return oldest to newest
+ std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest
+
+ ret.clear();
+ ret.setArray();
+ ret.push_backV(arrTmp);
return ret;
}
-Value listaccounts(const Array& params, bool fHelp)
+UniValue listaccounts(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 2)
throw runtime_error(
@@ -1558,17 +1575,17 @@ Value listaccounts(const Array& params, bool fHelp)
BOOST_FOREACH(const CAccountingEntry& entry, acentries)
mapAccountBalances[entry.strAccount] += entry.nCreditDebit;
- Object ret;
+ UniValue ret(UniValue::VOBJ);
BOOST_FOREACH(const PAIRTYPE(string, CAmount)& accountBalance, mapAccountBalances) {
ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
}
return ret;
}
-Value listsinceblock(const Array& params, bool fHelp)
+UniValue listsinceblock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp)
throw runtime_error(
@@ -1584,10 +1601,10 @@ Value listsinceblock(const Array& params, bool fHelp)
" \"account\":\"accountname\", (string) DEPRECATED. The account name associated with the transaction. Will be \"\" for the default account.\n"
" \"address\":\"bitcoinaddress\", (string) The bitcoin address of the transaction. Not present for move transactions (category = move).\n"
" \"category\":\"send|receive\", (string) The transaction category. 'send' has negative amounts, 'receive' has positive amounts.\n"
- " \"amount\": x.xxx, (numeric) The amount in btc. This is negative for the 'send' category, and for the 'move' category for moves \n"
+ " \"amount\": x.xxx, (numeric) The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and for the 'move' category for moves \n"
" outbound. It is positive for the 'receive' category, and for the 'move' category for inbound funds.\n"
" \"vout\" : n, (numeric) the vout value\n"
- " \"fee\": x.xxx, (numeric) The amount of the fee in btc. This is negative and only available for the 'send' category of transactions.\n"
+ " \"fee\": x.xxx, (numeric) The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the 'send' category of transactions.\n"
" \"confirmations\": n, (numeric) The number of confirmations for the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
" \"blockindex\": n, (numeric) The block index containing the transaction. Available for 'send' and 'receive' category of transactions.\n"
@@ -1636,7 +1653,7 @@ Value listsinceblock(const Array& params, bool fHelp)
int depth = pindex ? (1 + chainActive.Height() - pindex->nHeight) : -1;
- Array transactions;
+ UniValue transactions(UniValue::VARR);
for (map<uint256, CWalletTx>::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); it++)
{
@@ -1649,17 +1666,17 @@ Value listsinceblock(const Array& params, bool fHelp)
CBlockIndex *pblockLast = chainActive[chainActive.Height() + 1 - target_confirms];
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
- Object ret;
+ UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("transactions", transactions));
ret.push_back(Pair("lastblock", lastblock.GetHex()));
return ret;
}
-Value gettransaction(const Array& params, bool fHelp)
+UniValue gettransaction(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -1670,7 +1687,7 @@ Value gettransaction(const Array& params, bool fHelp)
"2. \"includeWatchonly\" (bool, optional, default=false) Whether to include watchonly addresses in balance calculation and details[]\n"
"\nResult:\n"
"{\n"
- " \"amount\" : x.xxx, (numeric) The transaction amount in btc\n"
+ " \"amount\" : x.xxx, (numeric) The transaction amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"blockhash\" : \"hash\", (string) The block hash\n"
" \"blockindex\" : xx, (numeric) The block index\n"
@@ -1683,7 +1700,7 @@ Value gettransaction(const Array& params, bool fHelp)
" \"account\" : \"accountname\", (string) DEPRECATED. The account name involved in the transaction, can be \"\" for the default account.\n"
" \"address\" : \"bitcoinaddress\", (string) The bitcoin address involved in the transaction\n"
" \"category\" : \"send|receive\", (string) The category, either 'send' or 'receive'\n"
- " \"amount\" : x.xxx (numeric) The amount in btc\n"
+ " \"amount\" : x.xxx (numeric) The amount in " + CURRENCY_UNIT + "\n"
" \"vout\" : n, (numeric) the vout value\n"
" }\n"
" ,...\n"
@@ -1707,7 +1724,7 @@ Value gettransaction(const Array& params, bool fHelp)
if(params[1].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
if (!pwalletMain->mapWallet.count(hash))
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
const CWalletTx& wtx = pwalletMain->mapWallet[hash];
@@ -1723,7 +1740,7 @@ Value gettransaction(const Array& params, bool fHelp)
WalletTxToJSON(wtx, entry);
- Array details;
+ UniValue details(UniValue::VARR);
ListTransactions(wtx, "*", 0, false, details, filter);
entry.push_back(Pair("details", details));
@@ -1734,10 +1751,10 @@ Value gettransaction(const Array& params, bool fHelp)
}
-Value backupwallet(const Array& params, bool fHelp)
+UniValue backupwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 1)
throw runtime_error(
@@ -1756,14 +1773,14 @@ Value backupwallet(const Array& params, bool fHelp)
if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
- return Value::null;
+ return NullUniValue;
}
-Value keypoolrefill(const Array& params, bool fHelp)
+UniValue keypoolrefill(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 1)
throw runtime_error(
@@ -1793,7 +1810,7 @@ Value keypoolrefill(const Array& params, bool fHelp)
if (pwalletMain->GetKeyPoolSize() < kpSize)
throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
- return Value::null;
+ return NullUniValue;
}
@@ -1804,10 +1821,10 @@ static void LockWallet(CWallet* pWallet)
pWallet->Lock();
}
-Value walletpassphrase(const Array& params, bool fHelp)
+UniValue walletpassphrase(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
@@ -1860,14 +1877,14 @@ Value walletpassphrase(const Array& params, bool fHelp)
nWalletUnlockTime = GetTime() + nSleepTime;
RPCRunLater("lockwallet", boost::bind(LockWallet, pwalletMain), nSleepTime);
- return Value::null;
+ return NullUniValue;
}
-Value walletpassphrasechange(const Array& params, bool fHelp)
+UniValue walletpassphrasechange(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 2))
throw runtime_error(
@@ -1906,14 +1923,14 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
if (!pwalletMain->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass))
throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
- return Value::null;
+ return NullUniValue;
}
-Value walletlock(const Array& params, bool fHelp)
+UniValue walletlock(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (pwalletMain->IsCrypted() && (fHelp || params.size() != 0))
throw runtime_error(
@@ -1945,14 +1962,14 @@ Value walletlock(const Array& params, bool fHelp)
nWalletUnlockTime = 0;
}
- return Value::null;
+ return NullUniValue;
}
-Value encryptwallet(const Array& params, bool fHelp)
+UniValue encryptwallet(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (!pwalletMain->IsCrypted() && (fHelp || params.size() != 1))
throw runtime_error(
@@ -2006,10 +2023,10 @@ Value encryptwallet(const Array& params, bool fHelp)
return "wallet encrypted; Bitcoin server stopping, restart to run with encrypted wallet. The keypool has been flushed, you need to make a new backup.";
}
-Value lockunspent(const Array& params, bool fHelp)
+UniValue lockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
@@ -2050,9 +2067,9 @@ Value lockunspent(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
if (params.size() == 1)
- RPCTypeCheck(params, boost::assign::list_of(bool_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL));
else
- RPCTypeCheck(params, boost::assign::list_of(bool_type)(array_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VBOOL)(UniValue::VARR));
bool fUnlock = params[0].get_bool();
@@ -2062,14 +2079,14 @@ Value lockunspent(const Array& params, bool fHelp)
return true;
}
- Array outputs = params[1].get_array();
- BOOST_FOREACH(Value& output, outputs)
- {
- if (output.type() != obj_type)
+ UniValue outputs = params[1].get_array();
+ for (unsigned int idx = 0; idx < outputs.size(); idx++) {
+ const UniValue& output = outputs[idx];
+ if (!output.isObject())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
- const Object& o = output.get_obj();
+ const UniValue& o = output.get_obj();
- RPCTypeCheck(o, boost::assign::map_list_of("txid", str_type)("vout", int_type));
+ RPCTypeCheckObj(o, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM));
string txid = find_value(o, "txid").get_str();
if (!IsHex(txid))
@@ -2090,10 +2107,10 @@ Value lockunspent(const Array& params, bool fHelp)
return true;
}
-Value listlockunspent(const Array& params, bool fHelp)
+UniValue listlockunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 0)
throw runtime_error(
@@ -2126,10 +2143,10 @@ Value listlockunspent(const Array& params, bool fHelp)
vector<COutPoint> vOutpts;
pwalletMain->ListLockedCoins(vOutpts);
- Array ret;
+ UniValue ret(UniValue::VARR);
BOOST_FOREACH(COutPoint &outpt, vOutpts) {
- Object o;
+ UniValue o(UniValue::VOBJ);
o.push_back(Pair("txid", outpt.hash.GetHex()));
o.push_back(Pair("vout", (int)outpt.n));
@@ -2139,17 +2156,17 @@ Value listlockunspent(const Array& params, bool fHelp)
return ret;
}
-Value settxfee(const Array& params, bool fHelp)
+UniValue settxfee(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"settxfee amount\n"
"\nSet the transaction fee per kB.\n"
"\nArguments:\n"
- "1. amount (numeric, required) The transaction fee in BTC/kB rounded to the nearest 0.00000001\n"
+ "1. amount (numeric, required) The transaction fee in " + CURRENCY_UNIT + "/kB rounded to the nearest 0.00000001\n"
"\nResult\n"
"true|false (boolean) Returns true if successful\n"
"\nExamples:\n"
@@ -2160,18 +2177,16 @@ Value settxfee(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
// Amount
- CAmount nAmount = 0;
- if (params[0].get_real() != 0.0)
- nAmount = AmountFromValue(params[0]); // rejects 0.0 amounts
+ CAmount nAmount = AmountFromValue(params[0]);
payTxFee = CFeeRate(nAmount, 1000);
return true;
}
-Value getwalletinfo(const Array& params, bool fHelp)
+UniValue getwalletinfo(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -2180,13 +2195,14 @@ Value getwalletinfo(const Array& params, bool fHelp)
"\nResult:\n"
"{\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
- " \"balance\": xxxxxxx, (numeric) the total confirmed bitcoin balance of the wallet\n"
- " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed bitcoin balance of the wallet\n"
- " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet\n"
+ " \"balance\": xxxxxxx, (numeric) the total confirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
+ " \"unconfirmed_balance\": xxx, (numeric) the total unconfirmed balance of the wallet in " + CURRENCY_UNIT + "\n"
+ " \"immature_balance\": xxxxxx, (numeric) the total immature balance of the wallet in " + CURRENCY_UNIT + "\n"
" \"txcount\": xxxxxxx, (numeric) the total number of transactions in the wallet\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
+ " \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("getwalletinfo", "")
@@ -2195,7 +2211,7 @@ Value getwalletinfo(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
- Object obj;
+ UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwalletMain->GetUnconfirmedBalance())));
@@ -2205,13 +2221,14 @@ Value getwalletinfo(const Array& params, bool fHelp)
obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
if (pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
+ obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
return obj;
}
-Value resendwallettransactions(const Array& params, bool fHelp)
+UniValue resendwallettransactions(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() != 0)
throw runtime_error(
@@ -2225,7 +2242,7 @@ Value resendwallettransactions(const Array& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
std::vector<uint256> txids = pwalletMain->ResendWalletTransactionsBefore(GetTime());
- Array result;
+ UniValue result(UniValue::VARR);
BOOST_FOREACH(const uint256& txid, txids)
{
result.push_back(txid.ToString());
@@ -2233,10 +2250,10 @@ Value resendwallettransactions(const Array& params, bool fHelp)
return result;
}
-Value listunspent(const Array& params, bool fHelp)
+UniValue listunspent(const UniValue& params, bool fHelp)
{
if (!EnsureWalletIsAvailable(fHelp))
- return Value::null;
+ return NullUniValue;
if (fHelp || params.size() > 3)
throw runtime_error(
@@ -2262,7 +2279,7 @@ Value listunspent(const Array& params, bool fHelp)
" \"address\" : \"address\", (string) the bitcoin address\n"
" \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
- " \"amount\" : x.xxx, (numeric) the transaction amount in btc\n"
+ " \"amount\" : x.xxx, (numeric) the transaction amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n (numeric) The number of confirmations\n"
" }\n"
" ,...\n"
@@ -2274,7 +2291,7 @@ Value listunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
);
- RPCTypeCheck(params, boost::assign::list_of(int_type)(int_type)(array_type));
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
int nMinDepth = 1;
if (params.size() > 0)
@@ -2286,8 +2303,9 @@ Value listunspent(const Array& params, bool fHelp)
set<CBitcoinAddress> setAddress;
if (params.size() > 2) {
- Array inputs = params[2].get_array();
- BOOST_FOREACH(Value& input, inputs) {
+ UniValue inputs = params[2].get_array();
+ for (unsigned int idx = 0; idx < inputs.size(); idx++) {
+ const UniValue& input = inputs[idx];
CBitcoinAddress address(input.get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+input.get_str());
@@ -2297,7 +2315,7 @@ Value listunspent(const Array& params, bool fHelp)
}
}
- Array results;
+ UniValue results(UniValue::VARR);
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet);
@@ -2317,7 +2335,7 @@ Value listunspent(const Array& params, bool fHelp)
CAmount nValue = out.tx->vout[out.i].nValue;
const CScript& pk = out.tx->vout[out.i].scriptPubKey;
- Object entry;
+ UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
entry.push_back(Pair("vout", out.i));
CTxDestination address;
@@ -2343,4 +2361,67 @@ Value listunspent(const Array& params, bool fHelp)
}
return results;
-} \ No newline at end of file
+}
+
+UniValue fundrawtransaction(const UniValue& params, bool fHelp)
+{
+ if (!EnsureWalletIsAvailable(fHelp))
+ return NullUniValue;
+
+ if (fHelp || params.size() < 1 || params.size() > 2)
+ throw runtime_error(
+ "fundrawtransaction \"hexstring\" includeWatching\n"
+ "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n"
+ "This will not modify existing inputs, and will add one change output to the outputs.\n"
+ "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
+ "The inputs added will not be signed, use signrawtransaction for that.\n"
+ "Note that all existing inputs must have their previous output transaction be in the wallet.\n"
+ "Note that all inputs selected must be of standard form and P2SH scripts must be"
+ "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
+ "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n"
+ "\nArguments:\n"
+ "1. \"hexstring\" (string, required) The hex string of the raw transaction\n"
+ "2. includeWatching (boolean, optional, default false) Also select inputs which are watch only\n"
+ "\nResult:\n"
+ "{\n"
+ " \"hex\": \"value\", (string) The resulting raw transaction (hex-encoded string)\n"
+ " \"fee\": n, (numeric) The fee added to the transaction\n"
+ " \"changepos\": n (numeric) The position of the added change output, or -1\n"
+ "}\n"
+ "\"hex\" \n"
+ "\nExamples:\n"
+ "\nCreate a transaction with no inputs\n"
+ + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
+ "\nAdd sufficient unsigned inputs to meet the output value\n"
+ + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
+ "\nSign the transaction\n"
+ + HelpExampleCli("signrawtransaction", "\"fundedtransactionhex\"") +
+ "\nSend the transaction\n"
+ + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
+ );
+
+ RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL));
+
+ // parse hex string from parameter
+ CTransaction origTx;
+ if (!DecodeHexTx(origTx, params[0].get_str()))
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+
+ bool includeWatching = false;
+ if (params.size() > 1)
+ includeWatching = true;
+
+ CMutableTransaction tx(origTx);
+ CAmount nFee;
+ string strFailReason;
+ int nChangePos = -1;
+ if(!pwalletMain->FundTransaction(tx, nFee, nChangePos, strFailReason, includeWatching))
+ throw JSONRPCError(RPC_INTERNAL_ERROR, strFailReason);
+
+ UniValue result(UniValue::VOBJ);
+ result.push_back(Pair("hex", EncodeHexTx(tx)));
+ result.push_back(Pair("changepos", nChangePos));
+ result.push_back(Pair("fee", ValueFromAmount(nFee)));
+
+ return result;
+}
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 0afdcd0011..c3b1172201 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -7,13 +7,21 @@
#include "base58.h"
#include "checkpoints.h"
+#include "chain.h"
#include "coincontrol.h"
#include "consensus/consensus.h"
+#include "consensus/validation.h"
+#include "key.h"
+#include "keystore.h"
#include "main.h"
#include "net.h"
+#include "policy/policy.h"
+#include "primitives/block.h"
+#include "primitives/transaction.h"
#include "script/script.h"
#include "script/sign.h"
#include "timedata.h"
+#include "txmempool.h"
#include "util.h"
#include "utilmoneystr.h"
@@ -30,7 +38,7 @@ using namespace std;
*/
CFeeRate payTxFee(DEFAULT_TRANSACTION_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
-unsigned int nTxConfirmTarget = 1;
+unsigned int nTxConfirmTarget = DEFAULT_TX_CONFIRM_TARGET;
bool bSpendZeroConfChange = true;
bool fSendFreeTransactions = false;
bool fPayAtLeastCustomFee = true;
@@ -106,6 +114,9 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
script = GetScriptForDestination(pubkey.GetID());
if (HaveWatchOnly(script))
RemoveWatchOnly(script);
+ script = GetScriptForRawPubKey(pubkey);
+ if (HaveWatchOnly(script))
+ RemoveWatchOnly(script);
if (!fFileBacked)
return true;
@@ -418,6 +429,7 @@ void CWallet::SyncMetaData(pair<TxSpends::iterator, TxSpends::iterator> range)
const uint256& hash = it->second;
CWalletTx* copyTo = &mapWallet[hash];
if (copyFrom == copyTo) continue;
+ if (!copyFrom->IsEquivalentTo(*copyTo)) continue;
copyTo->mapValue = copyFrom->mapValue;
copyTo->vOrderForm = copyFrom->vOrderForm;
// fTimeReceivedIsTxTime not copied on purpose
@@ -775,18 +787,6 @@ void CWallet::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
}
}
-void CWallet::EraseFromWallet(const uint256 &hash)
-{
- if (!fFileBacked)
- return;
- {
- LOCK(cs_wallet);
- if (mapWallet.erase(hash))
- CWalletDB(strWalletFile).EraseTx(hash);
- }
- return;
-}
-
isminetype CWallet::IsMine(const CTxIn &txin) const
{
@@ -1317,7 +1317,7 @@ CAmount CWalletTx::GetChange() const
bool CWalletTx::IsTrusted() const
{
// Quick answer in most cases
- if (!IsFinalTx(*this))
+ if (!CheckFinalTx(*this))
return false;
int nDepth = GetDepthInMainChain();
if (nDepth >= 1)
@@ -1341,6 +1341,15 @@ bool CWalletTx::IsTrusted() const
return true;
}
+bool CWalletTx::IsEquivalentTo(const CWalletTx& tx) const
+{
+ CMutableTransaction tx1 = *this;
+ CMutableTransaction tx2 = tx;
+ for (unsigned int i = 0; i < tx1.vin.size(); i++) tx1.vin[i].scriptSig = CScript();
+ for (unsigned int i = 0; i < tx2.vin.size(); i++) tx2.vin[i].scriptSig = CScript();
+ return CTransaction(tx1) == CTransaction(tx2);
+}
+
std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
{
std::vector<uint256> result;
@@ -1423,7 +1432,7 @@ CAmount CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -1468,7 +1477,7 @@ CAmount CWallet::GetUnconfirmedWatchOnlyBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
+ if (!CheckFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0))
nTotal += pcoin->GetAvailableWatchOnlyCredit();
}
}
@@ -1503,7 +1512,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
const uint256& wtxid = it->first;
const CWalletTx* pcoin = &(*it).second;
- if (!IsFinalTx(*pcoin))
+ if (!CheckFinalTx(*pcoin))
continue;
if (fOnlyConfirmed && !pcoin->IsTrusted())
@@ -1520,8 +1529,10 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
isminetype mine = IsMine(pcoin->vout[i]);
if (!(IsSpent(wtxid, i)) && mine != ISMINE_NO &&
!IsLockedCoin((*it).first, i) && (pcoin->vout[i].nValue > 0 || fIncludeZeroValue) &&
- (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i)))
- vCoins.push_back(COutput(pcoin, i, nDepth, (mine & ISMINE_SPENDABLE) != ISMINE_NO));
+ (!coinControl || !coinControl->HasSelected() || coinControl->fAllowOtherInputs || coinControl->IsSelected((*it).first, i)))
+ vCoins.push_back(COutput(pcoin, i, nDepth,
+ ((mine & ISMINE_SPENDABLE) != ISMINE_NO) ||
+ (coinControl && coinControl->fAllowWatchOnly && (mine & ISMINE_WATCH_SOLVABLE) != ISMINE_NO)));
}
}
}
@@ -1680,25 +1691,109 @@ bool CWallet::SelectCoins(const CAmount& nTargetValue, set<pair<const CWalletTx*
AvailableCoins(vCoins, true, coinControl);
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
- if (coinControl && coinControl->HasSelected())
+ if (coinControl && coinControl->HasSelected() && !coinControl->fAllowOtherInputs)
{
BOOST_FOREACH(const COutput& out, vCoins)
{
- if(!out.fSpendable)
- continue;
+ if (!out.fSpendable)
+ continue;
nValueRet += out.tx->vout[out.i].nValue;
setCoinsRet.insert(make_pair(out.tx, out.i));
}
return (nValueRet >= nTargetValue);
}
- return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) ||
- SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) ||
- (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet)));
+ // calculate value from preset inputs and store them
+ set<pair<const CWalletTx*, uint32_t> > setPresetCoins;
+ CAmount nValueFromPresetInputs = 0;
+
+ std::vector<COutPoint> vPresetInputs;
+ if (coinControl)
+ coinControl->ListSelected(vPresetInputs);
+ BOOST_FOREACH(const COutPoint& outpoint, vPresetInputs)
+ {
+ map<uint256, CWalletTx>::const_iterator it = mapWallet.find(outpoint.hash);
+ if (it != mapWallet.end())
+ {
+ const CWalletTx* pcoin = &it->second;
+ // Clearly invalid input, fail
+ if (pcoin->vout.size() <= outpoint.n)
+ return false;
+ nValueFromPresetInputs += pcoin->vout[outpoint.n].nValue;
+ setPresetCoins.insert(make_pair(pcoin, outpoint.n));
+ } else
+ return false; // TODO: Allow non-wallet inputs
+ }
+
+ // remove preset inputs from vCoins
+ for (vector<COutput>::iterator it = vCoins.begin(); it != vCoins.end() && coinControl && coinControl->HasSelected();)
+ {
+ if (setPresetCoins.count(make_pair(it->tx, it->i)))
+ it = vCoins.erase(it);
+ else
+ ++it;
+ }
+
+ bool res = nTargetValue <= nValueFromPresetInputs ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 6, vCoins, setCoinsRet, nValueRet) ||
+ SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 1, 1, vCoins, setCoinsRet, nValueRet) ||
+ (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue - nValueFromPresetInputs, 0, 1, vCoins, setCoinsRet, nValueRet));
+
+ // because SelectCoinsMinConf clears the setCoinsRet, we now add the possible inputs to the coinset
+ setCoinsRet.insert(setPresetCoins.begin(), setPresetCoins.end());
+
+ // add preset inputs to the total value selected
+ nValueRet += nValueFromPresetInputs;
+
+ return res;
}
-bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
- CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl)
+bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching)
+{
+ vector<CRecipient> vecSend;
+
+ // Turn the txout set into a CRecipient vector
+ BOOST_FOREACH(const CTxOut& txOut, tx.vout)
+ {
+ CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, false};
+ vecSend.push_back(recipient);
+ }
+
+ CCoinControl coinControl;
+ coinControl.fAllowOtherInputs = true;
+ coinControl.fAllowWatchOnly = includeWatching;
+ BOOST_FOREACH(const CTxIn& txin, tx.vin)
+ coinControl.Select(txin.prevout);
+
+ CReserveKey reservekey(this);
+ CWalletTx wtx;
+ if (!CreateTransaction(vecSend, wtx, reservekey, nFeeRet, nChangePosRet, strFailReason, &coinControl, false))
+ return false;
+
+ if (nChangePosRet != -1)
+ tx.vout.insert(tx.vout.begin() + nChangePosRet, wtx.vout[nChangePosRet]);
+
+ // Add new txins (keeping original txin scriptSig/order)
+ BOOST_FOREACH(const CTxIn& txin, wtx.vin)
+ {
+ bool found = false;
+ BOOST_FOREACH(const CTxIn& origTxIn, tx.vin)
+ {
+ if (txin.prevout.hash == origTxIn.prevout.hash && txin.prevout.n == origTxIn.prevout.n)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ tx.vin.push_back(txin);
+ }
+
+ return true;
+}
+
+bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet,
+ int& nChangePosRet, std::string& strFailReason, const CCoinControl* coinControl, bool sign)
{
CAmount nValue = 0;
unsigned int nSubtractFeeFromAmount = 0;
@@ -1901,23 +1996,43 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
// Sign
int nIn = 0;
+ CTransaction txNewConst(txNew);
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
- if (!SignSignature(*this, *coin.first, txNew, nIn++))
+ {
+ bool signSuccess;
+ const CScript& scriptPubKey = coin.first->vout[coin.second].scriptPubKey;
+ CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
+ if (sign)
+ signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);
+ else
+ signSuccess = ProduceSignature(DummySignatureCreator(this), scriptPubKey, scriptSigRes);
+
+ if (!signSuccess)
{
strFailReason = _("Signing transaction failed");
return false;
}
+ nIn++;
+ }
+
+ unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
+
+ // Remove scriptSigs if we used dummy signatures for fee calculation
+ if (!sign) {
+ BOOST_FOREACH (CTxIn& vin, txNew.vin)
+ vin.scriptSig = CScript();
+ }
// Embed the constructed transaction data in wtxNew.
*static_cast<CTransaction*>(&wtxNew) = CTransaction(txNew);
// Limit size
- unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
if (nBytes >= MAX_STANDARD_TX_SIZE)
{
strFailReason = _("Transaction too large");
return false;
}
+
dPriority = wtxNew.ComputePriority(dPriority, nBytes);
// Can we complete this as a free transaction?
@@ -2000,7 +2115,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
if (!wtxNew.AcceptToMemoryPool(false))
{
// This must not fail. The transaction has already been signed and recorded.
- LogPrintf("CommitTransaction(): Error: Transaction not valid");
+ LogPrintf("CommitTransaction(): Error: Transaction not valid\n");
return false;
}
wtxNew.RelayWalletTransaction();
@@ -2290,7 +2405,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted())
+ if (!CheckFinalTx(*pcoin) || !pcoin->IsTrusted())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -2413,7 +2528,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
return ret;
}
-set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
+std::set<CTxDestination> CWallet::GetAccountAddresses(const std::string& strAccount) const
{
LOCK(cs_wallet);
set<CTxDestination> result;
@@ -2491,6 +2606,17 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
}
}
+void CWallet::GetScriptForMining(boost::shared_ptr<CReserveScript> &script)
+{
+ boost::shared_ptr<CReserveKey> rKey(new CReserveKey(this));
+ CPubKey pubkey;
+ if (!rKey->GetReservedKey(pubkey))
+ return;
+
+ script = rKey;
+ script->reserveScript = CScript() << ToByteVector(pubkey) << OP_CHECKSIG;
+}
+
void CWallet::LockCoin(COutPoint& output)
{
AssertLockHeld(cs_wallet); // setLockedCoins
diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h
index 1c900b0315..bd30b67b09 100644
--- a/src/wallet/wallet.h
+++ b/src/wallet/wallet.h
@@ -7,10 +7,7 @@
#define BITCOIN_WALLET_WALLET_H
#include "amount.h"
-#include "key.h"
-#include "keystore.h"
-#include "primitives/block.h"
-#include "primitives/transaction.h"
+#include "streams.h"
#include "tinyformat.h"
#include "ui_interface.h"
#include "utilstrencodings.h"
@@ -28,6 +25,8 @@
#include <utility>
#include <vector>
+#include <boost/shared_ptr.hpp>
+
/**
* Settings
*/
@@ -44,6 +43,8 @@ static const CAmount DEFAULT_TRANSACTION_FEE = 0;
static const CAmount nHighTransactionFeeWarning = 0.01 * COIN;
//! -maxtxfee default
static const CAmount DEFAULT_TRANSACTION_MAXFEE = 0.1 * COIN;
+//! -txconfirmtarget default
+static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 2;
//! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
static const CAmount nHighTransactionMaxFeeWarning = 100 * nHighTransactionFeeWarning;
//! Largest (in bytes) free transaction we're willing to create
@@ -374,6 +375,9 @@ public:
return (GetDebit(filter) > 0);
}
+ // True if only scriptSigs are different
+ bool IsEquivalentTo(const CWalletTx& tx) const;
+
bool IsTrusted() const;
bool WriteToDisk(CWalletDB *pwalletdb);
@@ -494,7 +498,7 @@ public:
SetNull();
}
- CWallet(std::string strWalletFileIn)
+ CWallet(const std::string& strWalletFileIn)
{
SetNull();
@@ -613,7 +617,6 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
- void EraseFromWallet(const uint256 &hash);
int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false);
void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime);
@@ -624,8 +627,9 @@ public:
CAmount GetWatchOnlyBalance() const;
CAmount GetUnconfirmedWatchOnlyBalance() const;
CAmount GetImmatureWatchOnlyBalance() const;
- bool CreateTransaction(const std::vector<CRecipient>& vecSend,
- CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, const CCoinControl *coinControl = NULL);
+ bool FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosRet, std::string& strFailReason, bool includeWatching);
+ bool CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, CAmount& nFeeRet, int& nChangePosRet,
+ std::string& strFailReason, const CCoinControl *coinControl = NULL, bool sign = true);
bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey);
static CFeeRate minTxFee;
@@ -643,7 +647,7 @@ public:
std::set< std::set<CTxDestination> > GetAddressGroupings();
std::map<CTxDestination, CAmount> GetAddressBalances();
- std::set<CTxDestination> GetAccountAddresses(std::string strAccount) const;
+ std::set<CTxDestination> GetAccountAddresses(const std::string& strAccount) const;
isminetype IsMine(const CTxIn& txin) const;
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
@@ -678,6 +682,13 @@ public:
}
}
+ void GetScriptForMining(boost::shared_ptr<CReserveScript> &script);
+ void ResetRequestCount(const uint256 &hash)
+ {
+ LOCK(cs_wallet);
+ mapRequestCount[hash] = 0;
+ };
+
unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // setKeyPool
@@ -733,7 +744,7 @@ public:
};
/** A key allocated from the key pool. */
-class CReserveKey
+class CReserveKey : public CReserveScript
{
protected:
CWallet* pwallet;
@@ -754,6 +765,7 @@ public:
void ReturnKey();
bool GetReservedKey(CPubKey &pubkey);
void KeepKey();
+ void KeepScript() { KeepKey(); }
};
diff --git a/src/wallet/wallet_ismine.cpp b/src/wallet/wallet_ismine.cpp
index 5482348e35..d27b1531e3 100644
--- a/src/wallet/wallet_ismine.cpp
+++ b/src/wallet/wallet_ismine.cpp
@@ -9,6 +9,7 @@
#include "keystore.h"
#include "script/script.h"
#include "script/standard.h"
+#include "script/sign.h"
#include <boost/foreach.hpp>
@@ -40,7 +41,7 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
txnouttype whichType;
if (!Solver(scriptPubKey, whichType, vSolutions)) {
if (keystore.HaveWatchOnly(scriptPubKey))
- return ISMINE_WATCH_ONLY;
+ return ISMINE_WATCH_UNSOLVABLE;
return ISMINE_NO;
}
@@ -85,7 +86,10 @@ isminetype IsMine(const CKeyStore &keystore, const CScript& scriptPubKey)
}
}
- if (keystore.HaveWatchOnly(scriptPubKey))
- return ISMINE_WATCH_ONLY;
+ if (keystore.HaveWatchOnly(scriptPubKey)) {
+ // TODO: This could be optimized some by doing some work after the above solver
+ CScript scriptSig;
+ return ProduceSignature(DummySignatureCreator(&keystore), scriptPubKey, scriptSig) ? ISMINE_WATCH_SOLVABLE : ISMINE_WATCH_UNSOLVABLE;
+ }
return ISMINE_NO;
}
diff --git a/src/wallet/wallet_ismine.h b/src/wallet/wallet_ismine.h
index 5b9b0e0841..9f45f76c6b 100644
--- a/src/wallet/wallet_ismine.h
+++ b/src/wallet/wallet_ismine.h
@@ -6,9 +6,10 @@
#ifndef BITCOIN_WALLET_WALLET_ISMINE_H
#define BITCOIN_WALLET_WALLET_ISMINE_H
-#include "key.h"
#include "script/standard.h"
+#include <stdint.h>
+
class CKeyStore;
class CScript;
@@ -16,8 +17,12 @@ class CScript;
enum isminetype
{
ISMINE_NO = 0,
- ISMINE_WATCH_ONLY = 1,
- ISMINE_SPENDABLE = 2,
+ //! Indicates that we dont know how to create a scriptSig that would solve this if we were given the appropriate private keys
+ ISMINE_WATCH_UNSOLVABLE = 1,
+ //! Indicates that we know how to create a scriptSig that would solve this if we were given the appropriate private keys
+ ISMINE_WATCH_SOLVABLE = 2,
+ ISMINE_WATCH_ONLY = ISMINE_WATCH_SOLVABLE | ISMINE_WATCH_UNSOLVABLE,
+ ISMINE_SPENDABLE = 4,
ISMINE_ALL = ISMINE_WATCH_ONLY | ISMINE_SPENDABLE
};
/** used for bitflags of isminetype */
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index de56a2d1af..c1eb184581 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -6,7 +6,8 @@
#include "wallet/walletdb.h"
#include "base58.h"
-#include "main.h"
+#include "consensus/validation.h"
+#include "main.h" // For CheckTransaction
#include "protocol.h"
#include "serialize.h"
#include "sync.h"
@@ -915,7 +916,7 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
}
std::vector<CDBEnv::KeyValPair> salvagedData;
- bool allOK = dbenv.Salvage(newFilename, true, salvagedData);
+ bool fSuccess = dbenv.Salvage(newFilename, true, salvagedData);
if (salvagedData.empty())
{
LogPrintf("Salvage(aggressive) found no records in %s.\n", newFilename);
@@ -923,7 +924,6 @@ bool CWalletDB::Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKe
}
LogPrintf("Salvage(aggressive) found %u records\n", salvagedData.size());
- bool fSuccess = allOK;
boost::scoped_ptr<Db> pdbCopy(new Db(dbenv.dbenv, 0));
int ret = pdbCopy->open(NULL, // Txn pointer
filename.c_str(), // Filename
diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h
index bc1a104b5b..270f826aed 100644
--- a/src/wallet/walletdb.h
+++ b/src/wallet/walletdb.h
@@ -9,7 +9,6 @@
#include "amount.h"
#include "wallet/db.h"
#include "key.h"
-#include "keystore.h"
#include <list>
#include <stdint.h>
diff --git a/src/zmq/zmqabstractnotifier.cpp b/src/zmq/zmqabstractnotifier.cpp
new file mode 100644
index 0000000000..744ec59234
--- /dev/null
+++ b/src/zmq/zmqabstractnotifier.cpp
@@ -0,0 +1,22 @@
+// 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.
+
+#include "zmqabstractnotifier.h"
+#include "util.h"
+
+
+CZMQAbstractNotifier::~CZMQAbstractNotifier()
+{
+ assert(!psocket);
+}
+
+bool CZMQAbstractNotifier::NotifyBlock(const uint256 &/*hash*/)
+{
+ return true;
+}
+
+bool CZMQAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/)
+{
+ return true;
+}
diff --git a/src/zmq/zmqabstractnotifier.h b/src/zmq/zmqabstractnotifier.h
new file mode 100644
index 0000000000..626d1ddf92
--- /dev/null
+++ b/src/zmq/zmqabstractnotifier.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
+#define BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
+
+#include "zmqconfig.h"
+
+class CZMQAbstractNotifier;
+typedef CZMQAbstractNotifier* (*CZMQNotifierFactory)();
+
+class CZMQAbstractNotifier
+{
+public:
+ CZMQAbstractNotifier() : psocket(0) { }
+ virtual ~CZMQAbstractNotifier();
+
+ template <typename T>
+ static CZMQAbstractNotifier* Create()
+ {
+ return new T();
+ }
+
+ std::string GetType() const { return type; }
+ void SetType(const std::string &t) { type = t; }
+ std::string GetAddress() const { return address; }
+ void SetAddress(const std::string &a) { address = a; }
+
+ virtual bool Initialize(void *pcontext) = 0;
+ virtual void Shutdown() = 0;
+
+ virtual bool NotifyBlock(const uint256 &hash);
+ virtual bool NotifyTransaction(const CTransaction &transaction);
+
+protected:
+ void *psocket;
+ std::string type;
+ std::string address;
+};
+
+#endif // BITCOIN_ZMQ_ZMQABSTRACTNOTIFIER_H
diff --git a/src/zmq/zmqconfig.h b/src/zmq/zmqconfig.h
new file mode 100644
index 0000000000..6057f5d1a0
--- /dev/null
+++ b/src/zmq/zmqconfig.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef BITCOIN_ZMQ_ZMQCONFIG_H
+#define BITCOIN_ZMQ_ZMQCONFIG_H
+
+#if defined(HAVE_CONFIG_H)
+#include "config/bitcoin-config.h"
+#endif
+
+#include <stdarg.h>
+#include <string>
+
+#if ENABLE_ZMQ
+#include <zmq.h>
+#endif
+
+#include "primitives/block.h"
+#include "primitives/transaction.h"
+
+void zmqError(const char *str);
+
+#endif // BITCOIN_ZMQ_ZMQCONFIG_H
diff --git a/src/zmq/zmqnotificationinterface.cpp b/src/zmq/zmqnotificationinterface.cpp
new file mode 100644
index 0000000000..71ccb59a4a
--- /dev/null
+++ b/src/zmq/zmqnotificationinterface.cpp
@@ -0,0 +1,155 @@
+// 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.
+
+#include "zmqnotificationinterface.h"
+#include "zmqpublishnotifier.h"
+
+#include "version.h"
+#include "main.h"
+#include "streams.h"
+#include "util.h"
+
+void zmqError(const char *str)
+{
+ LogPrint("zmq", "Error: %s, errno=%s\n", str, zmq_strerror(errno));
+}
+
+CZMQNotificationInterface::CZMQNotificationInterface() : pcontext(NULL)
+{
+}
+
+CZMQNotificationInterface::~CZMQNotificationInterface()
+{
+ // ensure Shutdown if Initialize is called
+ assert(!pcontext);
+
+ for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
+ {
+ delete *i;
+ }
+}
+
+CZMQNotificationInterface* CZMQNotificationInterface::CreateWithArguments(const std::map<std::string, std::string> &args)
+{
+ CZMQNotificationInterface* notificationInterface = NULL;
+ std::map<std::string, CZMQNotifierFactory> factories;
+ std::list<CZMQAbstractNotifier*> notifiers;
+
+ factories["pubhashblock"] = CZMQAbstractNotifier::Create<CZMQPublishHashBlockNotifier>;
+ factories["pubhashtx"] = CZMQAbstractNotifier::Create<CZMQPublishHashTransactionNotifier>;
+ factories["pubrawblock"] = CZMQAbstractNotifier::Create<CZMQPublishRawBlockNotifier>;
+ factories["pubrawtx"] = CZMQAbstractNotifier::Create<CZMQPublishRawTransactionNotifier>;
+
+ for (std::map<std::string, CZMQNotifierFactory>::const_iterator i=factories.begin(); i!=factories.end(); ++i)
+ {
+ std::map<std::string, std::string>::const_iterator j = args.find("-zmq" + i->first);
+ if (j!=args.end())
+ {
+ CZMQNotifierFactory factory = i->second;
+ std::string address = j->second;
+ CZMQAbstractNotifier *notifier = factory();
+ notifier->SetType(i->first);
+ notifier->SetAddress(address);
+ notifiers.push_back(notifier);
+ }
+ }
+
+ if (!notifiers.empty())
+ {
+ notificationInterface = new CZMQNotificationInterface();
+ notificationInterface->notifiers = notifiers;
+ }
+
+ return notificationInterface;
+}
+
+// Called at startup to conditionally set up ZMQ socket(s)
+bool CZMQNotificationInterface::Initialize()
+{
+ LogPrint("zmq", "Initialize notification interface\n");
+ assert(!pcontext);
+
+ pcontext = zmq_init(1);
+
+ if (!pcontext)
+ {
+ zmqError("Unable to initialize context");
+ return false;
+ }
+
+ std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin();
+ for (; i!=notifiers.end(); ++i)
+ {
+ CZMQAbstractNotifier *notifier = *i;
+ if (notifier->Initialize(pcontext))
+ {
+ LogPrint("zmq", " Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ }
+ else
+ {
+ LogPrint("zmq", " Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress());
+ break;
+ }
+ }
+
+ if (i!=notifiers.end())
+ {
+ Shutdown();
+ return false;
+ }
+
+ return false;
+}
+
+// Called during shutdown sequence
+void CZMQNotificationInterface::Shutdown()
+{
+ LogPrint("zmq", "Shutdown notification interface\n");
+ if (pcontext)
+ {
+ for (std::list<CZMQAbstractNotifier*>::iterator i=notifiers.begin(); i!=notifiers.end(); ++i)
+ {
+ CZMQAbstractNotifier *notifier = *i;
+ LogPrint("zmq", " Shutdown notifier %s at %s\n", notifier->GetType(), notifier->GetAddress());
+ notifier->Shutdown();
+ }
+ zmq_ctx_destroy(pcontext);
+
+ pcontext = 0;
+ }
+}
+
+void CZMQNotificationInterface::UpdatedBlockTip(const uint256 &hash)
+{
+ for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
+ {
+ CZMQAbstractNotifier *notifier = *i;
+ if (notifier->NotifyBlock(hash))
+ {
+ i++;
+ }
+ else
+ {
+ notifier->Shutdown();
+ i = notifiers.erase(i);
+ }
+ }
+}
+
+void CZMQNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock)
+{
+ for (std::list<CZMQAbstractNotifier*>::iterator i = notifiers.begin(); i!=notifiers.end(); )
+ {
+ CZMQAbstractNotifier *notifier = *i;
+ if (notifier->NotifyTransaction(tx))
+ {
+ i++;
+ }
+ else
+ {
+ notifier->Shutdown();
+ i = notifiers.erase(i);
+ }
+ }
+}
diff --git a/src/zmq/zmqnotificationinterface.h b/src/zmq/zmqnotificationinterface.h
new file mode 100644
index 0000000000..afc0b8d24e
--- /dev/null
+++ b/src/zmq/zmqnotificationinterface.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
+#define BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
+
+#include "validationinterface.h"
+#include <string>
+#include <map>
+
+class CZMQAbstractNotifier;
+
+class CZMQNotificationInterface : public CValidationInterface
+{
+public:
+ virtual ~CZMQNotificationInterface();
+
+ static CZMQNotificationInterface* CreateWithArguments(const std::map<std::string, std::string> &args);
+
+ bool Initialize();
+ void Shutdown();
+
+protected: // CValidationInterface
+ void SyncTransaction(const CTransaction &tx, const CBlock *pblock);
+ void UpdatedBlockTip(const uint256 &newHashTip);
+
+private:
+ CZMQNotificationInterface();
+
+ void *pcontext;
+ std::list<CZMQAbstractNotifier*> notifiers;
+};
+
+#endif // BITCOIN_ZMQ_ZMQNOTIFICATIONINTERFACE_H
diff --git a/src/zmq/zmqpublishnotifier.cpp b/src/zmq/zmqpublishnotifier.cpp
new file mode 100644
index 0000000000..0a6d7d0dbc
--- /dev/null
+++ b/src/zmq/zmqpublishnotifier.cpp
@@ -0,0 +1,172 @@
+// 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.
+
+#include "zmqpublishnotifier.h"
+#include "main.h"
+#include "util.h"
+
+static std::multimap<std::string, CZMQAbstractPublishNotifier*> mapPublishNotifiers;
+
+// Internal function to send multipart message
+static int zmq_send_multipart(void *sock, const void* data, size_t size, ...)
+{
+ va_list args;
+ va_start(args, size);
+
+ while (1)
+ {
+ zmq_msg_t msg;
+
+ int rc = zmq_msg_init_size(&msg, size);
+ if (rc != 0)
+ {
+ zmqError("Unable to initialize ZMQ msg");
+ return -1;
+ }
+
+ void *buf = zmq_msg_data(&msg);
+ memcpy(buf, data, size);
+
+ data = va_arg(args, const void*);
+
+ rc = zmq_msg_send(&msg, sock, data ? ZMQ_SNDMORE : 0);
+ if (rc == -1)
+ {
+ zmqError("Unable to send ZMQ msg");
+ zmq_msg_close(&msg);
+ return -1;
+ }
+
+ zmq_msg_close(&msg);
+
+ if (!data)
+ break;
+
+ size = va_arg(args, size_t);
+ }
+ return 0;
+}
+
+bool CZMQAbstractPublishNotifier::Initialize(void *pcontext)
+{
+ assert(!psocket);
+
+ // check if address is being used by other publish notifier
+ std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator i = mapPublishNotifiers.find(address);
+
+ if (i==mapPublishNotifiers.end())
+ {
+ psocket = zmq_socket(pcontext, ZMQ_PUB);
+ if (!psocket)
+ {
+ zmqError("Failed to create socket");
+ return false;
+ }
+
+ int rc = zmq_bind(psocket, address.c_str());
+ if (rc!=0)
+ {
+ zmqError("Failed to bind address");
+ return false;
+ }
+
+ // register this notifier for the address, so it can be reused for other publish notifier
+ mapPublishNotifiers.insert(std::make_pair(address, this));
+ return true;
+ }
+ else
+ {
+ LogPrint("zmq", " Reuse socket for address %s\n", address);
+
+ psocket = i->second->psocket;
+ mapPublishNotifiers.insert(std::make_pair(address, this));
+
+ return true;
+ }
+}
+
+void CZMQAbstractPublishNotifier::Shutdown()
+{
+ assert(psocket);
+
+ int count = mapPublishNotifiers.count(address);
+
+ // remove this notifier from the list of publishers using this address
+ typedef std::multimap<std::string, CZMQAbstractPublishNotifier*>::iterator iterator;
+ std::pair<iterator, iterator> iterpair = mapPublishNotifiers.equal_range(address);
+
+ for (iterator it = iterpair.first; it != iterpair.second; ++it)
+ {
+ if (it->second==this)
+ {
+ mapPublishNotifiers.erase(it);
+ break;
+ }
+ }
+
+ if (count == 1)
+ {
+ LogPrint("zmq", "Close socket at address %s\n", address);
+ int linger = 0;
+ zmq_setsockopt(psocket, ZMQ_LINGER, &linger, sizeof(linger));
+ zmq_close(psocket);
+ }
+
+ psocket = 0;
+}
+
+bool CZMQPublishHashBlockNotifier::NotifyBlock(const uint256 &hash)
+{
+ LogPrint("zmq", "Publish hash block %s\n", hash.GetHex());
+ char data[32];
+ for (unsigned int i = 0; i < 32; i++)
+ data[31 - i] = hash.begin()[i];
+ int rc = zmq_send_multipart(psocket, "hashblock", 9, data, 32, 0);
+ return rc == 0;
+}
+
+bool CZMQPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
+{
+ uint256 hash = transaction.GetHash();
+ LogPrint("zmq", "Publish hash transaction %s\n", hash.GetHex());
+ char data[32];
+ for (unsigned int i = 0; i < 32; i++)
+ data[31 - i] = hash.begin()[i];
+ int rc = zmq_send_multipart(psocket, "hashtx", 6, data, 32, 0);
+ return rc == 0;
+}
+
+bool CZMQPublishRawBlockNotifier::NotifyBlock(const uint256 &hash)
+{
+ LogPrint("zmq", "Publish raw block %s\n", hash.GetHex());
+
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ {
+ LOCK(cs_main);
+
+ CBlock block;
+ CBlockIndex* pblockindex = mapBlockIndex[hash];
+
+ if(!ReadBlockFromDisk(block, pblockindex))
+ {
+ zmqError("Can't read block from disk");
+ return false;
+ }
+
+ ss << block;
+ }
+
+ int rc = zmq_send_multipart(psocket, "rawblock", 8, &(*ss.begin()), ss.size(), 0);
+ return rc == 0;
+}
+
+bool CZMQPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction)
+{
+ uint256 hash = transaction.GetHash();
+ LogPrint("zmq", "Publish raw transaction %s\n", hash.GetHex());
+ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
+ ss << transaction;
+ int rc = zmq_send_multipart(psocket, "rawtx", 5, &(*ss.begin()), ss.size(), 0);
+ return rc == 0;
+}
diff --git a/src/zmq/zmqpublishnotifier.h b/src/zmq/zmqpublishnotifier.h
new file mode 100644
index 0000000000..a0eb26f5e2
--- /dev/null
+++ b/src/zmq/zmqpublishnotifier.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
+#define BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H
+
+#include "zmqabstractnotifier.h"
+
+class CZMQAbstractPublishNotifier : public CZMQAbstractNotifier
+{
+public:
+ bool Initialize(void *pcontext);
+ void Shutdown();
+};
+
+class CZMQPublishHashBlockNotifier : public CZMQAbstractPublishNotifier
+{
+public:
+ bool NotifyBlock(const uint256 &hash);
+};
+
+class CZMQPublishHashTransactionNotifier : public CZMQAbstractPublishNotifier
+{
+public:
+ bool NotifyTransaction(const CTransaction &transaction);
+};
+
+class CZMQPublishRawBlockNotifier : public CZMQAbstractPublishNotifier
+{
+public:
+ bool NotifyBlock(const uint256 &hash);
+};
+
+class CZMQPublishRawTransactionNotifier : public CZMQAbstractPublishNotifier
+{
+public:
+ bool NotifyTransaction(const CTransaction &transaction);
+};
+
+#endif // BITCOIN_ZMQ_ZMQPUBLISHNOTIFIER_H